<?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: Styrow.dev</title>
    <description>The latest articles on DEV Community by Styrow.dev (@styrow_dev).</description>
    <link>https://dev.to/styrow_dev</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%2F582887%2Fed580db1-04ef-4146-841f-0e8055a857bf.png</url>
      <title>DEV Community: Styrow.dev</title>
      <link>https://dev.to/styrow_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/styrow_dev"/>
    <language>en</language>
    <item>
      <title>How do you leverage Chrome DevTools Protocol (CDP) in Playwright to simulate advanced browser conditions, such as networ</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Thu, 05 Nov 2026 14:18:11 +0000</pubDate>
      <link>https://dev.to/styrow_dev/how-do-you-leverage-chrome-devtools-protocol-cdp-in-playwright-to-simulate-advanced-browser-164o</link>
      <guid>https://dev.to/styrow_dev/how-do-you-leverage-chrome-devtools-protocol-cdp-in-playwright-to-simulate-advanced-browser-164o</guid>
      <description>&lt;p&gt;🔥 Playwright Pro-Tip: Struggling to simulate realistic network latency or device sensors in your Playwright tests? Most engineers overlook this browser superpower.&lt;/p&gt;

&lt;p&gt;📌 Problem Statement&lt;br&gt;
High-fidelity testing often demands advanced browser condition simulations beyond standard Playwright APIs. Think network throttling, geolocation spoofing, or device sensor emulation. Without direct access, these scenarios are hard to reproduce, leading to missed bugs.&lt;/p&gt;

&lt;p&gt;💡 Solution &amp;amp; Code Walkthrough&lt;br&gt;
Playwright offers a &lt;code&gt;CDPSession&lt;/code&gt; object to tap directly into the Chrome DevTools Protocol (CDP). This allows granular control over browser internals, enabling powerful simulations like network throttling.&lt;br&gt;
✅ Obtain a &lt;code&gt;CDPSession&lt;/code&gt; from a &lt;code&gt;BrowserContext&lt;/code&gt; or &lt;code&gt;Page&lt;/code&gt; instance.&lt;br&gt;
✅ Use &lt;code&gt;client.send('Domain.command', {params})&lt;/code&gt; to execute CDP commands.&lt;br&gt;
✅ Listen for CDP events to react to browser changes.&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;Page&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;simulate network throttling via CDP&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="nx"&gt;page&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;client&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;context&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;newCDPSession&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network.enable&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network.emulateNetworkConditions&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="na"&gt;offline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;latency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 2000ms delay&lt;/span&gt;
    &lt;span class="na"&gt;downloadThroughput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 500 KB/s (bytes/s)&lt;/span&gt;
    &lt;span class="na"&gt;uploadThroughput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 200 KB/s (bytes/s)&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Navigating with throttling...&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;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://example.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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detach&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;• This code snippet demonstrates throttling network conditions, making &lt;code&gt;page.goto()&lt;/code&gt; experience a simulated slow connection. CDP domains like &lt;code&gt;Emulation&lt;/code&gt; can also spoof geolocation or device sensors.&lt;/p&gt;

&lt;p&gt;🔑 Key Takeaways&lt;br&gt;
• CDP enables deep browser interaction beyond Playwright's high-level APIs.&lt;br&gt;
• Use &lt;code&gt;newCDPSession()&lt;/code&gt; on &lt;code&gt;BrowserContext&lt;/code&gt; or &lt;code&gt;Page&lt;/code&gt;.&lt;br&gt;
• &lt;code&gt;client.send()&lt;/code&gt; executes raw CDP commands (&lt;code&gt;Domain.command&lt;/code&gt;).&lt;br&gt;
• Essential for advanced performance, security, accessibility testing.&lt;br&gt;
❌ Overuse can make tests brittle; use judiciously for specific conditions.&lt;/p&gt;

&lt;p&gt;❓ Quick Summary Q&amp;amp;A&lt;br&gt;
Q: What is &lt;code&gt;CDPSession&lt;/code&gt; in Playwright?&lt;br&gt;
A: An object for direct CDP access, enabling granular browser control.&lt;br&gt;
Q: Why use CDP with Playwright?&lt;br&gt;
A: To simulate network throttling, geolocation, or device sensors beyond standard Playwright APIs.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, cdp, network throttling, browser automation, testing, typescript, devtools protocol&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Level up your test automation skills!&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261105" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261105&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261105&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261105&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Validating Complex Client-Side Data Transformations in a Dynamic Dashboard with Playwright</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Wed, 04 Nov 2026 13:58:18 +0000</pubDate>
      <link>https://dev.to/styrow_dev/validating-complex-client-side-data-transformations-in-a-dynamic-dashboard-with-playwright-ne6</link>
      <guid>https://dev.to/styrow_dev/validating-complex-client-side-data-transformations-in-a-dynamic-dashboard-with-playwright-ne6</guid>
      <description>&lt;p&gt;🔥 Playwright Challenge: Validating Complex Client-Side Data in Dynamic Dashboards!&lt;br&gt;
Many engineers struggle to reliably test dashboards with client-side transformations without direct backend checks. How do you ensure accuracy?&lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;Problem Statement&lt;/strong&gt;&lt;br&gt;
Validating dynamic, client-side configurable dashboards presents a significant E2E testing challenge. The core difficulty lies in verifying UI-displayed data accurately reflects client-side computations and aggregations. Relying solely on visual text extraction from complex UI components is fragile against asynchronous operations and UI rendering nuances.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Solution &amp;amp; Code Walkthrough&lt;/strong&gt;&lt;br&gt;
A robust strategy integrates precise data seeding with client-side extraction.&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;Strategy for Dynamic Dashboard Validation:&lt;/strong&gt;&lt;br&gt;
    *   ✅ &lt;strong&gt;Controlled Test Data&lt;/strong&gt;: Seed your backend with known, predictable data via API &lt;em&gt;before&lt;/em&gt; the E2E test. This allows pre-calculating &lt;em&gt;expected&lt;/em&gt; transformed outcomes.&lt;br&gt;
    *   ✅ &lt;strong&gt;Programmatic UI Configuration&lt;/strong&gt;: Use Playwright to simulate user interactions, configuring the dashboard (filters, groupings, sources).&lt;br&gt;
    *   ✅ &lt;strong&gt;Client-side Data Extraction&lt;/strong&gt;: Leverage Playwright's &lt;code&gt;page.evaluate()&lt;/code&gt; to execute JavaScript directly in the browser. This accesses the application's state or DOM, offering reliable data validation.&lt;br&gt;
    *   ✅ &lt;strong&gt;Robust Assertions&lt;/strong&gt;: Compare extracted client-side data against pre-calculated expected data. Implement smart waits for rendering and transformation delays.&lt;br&gt;
    *   ✅ &lt;strong&gt;Test Isolation&lt;/strong&gt;: Run each test in a clean browser context to prevent state contamination.&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;Example: Extracting Aggregated Sales Data&lt;/strong&gt;&lt;br&gt;
We'll use &lt;code&gt;page.evaluate()&lt;/code&gt; to pull data directly from a displayed table.&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;expect&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;validates dynamic dashboard sales data&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="nx"&gt;page&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="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;your-dashboard-url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Programmatic UI Configuration (e.g., selecting filters)&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;selectOption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#region-filter&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;EMEA&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;selectOption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#category-group&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;Electronics&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;waitForTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Wait for client-side processing/rendering&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Client-side Data Extraction via page.evaluate()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;displayedSalesData&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;evaluate&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="c1"&gt;// This script runs in the browser context&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;salesElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.total-sales-widget span&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;salesElement&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;0-9.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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="c1"&gt;// 3. Robust Assertions (comparing with pre-calculated expected value)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedTotalSalesEMEAElectronics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;12345.67&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Pre-calculated from seeded data&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;displayedSalesData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeCloseTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedTotalSalesEMEAElectronics&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;// Assert with tolerance&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;`Displayed Sales: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;displayedSalesData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Expected Sales: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expectedTotalSalesEMEAElectronics&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach directly taps into the browser's runtime, bypassing fragile UI parsing and confirming client-side logic.&lt;/p&gt;

&lt;p&gt;🔑 &lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;br&gt;
•   &lt;strong&gt;Direct Validation&lt;/strong&gt;: &lt;code&gt;page.evaluate()&lt;/code&gt; provides a powerful way to access the browser's DOM or &lt;code&gt;window&lt;/code&gt; objects for precise data validation.&lt;br&gt;
•   &lt;strong&gt;Reduce Flakiness&lt;/strong&gt;: This method is more robust than pixel-based or strict text assertions, especially for dynamic content.&lt;br&gt;
•   &lt;strong&gt;Enhanced Test Coverage&lt;/strong&gt;: Confidently verify complex client-side logic and data transformations.&lt;br&gt;
•   &lt;strong&gt;Faster Feedback&lt;/strong&gt;: Catch discrepancies in client-side computations before they hit production.&lt;/p&gt;

&lt;p&gt;❓ &lt;strong&gt;Quick Summary Q&amp;amp;A&lt;/strong&gt;&lt;br&gt;
•   &lt;strong&gt;Q: Why use &lt;code&gt;page.evaluate()&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
    •   A: It executes JavaScript directly in the browser, allowing access to the application's runtime state or complex DOM elements for accurate data extraction, avoiding fragile visual parsing.&lt;br&gt;
•   &lt;strong&gt;Q: How do I handle asynchronous data loading?&lt;/strong&gt;&lt;br&gt;
    •   A: Use Playwright's &lt;code&gt;await page.waitFor...()&lt;/code&gt; methods or &lt;code&gt;waitForTimeout()&lt;/code&gt; (judiciously) to ensure data is loaded and rendered before extraction.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, e2e testing, dashboard, data validation, client-side, javascript, automation, web testing&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
&lt;strong&gt;Enhance your dev skills on the go!&lt;/strong&gt;&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261104" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261104&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261104&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261104&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How Do You Automate the Payment Request API in Selenium-Java Across Cross-Origin Iframes with User Activation?</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Tue, 03 Nov 2026 13:51:33 +0000</pubDate>
      <link>https://dev.to/styrow_dev/how-do-you-automate-the-payment-request-api-in-selenium-java-across-cross-origin-iframes-with-user-4o76</link>
      <guid>https://dev.to/styrow_dev/how-do-you-automate-the-payment-request-api-in-selenium-java-across-cross-origin-iframes-with-user-4o76</guid>
      <description>&lt;p&gt;🔥 Senior SDET Interview Scenario:&lt;br&gt;
Automating the browser-native Payment Request API across cross-origin iframes with &lt;em&gt;real&lt;/em&gt; user activation in Selenium-Java. Think you can handle it?&lt;/p&gt;

&lt;p&gt;📌 Problem Statement:&lt;br&gt;
The Payment Request API (PRA) requires secure browsing context and &lt;em&gt;transient user activation&lt;/em&gt;—a trusted user gesture. Synthetic clicks often fail. When the PRA handler is in a cross-origin iframe, origin boundaries and storage partitioning compound the complexity, making reliable end-to-end testing extremely challenging.&lt;/p&gt;

&lt;p&gt;💡 Solution &amp;amp; Code Walkthrough:&lt;br&gt;
Achieving trusted user activation isn't about arbitrary waits; it's about input fidelity. For cross-origin iframes, robust synchronization and proper context switching are crucial.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Trusted User Activation:&lt;/strong&gt; Use Selenium's &lt;code&gt;Actions&lt;/code&gt; class to simulate a more realistic, composite click gesture.&lt;br&gt;
❌ &lt;strong&gt;Antipattern:&lt;/strong&gt; Relying solely on &lt;code&gt;element.click()&lt;/code&gt; for sensitive UI components gated by user activation.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.By&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.WebDriver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.WebElement&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.interactions.Actions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.support.ui.WebDriverWait&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.support.ui.ExpectedConditions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.Duration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentAutomation&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;automatePaymentRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Assume driver navigates to the main page&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;

        &lt;span class="c1"&gt;// 1. Locate the iframe (could be by name, id, or WebElement)&lt;/span&gt;
        &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;paymentIframe&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;"paymentIframeId"&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;switchTo&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentIframe&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Wait for elements inside the iframe to be present&lt;/span&gt;
        &lt;span class="c1"&gt;//    Crucial for cross-origin iframes as content loads independently&lt;/span&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="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;payButton&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;elementToBeClickable&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;"payNowButton"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. Simulate trusted user activation with Actions class&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Actions&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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;moveToElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payButton&lt;/span&gt;&lt;span class="o"&gt;)&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;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// 4. Assert payment sheet appears (e.g., a known element)&lt;/span&gt;
        &lt;span class="c1"&gt;//    driver.findElement(By.cssSelector(".payment-sheet-modal")).isDisplayed();&lt;/span&gt;

        &lt;span class="c1"&gt;// 5. Interact with payment sheet (e.g., select method, confirm)&lt;/span&gt;
        &lt;span class="c1"&gt;//    This might involve more frame switching or pop-up handling.&lt;/span&gt;
        &lt;span class="c1"&gt;//    Crucially, verify no raw payment data is exposed in logs/assertions.&lt;/span&gt;

        &lt;span class="c1"&gt;// 6. Switch back to default content&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;switchTo&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;defaultContent&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;• &lt;strong&gt;Secure Context:&lt;/strong&gt; Ensure your test environment (browser, URL) is &lt;code&gt;https://&lt;/code&gt;.&lt;br&gt;
• &lt;strong&gt;Assertions:&lt;/strong&gt; Focus on visible UI state changes, final confirmation, and &lt;em&gt;absence&lt;/em&gt; of sensitive data leakage.&lt;/p&gt;

&lt;p&gt;🔑 Key Takeaways:&lt;br&gt;
• &lt;strong&gt;Input Fidelity:&lt;/strong&gt; &lt;code&gt;Actions&lt;/code&gt; class provides a more robust user activation than basic &lt;code&gt;.click()&lt;/code&gt;.&lt;br&gt;
• &lt;strong&gt;Cross-Origin Nuances:&lt;/strong&gt; Isolate iframe interactions, handle context switching (&lt;code&gt;switchTo().frame()&lt;/code&gt;, &lt;code&gt;defaultContent()&lt;/code&gt;), and employ explicit waits.&lt;br&gt;
• &lt;strong&gt;Lifecycle Awareness:&lt;/strong&gt; Observe deterministic signals (e.g., element visibility, network calls) rather than arbitrary delays.&lt;br&gt;
• &lt;strong&gt;Secure Verification:&lt;/strong&gt; Always assert that sensitive payment data isn't exposed during or after the transaction.&lt;/p&gt;

&lt;p&gt;❓ Quick Summary Q&amp;amp;A:&lt;br&gt;
Q: Why is Payment Request API automation challenging?&lt;br&gt;
A: Requires trusted user activation, secure context, and complex cross-origin iframe handling.&lt;br&gt;
Q: How to achieve trusted user activation in Selenium?&lt;br&gt;
A: Use the &lt;code&gt;Actions&lt;/code&gt; class for a more realistic click gesture.&lt;br&gt;
Q: What's key for cross-origin iframe automation?&lt;br&gt;
A: Proper &lt;code&gt;switchTo().frame()&lt;/code&gt;/&lt;code&gt;defaultContent()&lt;/code&gt;, explicit waits for iframe content, and respecting origin boundaries.&lt;/p&gt;

&lt;p&gt;TAGS: selenium, java, automation, payment-api, iframes, testing, sdet, webdriver&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
👉 Elevate your testing skills!&lt;br&gt;
Download our app for more advanced scenarios and solutions:&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261103" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261103&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261103&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261103&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How do you effectively manage and interact with new browser windows opened via `window.open()` in Playwright, especially</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Mon, 02 Nov 2026 15:06:27 +0000</pubDate>
      <link>https://dev.to/styrow_dev/how-do-you-effectively-manage-and-interact-with-new-browser-windows-opened-via-windowopen-in-2ohd</link>
      <guid>https://dev.to/styrow_dev/how-do-you-effectively-manage-and-interact-with-new-browser-windows-opened-via-windowopen-in-2ohd</guid>
      <description>&lt;p&gt;⚠️ Playwright Popup Panic: Can you tame a &lt;code&gt;window.open()&lt;/code&gt; beast?&lt;br&gt;
Ever struggled to automate interactions with those pesky new browser windows opened via &lt;code&gt;window.open()&lt;/code&gt; in Playwright? It's a common trap!&lt;/p&gt;



&lt;p&gt;📌 &lt;strong&gt;Problem Statement&lt;/strong&gt;&lt;br&gt;
Automating applications that use &lt;code&gt;window.open()&lt;/code&gt; to spawn new browser windows or tabs (popups) presents a unique challenge in Playwright.&lt;/p&gt;

&lt;p&gt;❌ Unlike creating a new page programmatically or handling simple dialogs, these popups require a specialized approach.&lt;br&gt;
• Without proper handling, your tests can fail to interact with, or even recognize, these dynamically created pages.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Solution &amp;amp; Code Walkthrough&lt;/strong&gt;&lt;br&gt;
The key is to leverage Playwright's &lt;code&gt;page.waitForEvent('popup')&lt;/code&gt; concurrently with the action that triggers the new window.&lt;/p&gt;

&lt;p&gt;✅ Use &lt;code&gt;Promise.all()&lt;/code&gt; to prevent race conditions, ensuring you capture the new &lt;code&gt;Page&lt;/code&gt; object as soon as it appears.&lt;br&gt;
• This listener returns the new &lt;code&gt;Page&lt;/code&gt; object, allowing you to interact with it just like any other Playwright page.&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;expect&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;manage window.open() popups&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="nx"&gt;page&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="c1"&gt;// Simulate a page that opens a popup&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;data:text/html,&amp;lt;button id="open"&amp;gt;Open Popup&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ✅ Concurrently wait for the popup event and click the trigger&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;popupPage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&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;waitForEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// 1. Listen for the new window&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;#open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;// 2. Trigger the window.open()&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Now interact with the popup page&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;popupPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForLoadState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Ensure content is loaded&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;popupPage&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;data:text/html,&amp;lt;h1&amp;gt;Popup Content&amp;lt;/h1&amp;gt;&amp;lt;input id="data"&amp;gt;&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;popupPage&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;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toHaveText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Popup Content&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;popupPage&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;#data&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;Playwright rocks!&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;popupPage&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;#data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toHaveValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Playwright rocks!&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;popupPage&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="c1"&gt;// Clean up: close the popup&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔑 &lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;br&gt;
• Always use &lt;code&gt;page.waitForEvent('popup')&lt;/code&gt; to capture new windows opened by &lt;code&gt;window.open()&lt;/code&gt;.&lt;br&gt;
• Combine it with &lt;code&gt;Promise.all()&lt;/code&gt; to avoid race conditions between trigger and event.&lt;br&gt;
• The captured popup is a standard Playwright &lt;code&gt;Page&lt;/code&gt; object, allowing full interaction.&lt;br&gt;
• Remember to close popups (&lt;code&gt;popupPage.close()&lt;/code&gt;) if they are no longer needed.&lt;/p&gt;

&lt;p&gt;❓ &lt;strong&gt;Quick Summary Q&amp;amp;A&lt;/strong&gt;&lt;br&gt;
Q: How do you detect a &lt;code&gt;window.open()&lt;/code&gt; popup in Playwright?&lt;br&gt;
A: Use &lt;code&gt;page.waitForEvent('popup')&lt;/code&gt;.&lt;br&gt;
Q: Why use &lt;code&gt;Promise.all()&lt;/code&gt; with popups?&lt;br&gt;
A: To avoid race conditions and ensure the event listener is active before the popup opens.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, automation, testing, javascript, typescript, web-automation&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Ready to master advanced Playwright scenarios? Download our app for more expert insights and code examples!&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261102" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261102&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261102&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261102&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How do you leverage Playwright's `request` context to efficiently manage test data or backend state during E2E test setu</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Sun, 01 Nov 2026 12:53:30 +0000</pubDate>
      <link>https://dev.to/styrow_dev/how-do-you-leverage-playwrights-request-context-to-efficiently-manage-test-data-or-backend-state-454i</link>
      <guid>https://dev.to/styrow_dev/how-do-you-leverage-playwrights-request-context-to-efficiently-manage-test-data-or-backend-state-454i</guid>
      <description>&lt;p&gt;🔥 Playwright Tests Crawling? The API Secret Senior Devs Use:&lt;br&gt;
Are your E2E tests spending precious minutes on UI-based setup? Learn how to unlock blazing-fast test execution and rock-solid reliability with Playwright's &lt;code&gt;request&lt;/code&gt; context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📌 Problem Statement&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;❌&lt;/code&gt; Relying solely on UI for complex backend state setup (e.g., user registration, data seeding, authentication) is notoriously slow and introduces significant flakiness into E2E test suites. This impacts developer velocity and CI/CD feedback loops.&lt;br&gt;
&lt;code&gt;•&lt;/code&gt; Such dependencies on browser interactions for pre-test conditions often lead to extended test runtimes and complicated maintenance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Solution &amp;amp; Code Walkthrough&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;•&lt;/code&gt; Playwright's &lt;code&gt;request&lt;/code&gt; context (available via the &lt;code&gt;request&lt;/code&gt; fixture) enables direct HTTP/HTTPS API calls, completely bypassing the browser UI for setup and teardown phases.&lt;br&gt;
&lt;code&gt;✅&lt;/code&gt; This powerful mechanism allows for rapid test data provisioning, token-based authentication, and state manipulation, dramatically accelerating E2E tests and boosting their stability.&lt;br&gt;
&lt;code&gt;•&lt;/code&gt; &lt;strong&gt;Key Use Cases:&lt;/strong&gt; Swift user registration, efficient database seeding, fast authentication, and clean state resets.&lt;/p&gt;

&lt;p&gt;To integrate API-driven setup, leverage Playwright's &lt;code&gt;test.extend&lt;/code&gt; to define custom fixtures:&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="c1"&gt;// fixtures/auth.ts&lt;/span&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="kd"&gt;as &lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;APIRequestContext&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="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;type&lt;/span&gt; &lt;span class="nx"&gt;AuthFixtures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;authenticatedAPI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APIRequestContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthFixtures&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;authenticatedAPI&lt;/span&gt;&lt;span class="p"&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;request&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;use&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="c1"&gt;// Setup: Perform API login to get an auth token&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loginRes&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&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://api.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="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;user&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password123&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loginRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Ensure login was successful&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;}&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;loginRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&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="c1"&gt;// Apply token for subsequent API calls&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Provide the authenticated API context&lt;/span&gt;
    &lt;span class="c1"&gt;// Teardown (optional): Delete the user or invalidate the token via API&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="c1"&gt;// Run once per test&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// tests/secure.spec.ts&lt;/span&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./fixtures/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Import custom test&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;should access secure API endpoint&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="nx"&gt;authenticatedAPI&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;secureDataRes&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;authenticatedAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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/secure-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&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;secureDataRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Verify API call success&lt;/span&gt;
  &lt;span class="nf"&gt;expect&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;secureDataRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toHaveProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Check response structure&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🔑 Key Takeaways&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;✅&lt;/code&gt; &lt;strong&gt;Speed:&lt;/strong&gt; Drastically reduces E2E test execution time by using efficient API calls instead of slow UI interactions for preconditions.&lt;br&gt;
&lt;code&gt;✅&lt;/code&gt; &lt;strong&gt;Reliability:&lt;/strong&gt; Boosts test stability, as API calls are generally more consistent and less prone to flakiness than complex UI flows.&lt;br&gt;
&lt;code&gt;•&lt;/code&gt; &lt;strong&gt;Reusability:&lt;/strong&gt; Custom fixtures with &lt;code&gt;test.extend&lt;/code&gt; provide a clean, maintainable pattern for defining reusable API-driven test prerequisites.&lt;br&gt;
&lt;code&gt;•&lt;/code&gt; Ideal for managing complex authentication, seeding specific test data, and ensuring a pristine environment for each test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;❓ Quick Summary Q&amp;amp;A&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Q:&lt;/code&gt; Why use Playwright's &lt;code&gt;request&lt;/code&gt; context in E2E tests?&lt;br&gt;
&lt;code&gt;A:&lt;/code&gt; To bypass UI for faster, more reliable backend state setup/teardown via direct HTTP/HTTPS API calls.&lt;br&gt;
&lt;code&gt;Q:&lt;/code&gt; How can you achieve an authenticated session without UI login?&lt;br&gt;
&lt;code&gt;A:&lt;/code&gt; Define a custom &lt;code&gt;test.extend&lt;/code&gt; fixture that uses &lt;code&gt;request&lt;/code&gt; to perform an API login and then injects the resulting authentication token into the API context for subsequent requests.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, e2e testing, api testing, test automation, typescript, javascript, software engineering, qa, devops&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Download the #1 App for Developers!&lt;br&gt;
App Store: ────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261101" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261101&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261101&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261101&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Play Store: ────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261101" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261101&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261101&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261101&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How does Selenium-Java handle screen orientation changes when testing on mobile devices?</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Sat, 31 Oct 2026 11:53:58 +0000</pubDate>
      <link>https://dev.to/styrow_dev/how-does-selenium-java-handle-screen-orientation-changes-when-testing-on-mobile-devices-5fo9</link>
      <guid>https://dev.to/styrow_dev/how-does-selenium-java-handle-screen-orientation-changes-when-testing-on-mobile-devices-5fo9</guid>
      <description>&lt;p&gt;⚠️ Mobile Automation Fail: Are your Selenium tests ready for a screen rotation?&lt;br&gt;
Ever wonder why your mobile UI tests break when the device flips from portrait to landscape? It's a common pitfall!&lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;Problem Statement&lt;/strong&gt;&lt;br&gt;
Mobile device screen orientation changes dynamically (portrait/landscape). UI elements, layouts, and validations heavily depend on this state. Unhandled shifts lead to flaky tests in Selenium or Appium.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Challenges:&lt;/strong&gt;&lt;br&gt;
•  Locators or element positions become invalid (e.g., a "Next" button moves).&lt;br&gt;
•  Waits misinterpret new layouts, causing &lt;code&gt;StaleElementReferenceException&lt;/code&gt;.&lt;br&gt;
•  Hard-coded portrait expectations break tests on landscape devices.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Solution &amp;amp; Code Walkthrough&lt;/strong&gt;&lt;br&gt;
Leverage &lt;code&gt;MobileDriver&lt;/code&gt; to programmatically control and query screen orientation. Combine this with robust &lt;code&gt;WebDriverWait&lt;/code&gt; conditions to ensure elements are stable post-rotation.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.appium.java_client.MobileDriver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.appium.java_client.MobileElement&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.appium.java_client.android.orientation.ScreenOrientation&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Or io.appium.java_client.ios.orientation.ScreenOrientation&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.Duration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.By&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Essential for element location&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.support.ui.WebDriverWait&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.openqa.selenium.support.ui.ExpectedConditions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ScreenOrientationHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;MobileDriver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MobileElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&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="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ScreenOrientationHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MobileDriver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MobileElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;driver&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&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="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/** Locks the device into a specific orientation (e.g., PORTRAIT, LANDSCAPE). */&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setOrientation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ScreenOrientation&lt;/span&gt; &lt;span class="n"&gt;orientation&lt;/span&gt;&lt;span class="o"&gt;)&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;rotate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orientation&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/** Queries the current screen orientation. */&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ScreenOrientation&lt;/span&gt; &lt;span class="nf"&gt;getCurrentOrientation&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;getOrientation&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/** Waits until a set of elements is visible after an orientation change. */&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;waitUntilElementsAreVisible&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="n"&gt;locators&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;locators&lt;/span&gt;&lt;span class="o"&gt;)&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="n"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔑 &lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;br&gt;
•  &lt;code&gt;MobileDriver.rotate(orientation)&lt;/code&gt; dynamically changes screen orientation.&lt;br&gt;
•  &lt;code&gt;MobileDriver.getOrientation()&lt;/code&gt; fetches the current device state.&lt;br&gt;
•  &lt;code&gt;WebDriverWait&lt;/code&gt; with &lt;code&gt;ExpectedConditions&lt;/code&gt; is critical for element stability after rotation.&lt;br&gt;
•  Always test UI responsiveness in both portrait and landscape modes for complete coverage.&lt;/p&gt;

&lt;p&gt;❓ &lt;strong&gt;Quick Summary Q&amp;amp;A&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Q: Why do mobile tests often fail with orientation changes?&lt;/strong&gt;&lt;br&gt;
A: UI elements shift, invalidating locators and causing waits to misfire.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How can I change screen orientation in Selenium-Java?&lt;/strong&gt;&lt;br&gt;
A: Use &lt;code&gt;driver.rotate(ScreenOrientation.LANDSCAPE)&lt;/code&gt; or &lt;code&gt;ScreenOrientation.PORTRAIT)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What's the best practice to handle elements after rotation?&lt;/strong&gt;&lt;br&gt;
A: Implement &lt;code&gt;WebDriverWait&lt;/code&gt; with &lt;code&gt;ExpectedConditions.visibilityOfElementLocated&lt;/code&gt; to ensure elements are rendered and stable.&lt;/p&gt;

&lt;p&gt;TAGS: selenium, java, appium, mobile testing, automation, screen orientation, qa, sdet&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
🚀 Elevate your testing skills! Download our app today:&lt;br&gt;
App Store: ────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261031" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261031&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261031&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261031&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Play Store: ────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261031" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261031&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261031&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261031&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Designing a Robust Automation Strategy for Real-time Streaming Data Dashboards</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Fri, 30 Oct 2026 12:23:46 +0000</pubDate>
      <link>https://dev.to/styrow_dev/designing-a-robust-automation-strategy-for-real-time-streaming-data-dashboards-4jga</link>
      <guid>https://dev.to/styrow_dev/designing-a-robust-automation-strategy-for-real-time-streaming-data-dashboards-4jga</guid>
      <description>&lt;p&gt;📈 Real-time Dashboards: Your Selenium Tests Are Breaking. Here's Why.&lt;br&gt;
Verifying live stock tickers with Selenium-Java can feel like catching smoke. Data changes every second, UI elements flicker, and flakiness is a constant threat. Traditional waits and single-snapshot assertions crumble under the pressure of dynamic, streaming data.&lt;/p&gt;

&lt;p&gt;📌 Problem Statement&lt;br&gt;
Real-time financial dashboards, updating every 1-2 seconds, pose severe automation challenges:&lt;br&gt;
❌  &lt;strong&gt;Data Correctness&lt;/strong&gt;: How do you reliably verify constantly changing prices against an authoritative source?&lt;br&gt;
❌  &lt;strong&gt;Dynamic UI&lt;/strong&gt;: &lt;code&gt;StaleElementReferenceException&lt;/code&gt; and excessive fixed waits lead to flaky tests.&lt;br&gt;
❌  &lt;strong&gt;Update Fidelity&lt;/strong&gt;: Detecting data lag or UI discrepancies requires capturing and comparing multiple updates, not just one.&lt;/p&gt;

&lt;p&gt;💡 Solution &amp;amp; Code Walkthrough&lt;br&gt;
A robust strategy integrates an independent "ground truth" data source with reactive UI observation and temporal verification.&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;Architectural Overview:&lt;/strong&gt;&lt;br&gt;
    1.  &lt;strong&gt;Ground Truth Service (GTS):&lt;/strong&gt; An independent module (e.g., mock API client, WebSocket listener) fetching the &lt;em&gt;expected&lt;/em&gt; data.&lt;br&gt;
    2.  &lt;strong&gt;Reactive UI Observer:&lt;/strong&gt; Selenium interacts with the UI, but instead of blocking waits, it continuously polls for values, handling element staleness.&lt;br&gt;
    3.  &lt;strong&gt;Temporal Comparator:&lt;/strong&gt; Collects UI values and GTS values over a period for aggregate comparison, detecting lags or inconsistencies.&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;1. Ground Truth Data Integration:&lt;/strong&gt;&lt;br&gt;
    ✅  Fetch expected data &lt;em&gt;independently&lt;/em&gt; from the UI via a mock or actual API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```java
public interface GroundTruthService {
    StockData getLatestStockData(String symbol);
}
// StockData class would hold price, trend, timestamp
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;•   &lt;strong&gt;2. Dynamic UI Handling with Reactive Polling:&lt;/strong&gt;&lt;br&gt;
    ✅  Use &lt;code&gt;FluentWait&lt;/code&gt; with custom conditions to repeatedly fetch element text, gracefully handling &lt;code&gt;StaleElementReferenceException&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```java
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.FluentWait;
import java.time.Duration;

public String getDynamicElementText(WebDriver driver, By locator) {
    return new FluentWait&amp;lt;&amp;gt;(driver)
        .withTimeout(Duration.ofSeconds(10)) // Max wait
        .pollingEvery(Duration.ofMillis(500)) // Poll freq
        .ignoring(StaleElementReferenceException.class)
        .until(d -&amp;gt; {
            WebElement element = d.findElement(locator);
            return element.isDisplayed() ? element.getText() : null;
        });
}
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;•   &lt;strong&gt;3. Update Fidelity &amp;amp; Lag Detection (Temporal Verification):&lt;/strong&gt;&lt;br&gt;
    ✅  Capture UI and GTS data snapshots over a short duration (e.g., 5 seconds) and compare the collected sets for consistency and lag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```java
import java.util.*;

public List&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; collectTimeSeriesData(
    WebDriver driver, By uiLocator, GroundTruthService gts, String symbol, int durationSec) {

    List&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; series = new ArrayList&amp;lt;&amp;gt;();
    long startTime = System.currentTimeMillis();

    while (System.currentTimeMillis() - startTime &amp;lt; durationSec * 1000) {
        String uiValue = getDynamicElementText(driver, uiLocator);
        StockData gtData = gts.getLatestStockData(symbol);

        Map&amp;lt;String, Object&amp;gt; snapshot = new HashMap&amp;lt;&amp;gt;();
        snapshot.put("timestamp", System.currentTimeMillis());
        snapshot.put("uiValue", uiValue);
        snapshot.put("gtPrice", gtData.getPrice());
        // Add comparison logic: e.g., Math.abs(uiValue - gtPrice) &amp;lt; tolerance
        series.add(snapshot);
        try { Thread.sleep(1000); } catch (InterruptedException e) {} // Adjust polling
    }
    return series;
}
// Assertions would then analyze 'series' for discrepancies/lags.
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔑 Key Takeaways&lt;br&gt;
•   &lt;strong&gt;Ground Truth is Paramount:&lt;/strong&gt; Always compare UI against an independent, authoritative data source.&lt;br&gt;
•   &lt;strong&gt;Observe, Don't Just Wait:&lt;/strong&gt; Use &lt;code&gt;FluentWait&lt;/code&gt; with custom conditions for dynamic elements to avoid flakiness.&lt;br&gt;
•   &lt;strong&gt;Temporal Validation:&lt;/strong&gt; Collect UI and ground truth data over time to detect lags and subtle discrepancies.&lt;br&gt;
•   &lt;strong&gt;Tolerance for Volatility:&lt;/strong&gt; Implement reasonable error margins for comparisons in highly dynamic UIs.&lt;/p&gt;

&lt;p&gt;❓ Quick Summary Q&amp;amp;A&lt;br&gt;
&lt;strong&gt;Q: How to handle dynamic UI elements?&lt;/strong&gt;&lt;br&gt;
A: Use &lt;code&gt;FluentWait&lt;/code&gt; with &lt;code&gt;ignoring(StaleElementReferenceException.class)&lt;/code&gt; and a custom condition that re-finds and fetches text.&lt;br&gt;
&lt;strong&gt;Q: How to verify data correctness?&lt;/strong&gt;&lt;br&gt;
A: Integrate with an independent "ground truth" data service (API/WebSocket) and compare UI values to its output.&lt;br&gt;
&lt;strong&gt;Q: How to detect UI update lag?&lt;/strong&gt;&lt;br&gt;
A: Collect time-series data from both the UI and the ground truth service over a period and analyze their timestamps and values for consistency.&lt;/p&gt;

&lt;p&gt;TAGS: selenium-java, real-time testing, automation strategy, streaming data, financial tech&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Get more expert insights and advanced testing techniques!&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261030" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261030&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261030&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261030&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How do you design an E2E test strategy for data-driven validation of complex, interactive charts in Playwright?</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Thu, 29 Oct 2026 12:32:02 +0000</pubDate>
      <link>https://dev.to/styrow_dev/how-do-you-design-an-e2e-test-strategy-for-data-driven-validation-of-complex-interactive-charts-in-43j7</link>
      <guid>https://dev.to/styrow_dev/how-do-you-design-an-e2e-test-strategy-for-data-driven-validation-of-complex-interactive-charts-in-43j7</guid>
      <description>&lt;p&gt;🤯 Playwright Challenge: Complex Chart Validation&lt;br&gt;
How do you design an E2E test strategy for data-driven validation of complex, interactive charts?&lt;/p&gt;

&lt;p&gt;📌 Problem Statement&lt;br&gt;
Validating charts isn't just about visuals. Modern data visualizations (D3.js, Chart.js) require ensuring data accuracy, correct user interaction, and integrity across various states (zoom, filters). Simple visual regression isn't enough; we need to verify the &lt;em&gt;underlying data&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;💡 Solution &amp;amp; Code Walkthrough&lt;br&gt;
A robust Playwright strategy combines direct data extraction with interaction simulation. The most reliable method is accessing raw data within the browser's JavaScript context.&lt;/p&gt;

&lt;p&gt;• Many charting libraries expose data via DOM attributes or global JS objects.&lt;br&gt;
• Playwright's &lt;code&gt;page.evaluate()&lt;/code&gt; function is perfect for this.&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;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="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="c1"&gt;// Function to extract data from SVG bars with 'data-value' attributes&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getChartBarData&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="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Executes code directly in the browser context&lt;/span&gt;
    &lt;span class="k"&gt;return&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;evaluate&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;bars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#chart-container .bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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="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;chart displays correct data values&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="nx"&gt;page&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="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;/your-chart-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Navigate to your chart page&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getChartBarData&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="c1"&gt;// Extract rendered data&lt;/span&gt;
    &lt;span class="c1"&gt;// Define your expected data based on test scenarios&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="p"&gt;}];&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;actualData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Assert against expected data&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;code&gt;page.evaluate()&lt;/code&gt; allows executing custom JavaScript directly in the browser.&lt;br&gt;
✅ It can query DOM elements, extract attributes (e.g., &lt;code&gt;data-value&lt;/code&gt;), and access JavaScript variables.&lt;br&gt;
❌ Relying solely on screenshots or basic element text is prone to errors and misses data discrepancies.&lt;/p&gt;

&lt;p&gt;🔑 Key Takeaways&lt;br&gt;
• Always validate the underlying data, not just the visual appearance of charts.&lt;br&gt;
• &lt;code&gt;page.evaluate()&lt;/code&gt; is a powerful Playwright feature for accessing browser-side data.&lt;br&gt;
• Combine direct data extraction with precise interaction simulation for comprehensive E2E tests.&lt;/p&gt;

&lt;p&gt;❓ Quick Summary Q&amp;amp;A&lt;br&gt;
&lt;strong&gt;Q&lt;/strong&gt;: How do you validate complex chart data in Playwright?&lt;br&gt;
&lt;strong&gt;A&lt;/strong&gt;: Use &lt;code&gt;page.evaluate()&lt;/code&gt; to extract raw data directly from the browser's DOM or JavaScript context for assertive comparison.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, e2e testing, data visualization, chart testing, typescript, automation, qa&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261029" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261029&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261029&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261029&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Architecting Robust Playwright E2E Validation for Complex, Asynchronous WebSocket Data Streams</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Wed, 28 Oct 2026 12:22:31 +0000</pubDate>
      <link>https://dev.to/styrow_dev/architecting-robust-playwright-e2e-validation-for-complex-asynchronous-websocket-data-streams-4m9i</link>
      <guid>https://dev.to/styrow_dev/architecting-robust-playwright-e2e-validation-for-complex-asynchronous-websocket-data-streams-4m9i</guid>
      <description>&lt;p&gt;🚨 Senior Engineer Challenge: How do you reliably test complex, asynchronous WebSocket data streams in Playwright without flaky tests?&lt;/p&gt;

&lt;p&gt;📌 Problem Statement&lt;br&gt;
Modern web apps use WebSockets for real-time data, like trading platforms. Testing these streams end-to-end (E2E) in Playwright is challenging due to:&lt;br&gt;
❌ Asynchronous message arrival and potential out-of-order delivery.&lt;br&gt;
❌ High volume of diverse message types, requiring specific filtering.&lt;br&gt;
❌ Need for robust assertions on data structure, values, and event sequences within a timeframe.&lt;br&gt;
❌ Requirement for a reusable, maintainable solution to prevent flakiness.&lt;/p&gt;

&lt;p&gt;💡 Solution &amp;amp; Code Walkthrough&lt;br&gt;
A robust strategy involves intercepting, buffering, filtering, and flexible asynchronous assertions. We decouple data capture from assertion logic.&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;Conceptual Architecture:&lt;/strong&gt;&lt;br&gt;
    1.  &lt;strong&gt;Interceptor:&lt;/strong&gt; Captures all WebSocket frames.&lt;br&gt;
    2.  &lt;strong&gt;Buffer:&lt;/strong&gt; Stores captured JSON messages.&lt;br&gt;
    3.  &lt;strong&gt;Filter/Waiter:&lt;/strong&gt; Provides methods to retrieve specific messages based on criteria, with timeouts.&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;Playwright Implementation (TypeScript/JavaScript):&lt;/strong&gt;&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="c1"&gt;// websocketInterceptor.ts&lt;/span&gt;
&lt;span class="k"&gt;import&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="nx"&gt;WebSocket&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSocketInterceptor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;setup&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="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&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;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;websocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ws&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;framereceived&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&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;try&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Optionally ignore non-JSON frames&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="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Waits for a message matching a predicate within a timeout&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;waitForMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&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;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&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;foundMessageIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;predicate&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;foundMessageIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;foundMessageIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foundMessageIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Remove to prevent re-matching&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&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;waitForTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Polling interval&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Message not found within &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Clears all buffered messages&lt;/span&gt;
  &lt;span class="nf"&gt;clearMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test-scenario.spec.ts&lt;/span&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="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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebSocketInterceptor&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;./websocketInterceptor&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;validates real-time trade updates&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="nx"&gt;page&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;wsInterceptor&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;WebSocketInterceptor&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;wsInterceptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setup&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="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;YOUR_TRADING_APP_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Trigger an action that should emit a WebSocket message&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;button#buyStock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ✅ Assert on a specific trade confirmation message&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tradeConfirmation&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;wsInterceptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TRADE_CONFIRMATION&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SUCCESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AAPL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&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;tradeConfirmation&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&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;tradeConfirmation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;XYZ123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&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;tradeConfirmation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeGreaterThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;wsInterceptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearMessages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Clean up for subsequent steps/tests&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔑 Key Takeaways&lt;br&gt;
•   &lt;strong&gt;Decouple Capture &amp;amp; Assert:&lt;/strong&gt; Intercept messages into a buffer first, then assert.&lt;br&gt;
•   &lt;strong&gt;Flexible Waiting:&lt;/strong&gt; Use &lt;code&gt;waitForMessage&lt;/code&gt; with predicates and timeouts to handle asynchronous data and out-of-order arrival.&lt;br&gt;
•   &lt;strong&gt;Targeted Assertions:&lt;/strong&gt; Filter by message type, then validate structure and specific values.&lt;br&gt;
•   &lt;strong&gt;Reusability:&lt;/strong&gt; Encapsulate logic in a &lt;code&gt;WebSocketInterceptor&lt;/code&gt; class for maintainability.&lt;/p&gt;

&lt;p&gt;❓ Quick Summary Q&amp;amp;A&lt;br&gt;
&lt;strong&gt;Q: How do you handle out-of-order WebSocket messages in Playwright?&lt;/strong&gt;&lt;br&gt;
A: Buffer all messages, then use &lt;code&gt;waitForMessage&lt;/code&gt; with a predicate to search for the desired message regardless of its arrival order.&lt;br&gt;
&lt;strong&gt;Q: What is the core Playwright API for WebSocket interception?&lt;/strong&gt;&lt;br&gt;
A: &lt;code&gt;page.on('websocket', ws =&amp;gt; ws.on('framereceived', event =&amp;gt; { /* ... */ }))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, websocket, e2e testing, automation, real-time data, typescript&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Download our app for more advanced testing strategies!&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261028" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261028&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261028&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261028&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How would you inject custom client-side logic or dynamic data into a Playwright test to influence browser behavior or te</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Tue, 27 Oct 2026 11:48:53 +0000</pubDate>
      <link>https://dev.to/styrow_dev/how-would-you-inject-custom-client-side-logic-or-dynamic-data-into-a-playwright-test-to-influence-5cmh</link>
      <guid>https://dev.to/styrow_dev/how-would-you-inject-custom-client-side-logic-or-dynamic-data-into-a-playwright-test-to-influence-5cmh</guid>
      <description>&lt;p&gt;🔥 Playwright Pro Tip: How do you inject custom client-side logic or dynamic data &lt;em&gt;directly&lt;/em&gt; into your browser context? Essential for testing complex states inaccessible via standard UI.&lt;/p&gt;

&lt;p&gt;📌 Problem Statement&lt;br&gt;
When direct UI or network mocking falls short, inject client-side logic to:&lt;br&gt;
•  Invoke internal JavaScript functions.&lt;br&gt;
•  Seed &lt;code&gt;localStorage&lt;/code&gt;, &lt;code&gt;sessionStorage&lt;/code&gt;, or global variables.&lt;br&gt;
•  Mock browser APIs (e.g., &lt;code&gt;Date.now()&lt;/code&gt;) for predictable results.&lt;br&gt;
•  Trigger events hard to simulate via Playwright's high-level APIs.&lt;/p&gt;

&lt;p&gt;💡 Solution &amp;amp; Code Walkthrough&lt;br&gt;
Playwright bridges Node.js with client-side JS. &lt;code&gt;page.exposeFunction()&lt;/code&gt; lets you expose a Node.js function to the browser's &lt;code&gt;window&lt;/code&gt; object. Client-side code calls it; Playwright executes your Node.js logic, returning the result.&lt;/p&gt;

&lt;p&gt;✅ &lt;code&gt;page.exposeFunction()&lt;/code&gt; for Dynamic Data &amp;amp; Logic:&lt;br&gt;
Ideal for dynamic test data or simulating backend calls from your Node.js script directly to the client-side.&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="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;injects and calls exposed client-side function&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="nx"&gt;page&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="c1"&gt;// 1. Expose Node.js fn 'getClientConfig' to browser's window&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;exposeFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getClientConfig&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flag&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="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testUser123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// Simulate dynamic config&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Navigate (or use empty page)&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;data:text/html,&amp;lt;script&amp;gt;window.config = {};&amp;lt;/script&amp;gt;&amp;lt;h1&amp;gt;App&amp;lt;/h1&amp;gt;&amp;lt;p id="output"&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Client-side JS calls exposed fn&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;evaluate&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getClientConfig&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Call exposed Node.js function&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Config: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSideConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Store globally&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Assert client-side state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputText&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;textContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&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;outputText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;env":"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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flag":true&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;clientSideConfig&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;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSideConfig&lt;/span&gt;&lt;span class="p"&gt;);&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;clientSideConfig&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flag&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="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testUser123&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔑 Key Takeaways&lt;br&gt;
•  &lt;code&gt;exposeFunction()&lt;/code&gt; bridges Node.js and browser JS for two-way communication.&lt;br&gt;
•  Great for dynamic data, mocking API responses, or simulating backend.&lt;br&gt;
•  &lt;code&gt;addInitScript()&lt;/code&gt; injects scripts &lt;em&gt;before&lt;/em&gt; page loads (e.g., for global mocks, &lt;code&gt;localStorage&lt;/code&gt;).&lt;br&gt;
❌ Use sparingly; prioritize standard Playwright APIs first.&lt;/p&gt;

&lt;p&gt;❓ Quick Summary Q&amp;amp;A&lt;br&gt;
Q: Why inject client-side logic?&lt;br&gt;
A: Test internal functions, seed states, or mock browser APIs.&lt;/p&gt;

&lt;p&gt;Q: What does &lt;code&gt;exposeFunction()&lt;/code&gt; do?&lt;br&gt;
A: Exposes a Node.js function to the browser's &lt;code&gt;window&lt;/code&gt; object for two-way comms.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, javascript, e2e testing, automation, web development, client-side, dynamic data&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
🚀 Supercharge your skills! Download our app today for more expert tips &amp;amp; tricks.&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261027" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261027&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261027&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261027&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Integrating Mutation Testing (PITest) to Detect Insufficient Selenium Test Assertions</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Mon, 26 Oct 2026 12:30:25 +0000</pubDate>
      <link>https://dev.to/styrow_dev/integrating-mutation-testing-pitest-to-detect-insufficient-selenium-test-assertions-4b0m</link>
      <guid>https://dev.to/styrow_dev/integrating-mutation-testing-pitest-to-detect-insufficient-selenium-test-assertions-4b0m</guid>
      <description>&lt;p&gt;💀 Your 100% Selenium Code Coverage is Lying to You: How do you &lt;em&gt;prove&lt;/em&gt; your tests validate outcomes, not just execute lines?&lt;/p&gt;




&lt;p&gt;📌 &lt;strong&gt;Problem Statement&lt;/strong&gt;&lt;br&gt;
High code coverage in Selenium often creates a false sense of security. Tests can execute every line of a Page Object or utility but fail to verify the &lt;em&gt;actual outcome&lt;/em&gt; (e.g., data is correct, element state changed). This leads to silent failures.&lt;/p&gt;

&lt;p&gt;• Mutation Testing (PITest) validates your assertion density and logic correctness, not just line execution.&lt;/p&gt;

&lt;p&gt;Consider this common &lt;code&gt;WaitUtils&lt;/code&gt; class:&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WaitUtils&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="nf"&gt;waitForVisibility&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebDriver&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;By&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;timeoutSeconds&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&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="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&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="n"&gt;timeoutSeconds&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&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="n"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isElementPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebDriver&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;By&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&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="n"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NoSuchElementException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical test achieving 100% coverage might look like this:&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="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCoverage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Mockito setup...&lt;/span&gt;
    &lt;span class="nc"&gt;WaitUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;waitForVisibility&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDriver&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;"foo"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;WaitUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isElementPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDriver&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;"bar"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ No assertions on return values or interaction!&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ &lt;strong&gt;PITest Result:&lt;/strong&gt; &lt;strong&gt;SURVIVED&lt;/strong&gt; mutants!&lt;br&gt;
• Return Value Mutant: &lt;code&gt;return wait.until(...);&lt;/code&gt; $\rightarrow$ &lt;code&gt;return null;&lt;/code&gt;. Test passed as &lt;code&gt;null&lt;/code&gt; was ignored.&lt;br&gt;
• Exception Swallow Mutant: &lt;code&gt;catch (NoSuchElementException e) { return false; }&lt;/code&gt; $\rightarrow$ &lt;code&gt;catch (Exception e) { return false; }&lt;/code&gt;. Test still passed, swallowing broader exceptions.&lt;/p&gt;



&lt;p&gt;💡 &lt;strong&gt;Solution &amp;amp; Code Walkthrough&lt;/strong&gt;&lt;br&gt;
To kill these mutants, we need robust assertions and interaction verification. This ensures your test logic actively fails when the underlying code's behavior changes, even subtly.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;junit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jupiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mockito&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Mockito&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testRobustness&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Mock setup: WebDriver, WebDriverWait, WebElement&lt;/span&gt;
    &lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;mockDriver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebDriver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;WebDriverWait&lt;/span&gt; &lt;span class="n"&gt;mockWait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebDriverWait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;mockElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebElement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Stub mock interactions&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockWait&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;any&lt;/span&gt;&lt;span class="o"&gt;())).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockElement&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDriver&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="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;())).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockElement&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Call methods under test&lt;/span&gt;
    &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WaitUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;waitForVisibility&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDriver&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;"foo"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;present&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WaitUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isElementPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDriver&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;"bar"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ Assertions kill the mutants&lt;/span&gt;
    &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Wait should return an element."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;present&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Element reported present."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDriver&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;"bar"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Verify `isElementPresent` interacted&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these assertions, PITest will report "KILLED" mutants, validating the test's effectiveness.&lt;/p&gt;




&lt;p&gt;🔑 &lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;br&gt;
• Code coverage measures &lt;em&gt;execution&lt;/em&gt;, not &lt;em&gt;validation&lt;/em&gt;.&lt;br&gt;
• Mutation testing exposes weak or missing assertions in your test suite.&lt;br&gt;
• Always assert return values and verify critical method interactions.&lt;/p&gt;




&lt;p&gt;❓ &lt;strong&gt;Quick Summary Q&amp;amp;A&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Q: Why is 100% Selenium code coverage misleading?&lt;/strong&gt;&lt;br&gt;
A: It doesn't guarantee your tests assert actual outcomes or react to subtle logic changes, only that code lines run.&lt;br&gt;
&lt;strong&gt;Q: How does mutation testing help improve Selenium tests?&lt;/strong&gt;&lt;br&gt;
A: It deliberately changes your code, forcing tests to fail if they lack sufficient assertions to detect the change.&lt;/p&gt;




&lt;p&gt;TAGS: selenium, java, mutation testing, pitest, test automation, qa, sdet&lt;br&gt;
────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261026" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261026&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261026&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Designing a Playwright E2E Strategy for Micro-frontend Architectures</title>
      <dc:creator>Styrow.dev</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:58:32 +0000</pubDate>
      <link>https://dev.to/styrow_dev/designing-a-playwright-e2e-strategy-for-micro-frontend-architectures-417</link>
      <guid>https://dev.to/styrow_dev/designing-a-playwright-e2e-strategy-for-micro-frontend-architectures-417</guid>
      <description>&lt;p&gt;🤯 Micro-frontend E2E Nightmares? Stop. Your Playwright strategy for distributed apps needs this:&lt;br&gt;
You're designing a robust Playwright E2E strategy for a large-scale micro-frontend (MF) architecture. Independent teams, async deployments, shared shell – how do you ensure stable, scalable testing?&lt;/p&gt;

&lt;p&gt;📌 Problem Statement&lt;br&gt;
Micro-frontend architectures introduce unique E2E testing challenges:&lt;br&gt;
•   &lt;strong&gt;Inconsistent Environments:&lt;/strong&gt; Ensuring all MFs and backends are compatible.&lt;br&gt;
•   &lt;strong&gt;Distributed Data:&lt;/strong&gt; Managing test data across multiple, independent services.&lt;br&gt;
•   &lt;strong&gt;Ownership Confusion:&lt;/strong&gt; Preventing test duplication and defining clear responsibilities.&lt;br&gt;
•   &lt;strong&gt;Flaky Tests:&lt;/strong&gt; Dealing with asynchronous MF deployments and system instability.&lt;br&gt;
•   &lt;strong&gt;Complex Debugging:&lt;/strong&gt; Pinpointing the exact failure source in a distributed system.&lt;/p&gt;

&lt;p&gt;💡 Solution &amp;amp; Code Walkthrough&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;Test Environment &amp;amp; Orchestration&lt;/strong&gt;&lt;br&gt;
    ✅ Use Docker Compose/Kubernetes for consistent, versioned MF stacks.&lt;br&gt;
    ✅ Playwright's &lt;code&gt;webServer&lt;/code&gt; simplifies setup for local development and CI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```typescript
// playwright.config.ts (conceptual)
import { defineConfig } from '@playwright/test';
export default defineConfig({
  use: { baseURL: process.env.E2E_BASE_URL || 'http://localhost:3000' },
  webServer: {
    command: 'docker-compose up --build -d', // Orchestrates MFs
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;•   &lt;strong&gt;Test Data Management&lt;/strong&gt;&lt;br&gt;
    ✅ Prioritize API-first data setup/teardown using &lt;code&gt;request&lt;/code&gt; fixture.&lt;br&gt;
    ❌ Avoid slow, brittle UI-driven data setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```typescript
// Example: API-driven setup
import { test } from '@playwright/test';
test.beforeEach(async ({ request }) =&amp;gt; {
  await request.post('/api/users/create', { data: { email: 'test@example.com' } });
});
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;•   &lt;strong&gt;Test Ownership &amp;amp; Collaboration&lt;/strong&gt;&lt;br&gt;
    ✅ Monorepo &lt;code&gt;e2e-tests/&lt;/code&gt; with clear MF module separation.&lt;br&gt;
    ✅ Assign ownership to respective MF teams.&lt;br&gt;
    ✅ Use Playwright tags (&lt;code&gt;@checkout&lt;/code&gt;) for focused runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```typescript
// example.spec.ts
test.describe('Checkout Flow @checkout', () =&amp;gt; { /* ... tests */ });
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;•   &lt;strong&gt;Resilience &amp;amp; Stability&lt;/strong&gt;&lt;br&gt;
    ✅ Employ service virtualization (mocks) for external dependencies.&lt;br&gt;
    ✅ Configure Playwright &lt;code&gt;retry&lt;/code&gt; for transient failures.&lt;br&gt;
    ✅ Use robust, &lt;code&gt;data-test-id&lt;/code&gt; locators.&lt;br&gt;
    ❌ Avoid flaky CSS class selectors.&lt;/p&gt;

&lt;p&gt;•   &lt;strong&gt;Reporting &amp;amp; Debugging&lt;/strong&gt;&lt;br&gt;
    ✅ Integrate detailed reporters (e.g., Allure Report).&lt;br&gt;
    ✅ Capture screenshots, videos, network logs on failure.&lt;br&gt;
    ✅ Custom reporting: Link failures to specific MF versions/teams.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```typescript
// playwright.config.ts (reporting)
import { defineConfig } from '@playwright/test';
export default defineConfig({
  reporter: [['list'], ['html', { open: 'never' }], ['allure-playwright']],
});
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔑 Key Takeaways&lt;br&gt;
•   &lt;strong&gt;Orchestrate Environments:&lt;/strong&gt; Ensure consistent MF/backend stacks.&lt;br&gt;
•   &lt;strong&gt;API-First Data:&lt;/strong&gt; Fast, reliable test data management.&lt;br&gt;
•   &lt;strong&gt;Shared Ownership:&lt;/strong&gt; Clear responsibilities within a shared test codebase.&lt;br&gt;
•   &lt;strong&gt;Build for Resilience:&lt;/strong&gt; Mocks, retries, and stable locators.&lt;br&gt;
•   &lt;strong&gt;Actionable Reports:&lt;/strong&gt; Pinpoint failures quickly in distributed systems.&lt;/p&gt;

&lt;p&gt;❓ Quick Summary Q&amp;amp;A&lt;br&gt;
Q: What's the biggest challenge with MF E2E testing?&lt;br&gt;
A: Maintaining environment consistency and managing distributed test data.&lt;/p&gt;

&lt;p&gt;TAGS: playwright, e2e testing, micro-frontend, automation, software testing, architecture&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
Download our App for exclusive dev content &amp;amp; tips!&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

&lt;p&gt;📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&amp;amp;𝐀𝐬&lt;br&gt;
Practice real-world interview scenarios offline on the free QA Automation &amp;amp; SDET Prep app:&lt;/p&gt;

&lt;p&gt;🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261025" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&amp;amp;referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261025&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):&lt;br&gt;
&lt;a href="https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261025&amp;amp;mt=8" rel="noopener noreferrer"&gt;https://apps.apple.com/app/id6786760948?pt=128640464&amp;amp;ct=devto_selenium_20261025&amp;amp;mt=8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;────────────────────────────────────────&lt;br&gt;
────────────────────────────────────────&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
