<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mangai Ram</title>
    <description>The latest articles on DEV Community by Mangai Ram (@magi-magificient).</description>
    <link>https://dev.to/magi-magificient</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1252378%2F8d9346ae-ab65-4542-bebf-04f148f0d46a.png</url>
      <title>DEV Community: Mangai Ram</title>
      <link>https://dev.to/magi-magificient</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/magi-magificient"/>
    <language>en</language>
    <item>
      <title>Automating Call Barging Testing with Playwright: A Real-World Contact Center Use Case</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Mon, 15 Jun 2026 10:04:48 +0000</pubDate>
      <link>https://dev.to/magi-magificient/automating-call-barging-testing-with-playwright-a-real-world-contact-center-use-case-48kk</link>
      <guid>https://dev.to/magi-magificient/automating-call-barging-testing-with-playwright-a-real-world-contact-center-use-case-48kk</guid>
      <description>&lt;p&gt;In modern contact centers, supervisors often use the Call Barging feature to join live agent-customer conversations for monitoring, coaching, or escalation purposes. While the functionality sounds simple, testing it manually across multiple users can be time-consuming and error-prone.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how Playwright can help automate Call Barging scenarios efficiently.&lt;/p&gt;

&lt;p&gt;What is Call Barging?&lt;/p&gt;

&lt;p&gt;Call Barging allows a supervisor to enter an active call between an agent and a customer. Common scenarios include:&lt;/p&gt;

&lt;p&gt;Quality monitoring&lt;br&gt;
Agent training&lt;br&gt;
Escalation handling&lt;br&gt;
Customer issue resolution&lt;/p&gt;

&lt;p&gt;A typical call flow looks like this:&lt;/p&gt;

&lt;p&gt;Customer calls Agent.&lt;br&gt;
Agent answers the call.&lt;br&gt;
Supervisor monitors the conversation.&lt;br&gt;
Supervisor clicks "Barge In."&lt;br&gt;
Supervisor joins the live conversation.&lt;br&gt;
Testing Challenges&lt;/p&gt;

&lt;p&gt;Manual testing requires:&lt;/p&gt;

&lt;p&gt;Multiple user accounts&lt;br&gt;
Multiple browser sessions&lt;br&gt;
Coordination between testers&lt;br&gt;
Repeated execution for regression testing&lt;/p&gt;

&lt;p&gt;This is where Playwright shines.&lt;/p&gt;

&lt;p&gt;Why Use Playwright?&lt;/p&gt;

&lt;p&gt;Playwright provides:&lt;/p&gt;

&lt;p&gt;Multi-browser support&lt;br&gt;
Multiple user contexts&lt;br&gt;
Parallel execution&lt;br&gt;
Fast and reliable UI automation&lt;br&gt;
Network monitoring capabilities&lt;br&gt;
Sample Playwright Approach&lt;/p&gt;

&lt;p&gt;Create separate browser contexts for:&lt;/p&gt;

&lt;p&gt;Agent&lt;br&gt;
Supervisor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Supervisor should successfully barge into active call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agentContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supervisorContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agentPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agentContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supervisorPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supervisorContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Agent Login&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agentPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-contact-center-app.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agentPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agent1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agentPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agentPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Supervisor Login&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supervisorPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-contact-center-app.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supervisorPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supervisor1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supervisorPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supervisorPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Verify active call&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agentPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.call-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toContainText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Supervisor barges into call&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supervisorPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button:has-text("Barge In")&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Validate barging success&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supervisorPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.call-state&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toContainText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Joined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Validation Points&lt;/p&gt;

&lt;p&gt;While automating Call Barging, verify:&lt;/p&gt;

&lt;p&gt;Agent Side&lt;/p&gt;

&lt;p&gt;✅ Call remains connected&lt;/p&gt;

&lt;p&gt;✅ No audio interruption&lt;/p&gt;

&lt;p&gt;✅ Supervisor participant appears&lt;/p&gt;

&lt;p&gt;Supervisor Side&lt;/p&gt;

&lt;p&gt;✅ Barge button enabled&lt;/p&gt;

&lt;p&gt;✅ Successful connection status&lt;/p&gt;

&lt;p&gt;✅ Call controls available&lt;/p&gt;

&lt;p&gt;Customer Side&lt;/p&gt;

&lt;p&gt;✅ Call continuity maintained&lt;/p&gt;

&lt;p&gt;✅ No unexpected disconnections&lt;/p&gt;

&lt;p&gt;Negative Test Cases&lt;/p&gt;

&lt;p&gt;Consider automating:&lt;/p&gt;

&lt;p&gt;Barging into an already ended call&lt;br&gt;
Unauthorized user attempting to barge&lt;br&gt;
Network interruption during barging&lt;br&gt;
Multiple supervisors attempting to barge simultaneously&lt;br&gt;
Agent disconnecting during barging&lt;/p&gt;

&lt;p&gt;Best Practices&lt;br&gt;
Use Stable Locators&lt;/p&gt;

&lt;p&gt;Prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getByRole()
getByTestId()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of fragile XPath selectors.&lt;/p&gt;

&lt;p&gt;Capture Evidence&lt;/p&gt;

&lt;p&gt;Enable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;on'&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;screenshot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;only-on-failure'&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;retain-on-failure'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to simplify debugging.&lt;br&gt;
Run Parallel Tests&lt;/p&gt;

&lt;p&gt;Playwright allows multiple call-monitoring scenarios to execute simultaneously, reducing regression execution time.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;Call Barging is a critical feature in contact center environments, and ensuring its reliability directly impacts customer experience and agent productivity. By leveraging Playwright's multi-context capabilities, teams can automate complex supervisor-agent interactions, reduce manual effort, and improve release confidence.&lt;/p&gt;

&lt;p&gt;If you're testing contact center solutions such as predictive dialers, ACD, call monitoring, whisper coaching, or call barging, Playwright can become a powerful addition to your QA automation toolkit.&lt;/p&gt;

&lt;p&gt;Have you automated contact center features using Playwright? Share your experience in the comments!&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>How I Found a Hidden Login Bug in a Predictive Dialer Using Playwright — And What It Taught Me</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Mon, 06 Apr 2026 12:25:16 +0000</pubDate>
      <link>https://dev.to/magi-magificient/how-i-found-a-hidden-login-bug-in-a-predictive-dialer-using-playwright-and-what-it-taught-me-4pe2</link>
      <guid>https://dev.to/magi-magificient/how-i-found-a-hidden-login-bug-in-a-predictive-dialer-using-playwright-and-what-it-taught-me-4pe2</guid>
      <description>&lt;p&gt;&lt;em&gt;Testing a complex telephony platform revealed something unexpected: not all user agents are created equal.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  First, What Even Is a Predictive Dialer?
&lt;/h2&gt;

&lt;p&gt;If you're not from a contact center or sales tech background, you might be wondering — what exactly is a predictive dialer?&lt;/p&gt;

&lt;p&gt;I'll give you the short version before we get into the QA story.&lt;/p&gt;

&lt;p&gt;A predictive dialer is a system used in call centers that &lt;strong&gt;automatically dials phone numbers&lt;/strong&gt; from a contact list and connects answered calls to available agents — all in real time. The "predictive" part means it uses algorithms to predict when an agent will be free and starts dialing the next number &lt;em&gt;before&lt;/em&gt; the current call ends, minimizing idle time.&lt;/p&gt;

&lt;p&gt;Modern predictive dialers — like the ones built on platforms such as &lt;a href="https://www.cleartouch.in/" rel="noopener noreferrer"&gt;ClearTouch&lt;/a&gt; — have evolved far beyond simple auto-dialing. Today's &lt;a href="https://www.cleartouch.in/blog/what-is-ai-dialer-and-how-it-works-in-modern-sales/" rel="noopener noreferrer"&gt;AI-powered dialers&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rank leads by likelihood to answer&lt;/li&gt;
&lt;li&gt;Detect voicemail vs live humans in real time&lt;/li&gt;
&lt;li&gt;Adjust dialing pace dynamically based on agent availability&lt;/li&gt;
&lt;li&gt;Feed context to agents &lt;em&gt;before&lt;/em&gt; the call even begins&lt;/li&gt;
&lt;li&gt;Learn from every call outcome to improve future decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essentially, the platform is a decision engine, not just a phone dialer.&lt;/p&gt;

&lt;p&gt;Now imagine testing that.&lt;/p&gt;




&lt;h2&gt;
  
  
  My QA Assignment: Automated Login Testing for a Dialer Platform
&lt;/h2&gt;

&lt;p&gt;As a QA Specialist, I was tasked with setting up automated end-to-end login tests for a web-based predictive dialer application. The goal was straightforward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Verify that the login flow works reliably across different browsers and user environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simple enough, right? I reached for &lt;strong&gt;Playwright&lt;/strong&gt; — my go-to for browser automation — and got started.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;Here's how I structured the test suite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;devices&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USER_AGENTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Chrome Windows&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Firefox Linux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/121.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Safari macOS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Chrome Android (Mobile)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Legacy Edge (Old)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Headless Chrome (Bot-like)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/120.0.0.0 Safari/537.36&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ua&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;USER_AGENTS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Login should succeed - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://dialer-app.example.com/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testuser@qa.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SecurePass@123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#login-btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/.*dashboard/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.agent-panel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, readable, scalable. I ran it and... most tests passed.&lt;/p&gt;

&lt;p&gt;But not all.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bug: Certain User Agents Silently Blocked Login
&lt;/h2&gt;

&lt;p&gt;Two specific user agents were failing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Legacy Edge (EdgeHTML 18)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headless Chrome&lt;/strong&gt; (the raw &lt;code&gt;HeadlessChrome/&lt;/code&gt; string in the UA)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The behavior was strange. The tests weren't throwing errors. The login form was submitting. But instead of redirecting to the dashboard, the page was either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refreshing back to the login screen silently, OR&lt;/li&gt;
&lt;li&gt;Showing a blank white page with no error message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No toast. No &lt;code&gt;401&lt;/code&gt;. No console error visible to the user. Just... nothing.&lt;/p&gt;

&lt;p&gt;Here's the Playwright assertion that caught it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This was FAILING for the two problematic UAs&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/.*dashboard/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Error output:&lt;/span&gt;
&lt;span class="c1"&gt;// Error: Timed out 10000ms waiting for expect(page).toHaveURL()&lt;/span&gt;
&lt;span class="c1"&gt;// Expected pattern: /.*dashboard/&lt;/span&gt;
&lt;span class="c1"&gt;// Received string:  "https://dialer-app.example.com/login"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added a screenshot capture to understand what the user was actually seeing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Added to the test for debugging&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`screenshots/login-fail-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.png`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fullPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bodyText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] Page body text:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bodyText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The screenshots confirmed it: the login page was re-rendering, credentials cleared, no feedback given to the user. A real user in those environments would simply think the app was broken — or worse, assume their credentials were wrong and get locked out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Digging Deeper: Why Were These UAs Blocked?
&lt;/h2&gt;

&lt;p&gt;I added network request logging to trace what was happening at the API level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] Auth API → Status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output for the failing cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Legacy Edge (Old)] Auth API → Status: 403
[Headless Chrome (Bot-like)] Auth API → Status: 403
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There it was. The backend was returning &lt;strong&gt;HTTP 403 Forbidden&lt;/strong&gt; for both — but the frontend was swallowing that response and silently redirecting back to login instead of displaying an error.&lt;/p&gt;

&lt;p&gt;Two bugs in one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bug #1 (Backend):&lt;/strong&gt; The server-side logic was blocking login requests based on user agent string pattern matching — likely an anti-bot or browser compatibility check that was too aggressive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bug #2 (Frontend):&lt;/strong&gt; The application wasn't handling &lt;code&gt;403&lt;/code&gt; responses from the auth API correctly. It should have shown a meaningful error message, but it was silently failing.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  How I Documented and Reported the Bug
&lt;/h2&gt;

&lt;p&gt;I raised two separate tickets with the dev team — one for backend, one for frontend:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bug Report #1 — Backend&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Title:&lt;/strong&gt; Login API returns 403 for Legacy Edge and Headless Chrome user agents&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Severity:&lt;/strong&gt; High&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps to Reproduce:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send POST to &lt;code&gt;/api/auth/login&lt;/code&gt; with valid credentials&lt;/li&gt;
&lt;li&gt;Set User-Agent header to: &lt;code&gt;Mozilla/5.0 (Windows NT 10.0...) Edge/18.17763&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Observe 403 response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Expected:&lt;/strong&gt; 200 with auth token&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actual:&lt;/strong&gt; 403 Forbidden — no descriptive response body&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Any agent or supervisor using Legacy Edge cannot log in at all. Automated integration tools and certain CI pipelines using headless Chrome may also be blocked.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Bug Report #2 — Frontend&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Title:&lt;/strong&gt; Login form silently reloads on 403 — no error shown to user&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Severity:&lt;/strong&gt; Medium&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps to Reproduce:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Trigger a 403 from the auth API (see Bug #1)&lt;/li&gt;
&lt;li&gt;Observe frontend behavior&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Expected:&lt;/strong&gt; Display message: "Login failed. Please check your credentials or contact support."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actual:&lt;/strong&gt; Page refreshes silently. No error, no toast, no redirect explanation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Users experience a confusing dead end. No guidance to resolve the issue.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why This Matters for Predictive Dialer Platforms Specifically
&lt;/h2&gt;

&lt;p&gt;This wasn't just a generic web app login bug. The context here matters.&lt;/p&gt;

&lt;p&gt;Predictive dialer platforms are used in &lt;strong&gt;high-pressure, real-time environments&lt;/strong&gt;. A contact center agent starts their shift, opens the dialer, and needs to be connected and ready within minutes. They're not developers. They don't check browser consoles.&lt;/p&gt;

&lt;p&gt;If login silently fails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Calls don't get made.&lt;/strong&gt; The dialer can't pace outbound calls without agents marked as available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLAs are missed.&lt;/strong&gt; Outbound campaigns have timing windows — miss them and you lose the opportunity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supervisors can't monitor.&lt;/strong&gt; Real-time dashboards depend on agents being logged into the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The AI logic breaks.&lt;/strong&gt; Modern dialers like the ones described by ClearTouch learn from agent availability signals. If agents can't log in, the prediction engine is working with incomplete data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What looks like a minor auth bug has cascading effects in a telephony platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Future of QA in Predictive Dialer Testing
&lt;/h2&gt;

&lt;p&gt;This experience got me thinking about where QA is heading for platforms like this.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. User Agent Testing Isn't Optional Anymore
&lt;/h3&gt;

&lt;p&gt;Enterprise tools get accessed from aging hardware. Legacy browsers exist in the real world — especially in BPO environments where desktops aren't frequently upgraded. &lt;strong&gt;Testing a matrix of user agents should be standard&lt;/strong&gt;, not an afterthought.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Silent Failures Are the Worst Failures
&lt;/h3&gt;

&lt;p&gt;A crash is obvious. A silent failure hides in production until a real user is hurt by it. Playwright is exceptional at catching these because it makes assertions about &lt;em&gt;final state&lt;/em&gt;, not just the absence of errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. AI Dialers Will Demand AI-Level QA
&lt;/h3&gt;

&lt;p&gt;As predictive dialers become more AI-driven — scoring leads, adapting pacing, feeding pre-call context to agents — the QA surface explodes. You're no longer just testing a UI. You're testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model output consistency&lt;/li&gt;
&lt;li&gt;Real-time API decision latency&lt;/li&gt;
&lt;li&gt;CRM integration data accuracy&lt;/li&gt;
&lt;li&gt;Compliance rule enforcement &lt;em&gt;before&lt;/em&gt; calls are placed&lt;/li&gt;
&lt;li&gt;Voice detection accuracy (human vs voicemail)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Playwright alone won't cut it for all of this. The future is &lt;strong&gt;AI-assisted QA&lt;/strong&gt; — using ML models to generate test cases, detect anomalies in response patterns, and flag regressions in model behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Observability Is a QA Concern
&lt;/h3&gt;

&lt;p&gt;The frontend silently swallowing a 403 was partly a monitoring failure. Future QA pipelines for dialer platforms should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structured logging of all auth events&lt;/li&gt;
&lt;li&gt;Alerting on unexpected 4xx rates at the API layer&lt;/li&gt;
&lt;li&gt;Real user monitoring (RUM) to catch frontend error handling gaps&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Shift-Left on Browser Compatibility
&lt;/h3&gt;

&lt;p&gt;The user agent bug should have been caught in development, not in QA. The lesson: &lt;strong&gt;browser/UA compatibility checks belong in PR review pipelines&lt;/strong&gt;, not just in manual or exploratory testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I started this test run expecting to validate a login flow. I ended up discovering two bugs — one backend, one frontend — that would have silently blocked real users in production.&lt;/p&gt;

&lt;p&gt;Playwright gave me the visibility to find what a human tester easily would have missed: a page that &lt;em&gt;looked&lt;/em&gt; like it was doing something, but was actually failing quietly.&lt;/p&gt;

&lt;p&gt;If you're working on a predictive dialer platform — or any enterprise telephony product — don't underestimate the value of testing across user agents. The platform's intelligence means nothing if the agent can't get through the front door.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Are you also doing QA on contact center or telephony platforms? I'd love to hear about the edge cases you've found. Drop them in the comments below.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;#qa&lt;/code&gt; &lt;code&gt;#playwright&lt;/code&gt; &lt;code&gt;#testing&lt;/code&gt; &lt;code&gt;#javascript&lt;/code&gt; &lt;code&gt;#webdev&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;References:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;ClearTouch: &lt;a href="https://www.cleartouch.in/blog/what-is-ai-dialer-and-how-it-works-in-modern-sales/" rel="noopener noreferrer"&gt;AI Dialer — What It Is, How It Works, and Where It Fits in Modern Sales&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Playwright Documentation: &lt;a href="https://playwright.dev/docs/emulation" rel="noopener noreferrer"&gt;Browser Contexts &amp;amp; User Agent&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Hidden Problem in Contact Centers: Broken Customer Journeys (And How Playwright Fixed It)</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Wed, 18 Mar 2026 10:50:19 +0000</pubDate>
      <link>https://dev.to/magi-magificient/the-hidden-problem-in-contact-centers-broken-customer-journeys-and-how-playwright-fixed-it-681</link>
      <guid>https://dev.to/magi-magificient/the-hidden-problem-in-contact-centers-broken-customer-journeys-and-how-playwright-fixed-it-681</guid>
      <description>&lt;p&gt;Let’s talk about a problem most teams don’t notice… until customers start complaining.&lt;/p&gt;

&lt;p&gt;Not server crashes.&lt;br&gt;&lt;br&gt;
Not downtime.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Broken customer journeys.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  😬 The Real Issue: Everything Works… But Nothing Works Together
&lt;/h2&gt;

&lt;p&gt;In a modern &lt;a href="https://www.cleartouch.in/cloud-contact-center-solutions/?utm_source=organic&amp;amp;utm_medium=backlink&amp;amp;utm_campaign=seo&amp;amp;utm_content=devto_mangai_2026_03_18" rel="noopener noreferrer"&gt;cloud contact center software&lt;/a&gt;, multiple systems are involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRM
&lt;/li&gt;
&lt;li&gt;Ticketing tools
&lt;/li&gt;
&lt;li&gt;Call handling systems
&lt;/li&gt;
&lt;li&gt;Chat interfaces
&lt;/li&gt;
&lt;li&gt;Payment or collections systems
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually?&lt;br&gt;&lt;br&gt;
✅ They work perfectly.&lt;/p&gt;

&lt;p&gt;But together?&lt;/p&gt;

&lt;p&gt;❌ Things break in between.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ A Real Scenario
&lt;/h2&gt;

&lt;p&gt;Here’s something that actually happens in many support teams:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Customer raises a query via chat
&lt;/li&gt;
&lt;li&gt;Ticket gets created
&lt;/li&gt;
&lt;li&gt;Agent calls the customer
&lt;/li&gt;
&lt;li&gt;After the call → status should update to “Resolved”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But instead 👇&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ticket stays “Open”
&lt;/li&gt;
&lt;li&gt;Follow-up gets triggered again
&lt;/li&gt;
&lt;li&gt;Customer gets duplicate calls
&lt;/li&gt;
&lt;li&gt;Agent gets confused
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Result: Bad customer experience + wasted effort&lt;/p&gt;




&lt;h2&gt;
  
  
  🤯 Why This Happens
&lt;/h2&gt;

&lt;p&gt;Because most testing focuses on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Individual features
&lt;/li&gt;
&lt;li&gt;APIs
&lt;/li&gt;
&lt;li&gt;UI components
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But not on:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔴 &lt;strong&gt;End-to-end user journeys across systems&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that’s where the gap is.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Enter Playwright
&lt;/h2&gt;

&lt;p&gt;Playwright is an end-to-end testing framework that allows teams to test applications the way real users interact with them.&lt;/p&gt;

&lt;p&gt;Instead of testing isolated components, you can validate the entire workflow across systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 How Playwright Helped Fix This
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ 1. End-to-End Workflow Testing
&lt;/h3&gt;

&lt;p&gt;We simulated the full journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat initiated
&lt;/li&gt;
&lt;li&gt;Ticket created
&lt;/li&gt;
&lt;li&gt;Agent action
&lt;/li&gt;
&lt;li&gt;Status update
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in one automated test.&lt;/p&gt;

&lt;p&gt;👉 This exposed exactly where the workflow was breaking.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ 2. Cross-System Validation
&lt;/h3&gt;

&lt;p&gt;Playwright helped validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI updates
&lt;/li&gt;
&lt;li&gt;Backend responses
&lt;/li&gt;
&lt;li&gt;Data consistency across systems
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No more guessing where things failed.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ 3. Reliable Automation (No Flaky Tests)
&lt;/h3&gt;

&lt;p&gt;With features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-waiting
&lt;/li&gt;
&lt;li&gt;Network interception
&lt;/li&gt;
&lt;li&gt;Stable selectors
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tests became consistent and reliable.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ 4. Faster Debugging
&lt;/h3&gt;

&lt;p&gt;Playwright provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Screenshots
&lt;/li&gt;
&lt;li&gt;Videos
&lt;/li&gt;
&lt;li&gt;Detailed logs
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So developers can quickly identify and fix issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 The Impact
&lt;/h2&gt;

&lt;p&gt;After implementing Playwright:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Duplicate follow-ups reduced
&lt;/li&gt;
&lt;li&gt;✅ Ticket statuses updated correctly
&lt;/li&gt;
&lt;li&gt;⏱️ Debugging time decreased
&lt;/li&gt;
&lt;li&gt;😊 Customer experience improved
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 What Changed?
&lt;/h2&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Each system works fine, so the issue must be random.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We can clearly see where the journey breaks—and fix it fast.”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🚀 Final Thought
&lt;/h2&gt;

&lt;p&gt;Most teams focus on testing features.&lt;/p&gt;

&lt;p&gt;But users don’t experience features.&lt;/p&gt;

&lt;p&gt;👉 They experience &lt;strong&gt;journeys&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And when that journey breaks, it impacts trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 Key Takeaway
&lt;/h2&gt;

&lt;p&gt;If you're only testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs
&lt;/li&gt;
&lt;li&gt;UI components
&lt;/li&gt;
&lt;li&gt;Individual modules
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're missing the bigger picture.&lt;/p&gt;

&lt;p&gt;Start testing like a real user.&lt;/p&gt;

&lt;p&gt;That’s where end-to-end tools like Playwright make a real difference.&lt;/p&gt;




</description>
      <category>ai</category>
      <category>programming</category>
      <category>playwright</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Stop Selenium Tests from Clicking Before the Page is Ready</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Thu, 06 Nov 2025 11:30:00 +0000</pubDate>
      <link>https://dev.to/magi-magificient/how-to-stop-selenium-tests-from-clicking-before-the-page-is-ready-1pin</link>
      <guid>https://dev.to/magi-magificient/how-to-stop-selenium-tests-from-clicking-before-the-page-is-ready-1pin</guid>
      <description>&lt;h2&gt;
  
  
  Selenium: Using Explicit Waits for Spinners, Pop-ups &amp;amp; Loading Screens
&lt;/h2&gt;




&lt;h3&gt;
  
  
  Why This Matters
&lt;/h3&gt;

&lt;p&gt;One of the most common problems in Selenium testing is:&lt;br&gt;
Your test tries to click a button, type in a field, or read data &lt;strong&gt;before the page finishes loading.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This leads to errors like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ElementNotInteractableException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NoSuchElementException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StaleElementReferenceException&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In simple words → &lt;strong&gt;Selenium is faster than your website.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The browser is still loading, but Selenium is already trying to interact.&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;Explicit Waits&lt;/strong&gt; help.&lt;/p&gt;


&lt;h3&gt;
  
  
  What Are Explicit Waits?
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;Explicit Wait&lt;/strong&gt; tells Selenium:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Wait until a certain condition is true before moving to the next step.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You control &lt;em&gt;what&lt;/em&gt; to wait for and &lt;em&gt;how long&lt;/em&gt; to wait.&lt;/p&gt;

&lt;p&gt;Unlike general fixed waits (like &lt;code&gt;Thread.sleep(5000)&lt;/code&gt;),&lt;br&gt;
explicit waits are &lt;strong&gt;smart waits&lt;/strong&gt; — they wait &lt;strong&gt;only until needed&lt;/strong&gt;, not longer.&lt;/p&gt;


&lt;h3&gt;
  
  
  Example: Waiting for a Loading Spinner to Disappear
&lt;/h3&gt;

&lt;p&gt;Many modern web apps show a &lt;strong&gt;spinner&lt;/strong&gt; or &lt;strong&gt;loading animation&lt;/strong&gt; while content loads.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Without Explicit Wait&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"checkout"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If spinner is still visible → test fails.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;With Explicit Wait&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;WebDriverWait&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebDriverWait&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExpectedConditions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invisibilityOfElementLocated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".spinner"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"checkout"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now Selenium waits &lt;strong&gt;until the spinner disappears&lt;/strong&gt; before clicking.&lt;/p&gt;


&lt;h3&gt;
  
  
  Example: Waiting for a Modal Popup to Appear
&lt;/h3&gt;

&lt;p&gt;Sometimes you need to wait &lt;em&gt;for&lt;/em&gt; something to show up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;WebDriverWait&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebDriverWait&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExpectedConditions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visibilityOfElementLocated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"login-modal"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the modal is fully loaded before interacting.&lt;/p&gt;




&lt;h3&gt;
  
  
  Waiting for Network / AJAX Load
&lt;/h3&gt;

&lt;p&gt;Some pages update data &lt;strong&gt;in the background&lt;/strong&gt; (no full page refresh).&lt;br&gt;
Instead of checking time manually, we wait until the page appears “stable.”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebDriverWait&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webDriver&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;JavascriptExecutor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;webDriver&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeScript&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"return document.readyState"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"complete"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Wait until page loading is finished.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Why Explicit Waits Are Better Than &lt;code&gt;Thread.sleep()&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Thread.sleep()&lt;/th&gt;
&lt;th&gt;Explicit Wait&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Always waits full time&lt;/td&gt;
&lt;td&gt;Waits only as long as needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slows tests&lt;/td&gt;
&lt;td&gt;Makes tests faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Doesn’t care if page is ready&lt;/td&gt;
&lt;td&gt;Responds to real conditions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not reliable&lt;/td&gt;
&lt;td&gt;Very reliable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So instead of blindly waiting → Selenium waits &lt;strong&gt;intelligently&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  When to Use Explicit Waits
&lt;/h3&gt;

&lt;p&gt;Use explicit waits when your app has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loading spinners&lt;/li&gt;
&lt;li&gt;Popup messages&lt;/li&gt;
&lt;li&gt;Slow dropdowns&lt;/li&gt;
&lt;li&gt;AJAX-based content loads&lt;/li&gt;
&lt;li&gt;React/Angular dynamic UI updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically → Anytime the page takes time to update.&lt;/p&gt;




&lt;h3&gt;
  
  
  Best Practices
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Good Practice&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wait for disappearing elements&lt;/td&gt;
&lt;td&gt;Prevent premature clicks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wait for clickable element&lt;/td&gt;
&lt;td&gt;Ensures stability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wait for text/value change&lt;/td&gt;
&lt;td&gt;Validates real-time updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avoid long timeouts&lt;/td&gt;
&lt;td&gt;Speed + accuracy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Real-Life Example
&lt;/h3&gt;

&lt;p&gt;Before waits:&lt;br&gt;
Testers complained that tests passed sometimes and failed sometimes (flaky tests).&lt;/p&gt;

&lt;p&gt;After using explicit waits:&lt;br&gt;
&lt;strong&gt;Stable results&lt;/strong&gt;, fewer failures, and faster execution.&lt;/p&gt;

&lt;p&gt;This is one of the &lt;strong&gt;biggest improvements&lt;/strong&gt; QA leads notice.&lt;/p&gt;




&lt;h3&gt;
  
  
  In Simple Words
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Websites don’t load instantly.&lt;/li&gt;
&lt;li&gt;Selenium is very fast.&lt;/li&gt;
&lt;li&gt;If Selenium tries to interact before the page is ready → the test fails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explicit waits fix this by making Selenium pause &lt;em&gt;only&lt;/em&gt; until the page is ready.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  FAQs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Q1:&lt;/strong&gt; Do waits slow down tests?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No. They actually make tests faster because Selenium doesn’t have to retry failed steps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Q2:&lt;/strong&gt; Should we remove &lt;code&gt;Thread.sleep()&lt;/code&gt; completely?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes — use explicit waits instead. They are smarter and more reliable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Q3:&lt;/strong&gt; Is it hard to convert to explicit waits?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No — just replace direct actions with wait-and-action patterns.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
Using &lt;strong&gt;explicit waits&lt;/strong&gt; makes Selenium automation &lt;strong&gt;much more stable&lt;/strong&gt;.&lt;br&gt;
You avoid flaky tests, reduce failures, and let Selenium interact only when the page is ready.&lt;/p&gt;




&lt;p&gt;Still &lt;a href="https://www.testleaf.com/blog/why-automation-testing-with-selenium-is-still-the-1-choice-in-2026/" rel="noopener noreferrer"&gt;Selenium rule the Automation industry?&lt;/a&gt;&lt;/p&gt;

</description>
      <category>selenium</category>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Playwright Interview Questions and Answers (My Personal Experience)</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Thu, 06 Nov 2025 10:32:27 +0000</pubDate>
      <link>https://dev.to/magi-magificient/playwright-interview-questions-and-answers-my-personal-experience-1l03</link>
      <guid>https://dev.to/magi-magificient/playwright-interview-questions-and-answers-my-personal-experience-1l03</guid>
      <description>&lt;h2&gt;
  
  
  &lt;em&gt;Interview Series — JavaScript Fundamentals for Test Automation&lt;/em&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Q1. What is the difference between &lt;code&gt;slice()&lt;/code&gt; and &lt;code&gt;substring()&lt;/code&gt; in JavaScript?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Both &lt;code&gt;slice()&lt;/code&gt; and &lt;code&gt;substring()&lt;/code&gt; are used to extract part of a string. At first, they look like they work the same — but they behave differently when &lt;strong&gt;negative values&lt;/strong&gt; or &lt;strong&gt;reversed start–end values&lt;/strong&gt; are involved.&lt;/p&gt;

&lt;p&gt;Let’s use one example string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Playwright&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Basic Extraction&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;     &lt;span class="c1"&gt;// "Play"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "Play"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In normal cases, both give the same output.&lt;/p&gt;




&lt;h3&gt;
  
  
  Key Difference 1: &lt;strong&gt;Handling Negative Indices&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;       &lt;span class="c1"&gt;// "right"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// "Playwright"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;slice(-5)&lt;/code&gt; → Counts from end&lt;/td&gt;
&lt;td&gt;✅ Returns &lt;code&gt;"right"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;substring(-5)&lt;/code&gt; → Converts &lt;code&gt;-5&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌ Returns entire string&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;slice()&lt;/code&gt; &lt;strong&gt;understands negative indexing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;substring()&lt;/code&gt; &lt;strong&gt;ignores negative indexing&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Key Difference 2: &lt;strong&gt;If Start &amp;gt; End&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;      &lt;span class="c1"&gt;// "" (empty string)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// "ayw"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;slice()&lt;/code&gt; returns empty when start &amp;gt; end&lt;/td&gt;
&lt;td&gt;Keeps order exactly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;substring()&lt;/code&gt; automatically &lt;strong&gt;swaps the values&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Makes it work anyway&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Comparison Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;code&gt;slice(start, end)&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;substring(start, end)&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Negative index support&lt;/td&gt;
&lt;td&gt;✅ Yes (counts from end)&lt;/td&gt;
&lt;td&gt;❌ No (converted to 0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;If start &amp;gt; end&lt;/td&gt;
&lt;td&gt;❌ Returns empty&lt;/td&gt;
&lt;td&gt;✅ Automatically swaps values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works on&lt;/td&gt;
&lt;td&gt;Strings + Arrays&lt;/td&gt;
&lt;td&gt;Strings only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best Use&lt;/td&gt;
&lt;td&gt;Flexible slicing&lt;/td&gt;
&lt;td&gt;Safe string extraction when values are uncertain&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Internal Explanation (Simple Words)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;slice()&lt;/strong&gt; adjusts negative index by adding it to string length.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;substring()&lt;/strong&gt; treats any negative value as &lt;strong&gt;0&lt;/strong&gt;, and auto-reorders parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="nx"&gt;chars&lt;/span&gt;  
&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;treats&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="nx"&gt;whole&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  How to Answer in an Interview (Simple Version)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"&lt;code&gt;slice()&lt;/code&gt; supports negative indexing and keeps start/end order.&lt;br&gt;
&lt;code&gt;substring()&lt;/code&gt; does not support negative indexing and swaps start and end if needed.&lt;br&gt;
So &lt;code&gt;slice()&lt;/code&gt; is more flexible, while &lt;code&gt;substring()&lt;/code&gt; is safer for simple extractions."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Real QA Usage (Why Testers Should Know This)
&lt;/h3&gt;

&lt;p&gt;When parsing API responses, log messages, or dynamic text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;slice()&lt;/strong&gt; when taking values from &lt;strong&gt;end&lt;/strong&gt; of string&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;substring()&lt;/strong&gt; when taking values from &lt;strong&gt;beginning range&lt;/strong&gt; safely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: Extract last 4 digits of an ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Related Interview Follow-Up Questions (Highly Asked)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;What is the difference between &lt;code&gt;slice()&lt;/code&gt; and &lt;code&gt;splice()&lt;/code&gt;?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How is &lt;code&gt;substr()&lt;/code&gt; different from &lt;code&gt;slice()&lt;/code&gt;? Why is &lt;code&gt;substr()&lt;/code&gt; deprecated?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do you reverse a string without using built-in reverse() method?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do you extract numbers from a string?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What happens if &lt;code&gt;slice()&lt;/code&gt; receives floating number arguments?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Quick Summary (Easy to Remember)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ask Yourself&lt;/th&gt;
&lt;th&gt;Which One to Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Need to slice from the end?&lt;/td&gt;
&lt;td&gt;✅ Use &lt;code&gt;slice()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index values might be reversed?&lt;/td&gt;
&lt;td&gt;✅ Use &lt;code&gt;substring()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Working with arrays?&lt;/td&gt;
&lt;td&gt;✅ Use &lt;code&gt;slice()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simple safe string cut?&lt;/td&gt;
&lt;td&gt;✅ Use &lt;code&gt;substring()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




</description>
      <category>playwright</category>
      <category>interview</category>
      <category>career</category>
    </item>
    <item>
      <title>AI Testing Tool : How AI Fixes Broken Test Scripts Automatically</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Wed, 05 Nov 2025 12:30:00 +0000</pubDate>
      <link>https://dev.to/magi-magificient/ai-testing-tool-how-ai-fixes-broken-test-scripts-automatically-2j90</link>
      <guid>https://dev.to/magi-magificient/ai-testing-tool-how-ai-fixes-broken-test-scripts-automatically-2j90</guid>
      <description>&lt;p&gt;When people test websites using tools like Selenium or Playwright, their scripts often break whenever the website changes — for example, if a button name or layout changes.&lt;/p&gt;

&lt;p&gt;This blog shows how GenAI can now repair those broken tests on its own — without anyone opening the script to fix it manually.&lt;/p&gt;

&lt;p&gt;It’s about the new wave of “smart automation,” where AI helps testers save time and reduce repetitive work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Common Problem
&lt;/h2&gt;

&lt;p&gt;Imagine this:&lt;br&gt;
You’ve written a test that clicks the “Login” button.&lt;br&gt;
But one day, the developer changes that button to say “Sign In.”&lt;/p&gt;

&lt;p&gt;Now your test fails — because it’s still looking for “Login.”&lt;/p&gt;

&lt;p&gt;Normally, a tester must:&lt;/p&gt;

&lt;p&gt;Find the error,&lt;/p&gt;

&lt;p&gt;Open the test code, and&lt;/p&gt;

&lt;p&gt;Update it manually.&lt;/p&gt;

&lt;p&gt;When there are hundreds of tests, this becomes a nightmare.&lt;/p&gt;

&lt;h2&gt;
  
  
  How AI Changes This
&lt;/h2&gt;

&lt;p&gt;AI tools are now smart enough to “guess” what changed.&lt;br&gt;
They learn what your website looks like — the layout, colors, labels, and positions of elements.&lt;/p&gt;

&lt;p&gt;So when something changes, AI can say:&lt;/p&gt;

&lt;p&gt;“This looks like the new version of that button you used before. I’ll use it automatically.”&lt;/p&gt;

&lt;p&gt;And just like that — the test heals itself and continues running.&lt;/p&gt;

&lt;p&gt;That’s why it’s called “self-healing automation.”&lt;/p&gt;

&lt;p&gt;How AI Knows What to Fix&lt;/p&gt;

&lt;p&gt;Here’s how it works (in simple steps):&lt;/p&gt;

&lt;p&gt;Observe: AI watches all your tests and remembers patterns — like “this button always appears next to the password field.”&lt;/p&gt;

&lt;p&gt;Compare: When the test fails, AI checks what changed on the page.&lt;/p&gt;

&lt;p&gt;Predict: It uses logic and past data to find the new version of that element.&lt;/p&gt;

&lt;p&gt;Heal: It fixes the broken part temporarily or updates it automatically for you.&lt;/p&gt;

&lt;p&gt;Tools That Already Do This&lt;/p&gt;

&lt;p&gt;Testron.ai- Fixes broken locators automatically in Selenium or Playwright.&lt;br&gt;
Testim.io-Uses machine learning to find new elements when names change.&lt;br&gt;
Mabl-Predicts failures and repairs test paths before they break.&lt;br&gt;
Functionize-Lets testers describe tests in plain English; AI writes the code.&lt;/p&gt;

&lt;p&gt;These tools don’t replace your existing test setups — they add intelligence on top of them.&lt;/p&gt;

&lt;p&gt;Real-World Example&lt;/p&gt;

&lt;p&gt;Before AI, at least 10–15 of them broke daily due to small website updates.&lt;br&gt;
After adding AI-assisted healing, the number of failures dropped by 70%.&lt;/p&gt;

&lt;p&gt;That means testers spent more time writing new tests instead of fixing old ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It’s a Game-Changer
&lt;/h2&gt;

&lt;p&gt;✅ Saves time — less manual fixing.&lt;br&gt;
✅ Learns automatically — gets smarter after every test run.&lt;br&gt;
✅ Prevents test breaks — adapts to website changes.&lt;br&gt;
✅ Integrates easily — works with existing tools like Selenium and Playwright.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Analogy
&lt;/h2&gt;

&lt;p&gt;Think of it like Face ID on your phone.&lt;br&gt;
Even if you get a haircut or wear glasses, your phone still recognizes you.&lt;/p&gt;

&lt;p&gt;Similarly, AI-powered testing recognizes buttons and fields even if they look slightly different after an update.&lt;/p&gt;

&lt;p&gt;In Short&lt;/p&gt;

&lt;p&gt;Old tests break when a website changes.&lt;/p&gt;

&lt;p&gt;AI can now detect and fix those broken parts on its own.&lt;/p&gt;

&lt;p&gt;You get smarter, self-repairing automation that saves huge time.&lt;/p&gt;

&lt;p&gt;It’s the next step after Selenium and Playwright — the future of testing.&lt;/p&gt;

&lt;p&gt;🔗 If You Missed the Previous Blogs&lt;/p&gt;

&lt;p&gt;👉 Part A: &lt;a href="https://dev.to/magi-magificient/a-simple-trick-to-fix-broken-selenium-tests-data-testids-2dkc"&gt;Stop Your Selenium Tests from Breaking — Use data-testids&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 Part B: &lt;a href="https://dev.to/magi-magificient/how-playwright-finds-buttons-and-text-more-smartly-than-selenium-129"&gt;How Playwright Finds Buttons Smartly with Roles &amp;amp; TestIds&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Together, these three blogs show how automation is evolving:&lt;/p&gt;

&lt;p&gt;Selenium (Manual Fixing) → Playwright (Smart Locators) → AI (Self-Healing)&lt;/p&gt;

&lt;p&gt;❓ FAQs&lt;/p&gt;

&lt;p&gt;Q1: Do I need to know AI or coding for this?&lt;br&gt;
No — the tools handle it automatically. You just connect them to your existing tests.&lt;/p&gt;

&lt;p&gt;Q2: Does AI replace human testers?&lt;br&gt;
Not at all. It only removes repetitive fixing work so testers can focus on creative testing.&lt;/p&gt;

&lt;p&gt;Q3: Can I use this with my current Selenium or Playwright setup?&lt;br&gt;
Yes — these tools sit on top of your current system.&lt;/p&gt;

&lt;p&gt;Q4: Is it reliable?&lt;br&gt;
Mostly yes. AI uses “confidence levels” to ensure accuracy and shows a report of what it changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Final Summary
&lt;/h2&gt;

&lt;p&gt;AI in automation testing is like having an assistant who keeps your tests running smoothly, even when your website changes.&lt;/p&gt;

&lt;p&gt;It saves time, prevents frustration, and keeps your testing pipeline strong — 24/7.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>How Playwright Finds Buttons and Text More Smartly Than Selenium</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Tue, 04 Nov 2025 12:30:00 +0000</pubDate>
      <link>https://dev.to/magi-magificient/how-playwright-finds-buttons-and-text-more-smartly-than-selenium-129</link>
      <guid>https://dev.to/magi-magificient/how-playwright-finds-buttons-and-text-more-smartly-than-selenium-129</guid>
      <description>&lt;p&gt;This post talks about another testing tool called Playwright.&lt;/p&gt;

&lt;p&gt;Do you want to &lt;a href="https://www.testleaf.com/course/playwright.html/?utm_source=MgBklnk" rel="noopener noreferrer"&gt;learn playwright&lt;/a&gt; contact &lt;a href="https://www.testleaf.com/?utm_source=MgBklnk" rel="noopener noreferrer"&gt;testleaf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think of Playwright as a modern version of Selenium — it does the same job (checking whether a website works) but uses smarter ways to find things on the screen.&lt;/p&gt;

&lt;p&gt;Instead of depending on long, fragile paths like Selenium used to, Playwright looks for meaningful labels such as:&lt;/p&gt;

&lt;p&gt;the role of an element (like button, textbox, link)&lt;/p&gt;

&lt;p&gt;or a special tag (called a testId) that developers can add.&lt;/p&gt;

&lt;p&gt;These new ways make tests more stable, readable, and future-proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Example
&lt;/h2&gt;

&lt;p&gt;Let’s imagine a “Login” button again.&lt;/p&gt;

&lt;p&gt;With Selenium, a tester might have written:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// old fragile way
page.$("//div[3]/button").click();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the page design changes, this line fails.&lt;/p&gt;

&lt;p&gt;With Playwright, you can write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// smart new way
await page.getByRole('button', { name: 'Login' }).click();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here Playwright automatically finds the visible button that says “Login.”&lt;br&gt;
Even if the developer changes its position or layout, your test still works.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why It’s Better
&lt;/h2&gt;

&lt;p&gt;Fewer failures when the website changes.&lt;/p&gt;

&lt;p&gt;Easy to read — the code looks almost like plain English.&lt;/p&gt;

&lt;p&gt;No extra waiting — Playwright automatically waits until the button is clickable.&lt;/p&gt;

&lt;p&gt;Works with modern websites built in React, Angular, or Vue.&lt;/p&gt;

&lt;p&gt;What is getByRole() and getByTestId()?&lt;/p&gt;

&lt;p&gt;getByRole() looks for elements based on their function — for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;page.getByRole('textbox', { name: 'Email' });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means “Find the text box called Email.”&lt;/p&gt;

&lt;p&gt;getByTestId() uses a tag added by developers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input data-testid="email-input" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in Playwright:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;page.getByTestId('email-input').fill('user@testleaf.com');

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s like giving every element a name tag that never changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mixing Both for Best Results
&lt;/h2&gt;

&lt;p&gt;Many testers use both together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const loginBtn = page.getByRole('button', { name: /login/i });
await expect(loginBtn).toBeEnabled();
await loginBtn.click();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes tests extra strong and human-friendly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Wait Feature
&lt;/h2&gt;

&lt;p&gt;A big win with Playwright is that it waits automatically for things to load or become clickable — no need to tell it to “wait 5 seconds.”&lt;br&gt;
That means fewer timing errors and faster scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration from Selenium to Playwright:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Selenium Way                           | Playwright Way                                |
| -------------------------------------- | --------------------------------------------- |
| `By.xpath("//button[text()='Login']")` | `page.getByRole('button', { name: 'Login' })` |
| `By.id("submit")`                      | `page.getByTestId('submit')`                  |

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  In Short
&lt;/h2&gt;

&lt;p&gt;Playwright is faster and more intelligent.&lt;/p&gt;

&lt;p&gt;It finds buttons and fields using roles or tags, not messy paths.&lt;/p&gt;

&lt;p&gt;Tests are cleaner, shorter, and more reliable.&lt;/p&gt;

&lt;p&gt;Great for any company using modern web apps.&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>selenium</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>A Simple Trick to Fix Broken Selenium Tests: "data-testids"</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Mon, 03 Nov 2025 12:23:41 +0000</pubDate>
      <link>https://dev.to/magi-magificient/a-simple-trick-to-fix-broken-selenium-tests-data-testids-2dkc</link>
      <guid>https://dev.to/magi-magificient/a-simple-trick-to-fix-broken-selenium-tests-data-testids-2dkc</guid>
      <description>&lt;p&gt;This article talks about how software testers find and click buttons, links, or text on a website automatically using a tool called Selenium.&lt;/p&gt;

&lt;p&gt;But there’s a problem — sometimes those automatic tests break when the website’s design changes even slightly.&lt;/p&gt;

&lt;p&gt;The blog teaches how to avoid that by using something called data-testid — a small label that developers can add to buttons or fields to make them easy for the test scripts to find every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Example
&lt;/h2&gt;

&lt;p&gt;Let’s say you have a website with a “Login” button.&lt;br&gt;
Normally, a tester would write something like:&lt;/p&gt;

&lt;p&gt;“Click the 3rd button inside that box.”&lt;/p&gt;

&lt;p&gt;But if the page layout changes, that 3rd button might move — and the test breaks.&lt;/p&gt;

&lt;p&gt;Instead, developers can add a label:&lt;/p&gt;

&lt;p&gt;Login&lt;/p&gt;

&lt;p&gt;Now the test can just say:&lt;/p&gt;

&lt;p&gt;“Click the button with label login-button.”&lt;/p&gt;

&lt;p&gt;No matter how the design changes, the test still works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Learn
&lt;/h2&gt;

&lt;p&gt;Old-style testing used complicated “paths” (called XPaths) to find elements.&lt;/p&gt;

&lt;p&gt;These paths often break when the website changes.&lt;/p&gt;

&lt;p&gt;Using data-testids makes your tests much more stable and future-proof.&lt;/p&gt;

&lt;p&gt;It also helps testers and developers work together better, since both agree on the labels to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Example
&lt;/h2&gt;

&lt;p&gt;Imagine an e-commerce site with 100 buttons and forms.&lt;br&gt;
Earlier, every small UI change broke many test scripts.&lt;br&gt;
After switching to data-testids, testers didn’t have to fix broken tests every day — saving hours of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Short
&lt;/h2&gt;

&lt;p&gt;Old method = fragile, keeps breaking&lt;/p&gt;

&lt;p&gt;New method (data-testid) = strong, stable, easy to manage&lt;/p&gt;

&lt;p&gt;Helps testers find website elements easily, even after design changes&lt;/p&gt;

&lt;p&gt;Makes the testing process faster and more reliable&lt;/p&gt;

</description>
      <category>selenium</category>
      <category>java</category>
      <category>automation</category>
    </item>
    <item>
      <title>How I helped 200+ manual testers move into automation testing</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Tue, 28 Oct 2025 06:44:31 +0000</pubDate>
      <link>https://dev.to/magi-magificient/how-i-helped-200-manual-testers-move-into-automation-testing-54i3</link>
      <guid>https://dev.to/magi-magificient/how-i-helped-200-manual-testers-move-into-automation-testing-54i3</guid>
      <description>&lt;p&gt;Body:&lt;br&gt;
When I started mentoring testers, I noticed one pattern — most were stuck not because of a lack of knowledge, but because they didn’t know where to start.&lt;/p&gt;

&lt;p&gt;So, we created a roadmap that worked — from manual to automation, step by step.&lt;/p&gt;

&lt;p&gt;Here’s what it includes:&lt;br&gt;
✅ The right order to learn tools (Selenium → Playwright → API → AI-assisted testing)&lt;br&gt;
✅ How to make your resume reflect automation skills&lt;br&gt;
✅ How to build small projects that attract recruiters&lt;/p&gt;

&lt;p&gt;If you’re exploring the same path, I’ve shared the detailed guide here 👉&lt;a href="https://www.testleaf.com/blog/career-roadmap-for-functional-test-automation-developers/" rel="noopener noreferrer"&gt;https://www.testleaf.com/blog/career-roadmap-for-functional-test-automation-developers/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>selenium</category>
      <category>javascript</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Playwright Interview Questions and Answers (My Personal Experience)</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Wed, 22 Oct 2025 10:25:56 +0000</pubDate>
      <link>https://dev.to/magi-magificient/playwright-interview-questions-and-answers-my-personal-experience-4enl</link>
      <guid>https://dev.to/magi-magificient/playwright-interview-questions-and-answers-my-personal-experience-4enl</guid>
      <description>&lt;p&gt;If you’re preparing for a QA automation interview, mastering Playwright can help you stand out from the crowd. This 2025 updated guide covers the most common and advanced Playwright interview questions — including real-world coding scenarios, differences from Selenium, and hands-on best practices.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Whether you’re a beginner or an experienced automation engineer, this article will help you gain clarity and confidence for your next interview.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Beginner-Level Playwright Interview Questions&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is Playwright?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&lt;br&gt;
Playwright is a modern end-to-end testing framework developed by Microsoft, designed to automate browsers (Chromium, Firefox, WebKit).&lt;br&gt;
It supports cross-browser, cross-platform, and multi-language testing (JS/TS, Python, Java, .NET).&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you handle waiting / synchronization issues in Playwright?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&lt;br&gt;
Playwright auto-waits for elements to become actionable before performing any action.&lt;br&gt;
Still, you can use:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;await page.waitForSelector('#submit');&lt;br&gt;
await expect(page.locator('#success')).toBeVisible();&lt;br&gt;
await page.waitForLoadState('networkidle');&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Types:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Auto-wait → built-in for actions like .click(), .fill()&amp;nbsp;&lt;br&gt;
Explicit wait → page.waitForSelector(), expect(locator).toBeVisible()&amp;nbsp;&lt;br&gt;
No implicit waits like Selenium (Playwright avoids flakiness by design).&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Other Recommended Reads: api automation interview questions&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you run tests in parallel or in multiple browsers/devices/contexts?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Parallel Execution: Each test runs in an isolated worker.&amp;nbsp;&lt;br&gt;
Multiple Browsers/Devices: Defined via projects in playwright.config.ts&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;export default defineConfig({&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp; fullyParallel: true,&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp; workers: 4,&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp; projects: [&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { name: 'chromium', use: { browserName: 'chromium' } },&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { name: 'firefox', use: { browserName: 'firefox' } },&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { name: 'webkit', use: { browserName: 'webkit' } },&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp; ],&amp;nbsp;&lt;/p&gt;

&lt;p&gt;});&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you run Playwright tests headlessly vs headed?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Headless: For CI/CD environments (default).&amp;nbsp;&lt;br&gt;
Headed: For debugging or local runs.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;npx playwright test --headed&lt;br&gt;
npx playwright test --headless&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Or in config:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;use: { headless: false }&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you manage environment configuration (dev/stage/prod)?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Use .env files or JSON config files.&amp;nbsp;&lt;br&gt;
Access variables via process.env.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Example:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;BASE_URL=&lt;a href="https://staging.example.com" rel="noopener noreferrer"&gt;https://staging.example.com&lt;/a&gt;&lt;br&gt;
&amp;nbsp;export default defineConfig({&lt;br&gt;
&amp;nbsp;use: { baseURL: process.env.BASE_URL }&lt;br&gt;
});&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What makes a “good API”? What best practices do you follow?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&lt;br&gt;
A good API is consistent, predictable, secure, and well-versioned.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Best Practices:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Proper HTTP verbs (GET, POST, PUT, DELETE)&amp;nbsp;&lt;br&gt;
Correct status codes (200, 201, 400, 404, 500)&amp;nbsp;&lt;br&gt;
Consistent naming conventions&amp;nbsp;&lt;br&gt;
Pagination &amp;amp; filtering&amp;nbsp;&lt;br&gt;
Versioning (/v1/users)&amp;nbsp;&lt;br&gt;
Proper authentication (OAuth/JWT)&amp;nbsp;&lt;br&gt;
Meaningful error messages&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you handle authentication &amp;amp; authorization in APIs?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Use JWT tokens, API keys, or OAuth2.&amp;nbsp;&lt;br&gt;
Fetch token via a login request, reuse it across tests.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;const api = await request.newContext({&lt;br&gt;
&amp;nbsp;extraHTTPHeaders: { Authorization: &lt;code&gt;Bearer ${token}&lt;/code&gt; }&lt;br&gt;
});&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you ensure your test automation code is maintainable and scalable?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Use Page Object Model (POM).&amp;nbsp;&lt;br&gt;
Centralize locators and common logic.&amp;nbsp;&lt;br&gt;
Use fixtures for setup/teardown.&amp;nbsp;&lt;br&gt;
Parameterize environment/config.&amp;nbsp;&lt;br&gt;
Implement clear naming conventions and folder structure.&amp;nbsp;&lt;br&gt;
Continuous refactoring, DRY principle, and TypeScript typings.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you build custom fixtures in Playwright?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&lt;br&gt;
Fixtures let you share setup/teardown logic.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;import { test as base } from '@playwright/test';&lt;/p&gt;

&lt;p&gt;type MyFixtures = { loginPage: LoginPage };&lt;br&gt;
const test = base.extend({&lt;br&gt;
&amp;nbsp;loginPage: async ({ page }, use) =&amp;gt; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;const login = new LoginPage(page);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;await use(login);&lt;br&gt;
&amp;nbsp;},&lt;br&gt;
});&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Intermediate-Level Playwright Interview Questions&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is the difference between browser, context, and page in Playwright?&amp;nbsp;
Object&amp;nbsp;    Description&amp;nbsp;
Browser&amp;nbsp;   Top-level instance (e.g., Chromium).&amp;nbsp;
Context&amp;nbsp;   Isolated incognito-like session within a browser.&amp;nbsp;
Page&amp;nbsp;  Represents a single tab in a browser context.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you select elements? What are locators?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&lt;br&gt;
Locators are Playwright’s recommended way to find elements.&lt;br&gt;
They are lazy-evaluated and auto-wait.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;const loginBtn = page.locator('button:has-text("Login")');&lt;br&gt;
await loginBtn.click();&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is a fixture in Playwright Test?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answer:&lt;br&gt;
A fixture is a reusable setup resource (like browser context, page, API client).&lt;br&gt;
Playwright provides built-in fixtures like page, context, request.&lt;br&gt;
You can extend them for custom object&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you handle file uploads or downloads?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Upload:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;await page.setInputFiles('input[type="file"]', 'tests/data/sample.pdf');&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Download:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;const [download] = await Promise.all([&lt;br&gt;
&amp;nbsp;page.waitForEvent('download'),&lt;br&gt;
&amp;nbsp;page.click('text=Download File'),&lt;br&gt;
]);&lt;br&gt;
await download.saveAs('downloads/file.pdf');&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Difference between page.locator(selector).click() and page.click(selector)&amp;nbsp;
Method&amp;nbsp;    Behavior&amp;nbsp;
page.locator().click()&amp;nbsp;    Uses Locator API (auto-wait, retries). ✅&amp;nbsp;
page.click()&amp;nbsp;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Executes immediately (can be&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;flaky). ⚠️&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Additional Resources: product based companies in bangalore&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to assert something in Playwright Test?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use expect() API:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;await expect(page).toHaveURL(/dashboard/);&lt;br&gt;
await expect(locator).toBeVisible();&lt;br&gt;
await expect(locator).toHaveText('Welcome');&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Difference between page.waitForLoadState('networkidle') and waitForNavigation()&amp;nbsp;
Method&amp;nbsp;    Purpose&amp;nbsp;
waitForLoadState('networkidle')&amp;nbsp;   Waits for no network connections for 500ms.&amp;nbsp;
waitForNavigation()&amp;nbsp;   Waits for a navigation event triggered by an action.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use waitForLoadState when waiting for background requests, not full navigation.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to use test hooks and where to place them?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hooks manage setup/cleanup:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;test.beforeAll(...)&lt;br&gt;
test.beforeEach(...)&lt;br&gt;
test.afterEach(...)&lt;br&gt;
test.afterAll(...)&lt;/p&gt;

&lt;p&gt;Placed inside test.describe() or globally in test files.&lt;br&gt;
Best practice: use hooks for test data setup and teardown.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you generate and publish HTML / Allure / custom reports?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;HTML report:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;npx playwright test --reporter=html&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Allure report:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;npm install --save-dev allure-playwright&lt;br&gt;
npx playwright test --reporter=allure-playwright&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Publishing in GitHub Actions:&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run: npx playwright test --reporter=html&lt;/li&gt;
&lt;li&gt;uses: actions/upload-artifact@v4
&amp;nbsp;with:
&amp;nbsp;&amp;nbsp;&amp;nbsp;name: report
&amp;nbsp;&amp;nbsp;&amp;nbsp;path: playwright-report/
&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Can Playwright be used for API testing? How?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Yes.&lt;br&gt;
Playwright provides APIRequestContext to perform REST API testing.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;const api = await request.newContext();&lt;br&gt;
const res = await api.get('&lt;a href="https://api.example.com/users'" rel="noopener noreferrer"&gt;https://api.example.com/users'&lt;/a&gt;);&lt;br&gt;
expect(res.status()).toBe(200);&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Advanced Playwright Interview Questions for Experienced Testers&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you create an API request context with authentication?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;const api = await request.newContext({&lt;br&gt;
&amp;nbsp;baseURL: '&lt;a href="https://api.example.com" rel="noopener noreferrer"&gt;https://api.example.com&lt;/a&gt;',&lt;br&gt;
&amp;nbsp;extraHTTPHeaders: {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;Authorization: &lt;code&gt;Bearer ${token}&lt;/code&gt;,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;'Content-Type': 'application/json',&lt;br&gt;
&amp;nbsp;},&lt;br&gt;
});&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you chain API calls (use one response to feed another)?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;const createUser = await api.post('/users', { data: { name: 'John' } });&lt;br&gt;
const id = (await createUser.json()).id;&lt;br&gt;
const getUser = await api.get(&lt;code&gt;/users/${id}&lt;/code&gt;);&lt;br&gt;
expect(getUser.status()).toBe(200);&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is Playwright’s APIRequestContext and how is it used for API testing?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It represents an isolated API session that can:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Send REST requests&amp;nbsp;&lt;br&gt;
Store cookies, headers, and auth data&amp;nbsp;&lt;br&gt;
Reuse between tests&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you architect a Playwright test suite for a large codebase?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Best practice structure:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;├── pages/&lt;br&gt;
├── api/&lt;br&gt;
├── fixtures/&lt;br&gt;
└── utils/&lt;br&gt;
├── tests/&lt;br&gt;
│ &amp;nbsp;&amp;nbsp;├── ui/&lt;br&gt;
│ &amp;nbsp;&amp;nbsp;└── api/&lt;br&gt;
├── playwright.config.ts&lt;br&gt;
└── package.json&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Principles:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Reusable page &amp;amp; API classes&amp;nbsp;&lt;br&gt;
Configurable environments&amp;nbsp;&lt;br&gt;
Modular utilities &amp;amp; fixtures&amp;nbsp;&lt;br&gt;
Parallel-safe test data setup&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to parallelize tests safely when they share resources?&amp;nbsp;
Avoid shared mutable data.&amp;nbsp;
Use unique test data per worker (uuid, timestamp).&amp;nbsp;
Isolate environments using fixtures.&amp;nbsp;
Use locks or queues only when unavoidable (e.g., shared DB).&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Basic JS: What’s the difference between == and ===?&amp;nbsp;
Operator&amp;nbsp;  Meaning&amp;nbsp;
==&amp;nbsp;    Equality with type coercion&amp;nbsp;
===&amp;nbsp;   Strict equality, no type conversion&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;'5' == 5 &amp;nbsp;&amp;nbsp;// true&lt;br&gt;
'5' === 5 &amp;nbsp;// false&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;26 : How do you handle dropdowns with  and  in Playwright?&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Answer:&lt;br&gt;
In Playwright, you handle  dropdowns using the selectOption() method. It allows selecting an option by value, label, or index. For multi-select dropdowns, you can pass an array of values.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Example:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;import { test, expect } from '@playwright/test';&lt;/p&gt;

&lt;p&gt;test('Select dropdown option', async ({ page }) =&amp;gt; {&lt;br&gt;
&amp;nbsp;await page.goto('&lt;a href="https://example.com'" rel="noopener noreferrer"&gt;https://example.com'&lt;/a&gt;);&lt;/p&gt;

&lt;p&gt;&amp;nbsp;// Select by value&lt;br&gt;
&amp;nbsp;await page.selectOption('#country', 'ca'); // Canada&lt;/p&gt;

&lt;p&gt;&amp;nbsp;// Select by label&lt;br&gt;
&amp;nbsp;await page.selectOption('#country', { label: 'United Kingdom' });&lt;/p&gt;

&lt;p&gt;&amp;nbsp;// Select by index&lt;br&gt;
&amp;nbsp;await page.selectOption('#country', { index: 0 }); // United States&lt;/p&gt;

&lt;p&gt;&amp;nbsp;// Verify selection&lt;br&gt;
&amp;nbsp;const selectedValue = await page.$eval('#country', el =&amp;gt; (el as HTMLSelectElement).value);&lt;br&gt;
&amp;nbsp;expect(selectedValue).toBe('us');&lt;br&gt;
});&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Key Points:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Works only with  elements.&amp;nbsp;&lt;br&gt;
Can select by value, label, or index.&amp;nbsp;&lt;br&gt;
Supports multi-select: await page.selectOption('#multi', ['us', 'uk']).&amp;nbsp;&lt;br&gt;
Playwright automatically handles the dropdown; no manual click needed.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;27 : How do you handle a dropdown that dynamically loads options based on previous selection?&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Answer:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;First, select the parent dropdown option using selectOption().&amp;nbsp;&lt;br&gt;
Wait for the child dropdown to be populated using page.waitForSelector() or locator.waitFor().&amp;nbsp;&lt;br&gt;
Then, select the desired child option.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Example:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;await page.selectOption('#country', 'us');&lt;br&gt;
await page.waitForSelector('#state option:not(:empty)');&lt;br&gt;
await page.selectOption('#state', 'ca'); // Select California&amp;nbsp;&lt;/p&gt;

&lt;p&gt;28: Difference between var, let, and const&amp;nbsp;&lt;br&gt;
Feature&amp;nbsp;   var&amp;nbsp;   let&amp;nbsp;   const&amp;nbsp;&lt;br&gt;
Scope&amp;nbsp; Function-scoped&amp;nbsp;   Block-scoped&amp;nbsp;  Block-scoped&amp;nbsp;&lt;br&gt;
Redeclaration&amp;nbsp; Allowed&amp;nbsp;   Not allowed&amp;nbsp;   Not allowed&amp;nbsp;&lt;br&gt;
Re-assignment&amp;nbsp; Allowed&amp;nbsp;   Allowed&amp;nbsp;   Not allowed (must be initialized)&amp;nbsp;&lt;br&gt;
Hoisting&amp;nbsp;  Yes (initialized as undefined)&amp;nbsp;    Yes (temporal dead zone)&amp;nbsp;  Yes (temporal dead zone)&amp;nbsp;&lt;br&gt;
Use case&amp;nbsp;  Legacy code&amp;nbsp;   Modern variables&amp;nbsp;  Constants / immutable references&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Key points:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Use let for variables that change.&amp;nbsp;&lt;br&gt;
Use const for values that shouldn’t change.&amp;nbsp;&lt;br&gt;
Avoid var in modern JavaScript due to scoping issues.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;29: How do Promises to differ from callbacks?&amp;nbsp;&lt;br&gt;
Feature&amp;nbsp;   Callbacks&amp;nbsp; Promises&amp;nbsp;&lt;br&gt;
Syntax&amp;nbsp;    Function passed as argument&amp;nbsp;   Object with .then() / .catch()&amp;nbsp;&lt;br&gt;
Handling async&amp;nbsp;    Nested or “callback hell”&amp;nbsp; Chainable, avoids nested callbacks&amp;nbsp;&lt;br&gt;
Error handling&amp;nbsp;    Needs try/catch inside callback&amp;nbsp;   Built-in .catch() for errors&amp;nbsp;&lt;br&gt;
Execution&amp;nbsp; Executes immediately when function runs&amp;nbsp;   Executes asynchronously and resolves later&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Example:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;// Callback&lt;br&gt;
doSomething(function(result) {&lt;br&gt;
&amp;nbsp;doSomethingElse(result, function(newResult) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;console.log(newResult);&lt;br&gt;
&amp;nbsp;});&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// Promise&lt;br&gt;
doSomething()&lt;br&gt;
&amp;nbsp;.then(result =&amp;gt; doSomethingElse(result))&lt;br&gt;
&amp;nbsp;.then(newResult =&amp;gt; console.log(newResult))&lt;br&gt;
&amp;nbsp;.catch(error =&amp;gt; console.error(error));&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Summary for Interview:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Promises provide better readability and error handling than callbacks.&amp;nbsp;&lt;br&gt;
Helps avoid “callback hell” for complex async code.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;30: What is Hoisting?&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Definition:&lt;br&gt;
Hoisting is JavaScript’s behavior of moving variable and function declarations to the top of their scope during compilation.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Key Points:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Only declarations are hoisted, not initializations.&amp;nbsp;&lt;br&gt;
var variables are hoisted with value undefined.&amp;nbsp;&lt;br&gt;
let and const are hoisted but in a temporal dead zone (TDZ) until initialization.&amp;nbsp;&lt;br&gt;
Function declarations are fully hoisted, but function expressions are not.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Example:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;console.log(a); // undefined&lt;br&gt;
var a = 10;&lt;/p&gt;

&lt;p&gt;console.log(b); // ReferenceError&lt;br&gt;
let b = 20;&lt;/p&gt;

&lt;p&gt;foo(); // Works&lt;br&gt;
function foo() { console.log('Hello'); }&lt;/p&gt;

&lt;p&gt;bar(); // Error&lt;br&gt;
const bar = function() { console.log('Hi'); }&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Playwright vs Selenium — Key Differences&amp;nbsp;&lt;br&gt;
Feature&amp;nbsp;   Playwright&amp;nbsp;    Selenium&amp;nbsp;&lt;br&gt;
Auto-waiting&amp;nbsp;  ✅ Built-in&amp;nbsp;  ❌ Manual waits&amp;nbsp;&lt;br&gt;
Browser Contexts&amp;nbsp;  ✅ Yes&amp;nbsp;   ❌ Needs multiple drivers&amp;nbsp;&lt;br&gt;
Network Mocking&amp;nbsp;   ✅ Easy&amp;nbsp;  ⚠️ Limited&amp;nbsp;&lt;br&gt;
Speed&amp;nbsp; ⚡ Fast (CDP protocol)&amp;nbsp;   🐢 Slower (HTTP JSON wire)&amp;nbsp;&lt;br&gt;
API Testing&amp;nbsp;   ✅ Built-in&amp;nbsp;  ❌ External tools needed&amp;nbsp;&lt;/p&gt;

&lt;p&gt;💡 Pro Tip: Prefer page.locator() over page.click() for more reliable element handling.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Bonus: Real-Time Playwright Coding Questions&amp;nbsp;&lt;br&gt;
Write a Playwright script to log into a website and verify the title.&amp;nbsp;&lt;br&gt;
How do you capture screenshots and videos in Playwright?&amp;nbsp;&lt;br&gt;
Demonstrate API testing with Playwright using APIRequestContext.&amp;nbsp;&lt;br&gt;
How do you handle multiple tabs and pop-ups?&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Playwright Framework Best Practices&amp;nbsp;&lt;br&gt;
Use Page Object Model (POM) for scalability.&amp;nbsp;&lt;br&gt;
Integrate with CI/CD tools like Jenkins or GitHub Actions.&amp;nbsp;&lt;br&gt;
Implement test tagging for selective execution.&amp;nbsp;&lt;br&gt;
Maintain reusable test data and environment configs.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Playwright Interview Preparation Tips&amp;nbsp;&lt;/p&gt;

&lt;p&gt;✅ Practice automation challenges on GitHub repositories.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;✅ Review Playwright’s official documentation weekly.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;✅ Mock interviews help improve confidence.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;✅ Learn Playwright with real projects — not just syntax.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Conclusion: How to Prepare for a Playwright Interview&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Playwright is redefining automation with speed, reliability, and built-in testing features. Whether you’re transitioning from Selenium or starting fresh, understanding these questions and concepts will make you interview-ready.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;If you want hands-on mastery, explore a Playwright course online that blends practical frameworks and interview guidance — the key to building your automation career in 2025.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;FAQs&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Q1. What is Playwright used for?&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Playwright is used for end-to-end web automation testing across browsers and devices.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Q2. Is Playwright better than Selenium?&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Yes. Playwright offers faster execution, auto-waiting, and API testing support.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Q3. What are the most asked Playwright topics in interviews?&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Locators, waits, fixtures, POM, API testing, and Playwright vs Selenium.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>testing</category>
    </item>
    <item>
      <title>Use Case: Simulating a Payment Gateway Timeout with Playwright</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Tue, 19 Aug 2025 09:34:45 +0000</pubDate>
      <link>https://dev.to/magi-magificient/use-case-simulating-a-payment-gateway-timeout-with-playwright-253k</link>
      <guid>https://dev.to/magi-magificient/use-case-simulating-a-payment-gateway-timeout-with-playwright-253k</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;During testing, the payment flow needed to be validated for failure scenarios like gateway timeout. But the actual payment service was managed by a third-party provider, and modifying or slowing it down for testing was not possible due to compliance and contractual restrictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenge
&lt;/h2&gt;

&lt;p&gt;Couldn’t directly trigger timeouts in the real payment system.&lt;/p&gt;

&lt;p&gt;Needed to ensure the application displayed the correct error messages, handled retries, and logged the failure properly.&lt;/p&gt;

&lt;p&gt;Manually waiting for rare real-time outages was not practical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution (with Playwright)
&lt;/h2&gt;

&lt;p&gt;Using Playwright’s network mocking capability, the payment API call was intercepted and programmed to:&lt;/p&gt;

&lt;p&gt;Simulate a 408 timeout response.&lt;/p&gt;

&lt;p&gt;Delay the response beyond the configured threshold.&lt;/p&gt;

&lt;p&gt;Return a controlled failure payload for consistency across tests.&lt;/p&gt;

&lt;p&gt;This way, the timeout scenario could be reproduced on-demand without touching the live payment gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outcome
&lt;/h2&gt;

&lt;p&gt;Application’s error handling and retry logic were successfully validated.&lt;/p&gt;

&lt;p&gt;Saved significant time by avoiding dependency on external payment provider outages.&lt;/p&gt;

&lt;p&gt;Enabled QA team to cover edge cases that are critical for user trust and compliance.&lt;/p&gt;

&lt;p&gt;Would like you to know more use case related to Playwright , one of my mentor trained this in &lt;a href="//testleaf.com?utm-source=mgbklng"&gt;Testleaf &lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;you want to &lt;a href="https://www.testleaf.com/course/playwright.html?utm-source=mgbklng" rel="noopener noreferrer"&gt;learn Playwright&lt;/a&gt; with me or you need &lt;a href="https://www.testleaf.com/course/playwright.html?utm-source=mgbklng" rel="noopener noreferrer"&gt;playwright training&lt;/a&gt; reach me .&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Why I Switched to Playwright? ans: Playwright Assertions</title>
      <dc:creator>Mangai Ram</dc:creator>
      <pubDate>Tue, 22 Jul 2025 05:53:25 +0000</pubDate>
      <link>https://dev.to/magi-magificient/why-i-switched-to-playwright-ans-playwright-assertions-1cb3</link>
      <guid>https://dev.to/magi-magificient/why-i-switched-to-playwright-ans-playwright-assertions-1cb3</guid>
      <description>&lt;p&gt;I didn’t switch to Playwright just because it’s the “new cool tool.” &lt;/p&gt;

&lt;p&gt;I switched because I was tired of writing flaky tests that passed locally and failed on CI. &lt;/p&gt;

&lt;p&gt;Selenium, for all its legacy strengths, often left me guessing:&lt;/p&gt;

&lt;p&gt;Is the element visible yet? &lt;/p&gt;

&lt;p&gt;Did the page fully load? Should I throw in a sleep() just to be safe?&lt;/p&gt;

&lt;p&gt;That uncertainty wastes time. That’s where Playwright came in—and more specifically, its built-in assertions.&lt;/p&gt;

&lt;p&gt;What hooked me first was auto-waiting. &lt;/p&gt;

&lt;p&gt;Playwright’s expect() API waits for an element to meet a condition before throwing an error.&lt;/p&gt;

&lt;p&gt;No more chaining complex waits or debugging why a test randomly fails in staging. &lt;/p&gt;

&lt;p&gt;Whether I’m checking for toBeVisible(), toHaveText(), or even toHaveAttribute(), Playwright handles the timing internally. &lt;/p&gt;

&lt;p&gt;It felt like the framework finally had my back.&lt;/p&gt;

&lt;p&gt;Then came soft assertions. This was a game changer. &lt;/p&gt;

&lt;p&gt;With Selenium, one failed assertion meant the whole test bailed out. But Playwright allows expect.&lt;/p&gt;

&lt;p&gt;soft()—so I can validate multiple things and get a complete report of what failed. Especially in form validation or checkout flows, this saved me hours of reruns.&lt;/p&gt;

&lt;p&gt;And the failure diagnostics? Chef’s kiss. &lt;/p&gt;

&lt;p&gt;The error messages are clean, show expected vs received values, and I can trace test steps visually. It’s not just a failure—it’s a clue to a fix.&lt;/p&gt;

&lt;p&gt;Switching to Playwright wasn’t about hype. It was about stability, clarity, and speed. The assertion engine alone made the move worth it. &lt;/p&gt;

&lt;p&gt;If your tests are still a guessing game, you might want to give Playwright a try—not for the name, but for the confidence it brings to every single test.&lt;/p&gt;

&lt;p&gt;Referred from my own written blog : &lt;a href="https://www.testleaf.com/blog/free-playwright-tutorial-on-assertions-and-validations-for-automation-testers/" rel="noopener noreferrer"&gt;Playwright Assertions Free Tutorial&lt;/a&gt; &amp;amp; Why It Matters&lt;/p&gt;

</description>
      <category>playwright</category>
    </item>
  </channel>
</rss>
