<?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: iolaire mcfadden</title>
    <description>The latest articles on DEV Community by iolaire mcfadden (@iolaire).</description>
    <link>https://dev.to/iolaire</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3484698%2Fd42648c5-23b1-4ed5-850d-6cd2e95af244.jpeg</url>
      <title>DEV Community: iolaire mcfadden</title>
      <link>https://dev.to/iolaire</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iolaire"/>
    <language>en</language>
    <item>
      <title>Fixing JavaScript console errors with Kiro and the Playwright MCP Server</title>
      <dc:creator>iolaire mcfadden</dc:creator>
      <pubDate>Sun, 07 Sep 2025 11:38:34 +0000</pubDate>
      <link>https://dev.to/kirodotdev/fixing-javascript-console-errors-with-kiro-and-the-playwright-mcp-server-397k</link>
      <guid>https://dev.to/kirodotdev/fixing-javascript-console-errors-with-kiro-and-the-playwright-mcp-server-397k</guid>
      <description>&lt;p&gt;In 2022, I started the move to Mastodon on the Activity Pub platform.  As I started in the community, people would advocate for including accessibility on the platform. In a good way, it was drummed into my head that every image posted should have ALT text added to the images to improve accessibility, especially for folks using screen readers. That’s something I'm happy to support, especially as my own eyes move to the reading glasses stage.  I personally take issue with photographs of page-size documents where it’s very difficult to read the text zooming around an iPhone window.&lt;/p&gt;

&lt;p&gt;I'm now most active on PixelFed at &lt;a href="https://pixey.org/@iolaire" rel="noopener noreferrer"&gt;https://pixey.org/@iolaire&lt;/a&gt;.  I enjoy posting photos and scrolling through everyone else's photos.  However, I often am lazy or don't want to type the alt text on the phone. Luckily, &lt;a href="http://fuzzies.wtf/@altbot" rel="noopener noreferrer"&gt;Altbot&lt;/a&gt; would reply to my post with AI-generated captions.  However, at some point, they implemented GDPR approval, and it no longer worked with PixelFed.&lt;/p&gt;

&lt;p&gt;So this year, I started on a small project to backfill missing alt text on my &lt;a href="https://pixey.org/@iolaire" rel="noopener noreferrer"&gt;PixelFed account&lt;/a&gt;. I wrote a nice small Flask script to generate image descriptions using llava:7b running on the Ollama server locally.  When I say wrote, I started out with AI prompts in the various AI chat programs and then moved to using Amazon Q to polish it up.&lt;/p&gt;

&lt;p&gt;However, on July 14th, &lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;Kiro&lt;/a&gt; from Amazon dropped providing a framework to do spec-driven development.  As a getting stuff done person I had to try Kiro to practice a more organized and professional development style, and my 2,500-line Python script started growing quickly, its now over 200k lines:&lt;br&gt;
 √ Implement multi-user processing support&lt;br&gt;
 √ Enhance error handling and recovery&lt;br&gt;
 √ Optimize image processing&lt;br&gt;
 √ Optimize Ollama integration with llava:7b model&lt;br&gt;
 √ Improve database management&lt;br&gt;
 √ Enhance web interface&lt;br&gt;
 √ Improve ActivityPub integration&lt;br&gt;
 √ Implement system monitoring and management&lt;br&gt;
 √ Add comprehensive testing&lt;br&gt;
 √ Implement Multi-Platform ActivityPub Support&lt;br&gt;
 ... and the list goes on&lt;/p&gt;

&lt;p&gt;At some point, my specs included &lt;code&gt;csrf-security-audit&lt;/code&gt; (don't add this mid-development, do it near the end), and I began frequent debugging using the JavaScript console. I've been learning a lot about CSRF tokens.  &lt;/p&gt;

&lt;p&gt;Pasting over JavaScript console errors into the chat for debugging became quite cumbersome.  The Python tests Kiro wrote for me didn't actually catch frontend errors like CSRF token missmatches.  So I went down the productive path of asking Kiro to write &lt;a href="https://playwright.dev" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt; tests.&lt;/p&gt;

&lt;p&gt;You can start to make progress on those CSRF token errors with commands like &lt;code&gt;test the admin dashboard with playwright, use the admin user admin/abc134, look for JavaScript console errors, and resolve the issues&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Sometimes, to test redirects on pages, it’s great to let Kiro use the Playwright MCP server and step through the process.&lt;/p&gt;

&lt;p&gt;Installing the MCP server is fairly simple once it’s on your system.  In my case on a Mac Mini M4, it’s:&lt;br&gt;
&lt;code&gt;{&lt;br&gt;
  "mcpServers": {&lt;br&gt;
    "playwright": {&lt;br&gt;
      "command": "npx",&lt;br&gt;
      "args": [&lt;br&gt;
        "@playwright/mcp@latest"&lt;br&gt;
      ],&lt;br&gt;
      "disabled": false,&lt;br&gt;
      "autoApprove": [&lt;br&gt;
        "browser_click",&lt;br&gt;
        "browser_wait_for",&lt;br&gt;
        "browser_navigate"&lt;br&gt;
      ]&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/code&gt;&lt;br&gt;
Note that a few steps are auto-approved; for most others, I like to run Playwright in headless mode = false and watch the test in case I need to give feedback to Kiro.&lt;/p&gt;

&lt;p&gt;When running the tests via script, I've learned a few things, and Kiro helped to create a robust (maybe too robust) steering document - playwright-testing-guidelines.md.  That steering document is at the end of the post.&lt;/p&gt;

&lt;p&gt;Now, many spec tasks will do some visual testing with Playwright, but when it’s time to debug something, I'll often instruct Kiro to use the Playwright MCP to visually walk through the bug and review both the JavaScript console output and the app logs to identify and resolve the bug.&lt;/p&gt;

&lt;p&gt;playwright-testing-guidelines.md steering document content:&lt;/p&gt;
&lt;h1&gt;
  
  
  Playwright Testing Guidelines
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Mandatory Requirements
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Timeouts (REQUIRED)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Always prefix with timeout (run from tests/playwright/)&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Configuration Timeouts
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="c1"&gt;// 120 seconds&lt;/span&gt;
  &lt;span class="na"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;         &lt;span class="c1"&gt;// 30 seconds&lt;/span&gt;
  &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headless&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="c1"&gt;// MANDATORY for debugging&lt;/span&gt;
    &lt;span class="na"&gt;actionTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;navigationTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;webServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120000&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;h3&gt;
  
  
  Authentication (MANDATORY)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ensureLoggedOut&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/0830_17_52_auth_utils&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;describe&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 Suite&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="o"&gt;=&amp;gt;&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="nf"&gt;beforeEach&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="nf"&gt;ensureLoggedOut&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;// MANDATORY cleanup&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="nf"&gt;afterEach&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="nf"&gt;ensureLoggedOut&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;// MANDATORY cleanup&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;h2&gt;
  
  
  File Organization
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Directory Structure
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/playwright/
├── tests/                           # All test files
├── utils/                           # Utility functions
├── 0830_17_52_playwright.config.js  # Configuration
├── 0830_17_52_package.json          # Dependencies
└── 0830_17_52_README.md             # Documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  File Naming (MANDATORY)
&lt;/h3&gt;

&lt;p&gt;All files MUST use timestamp prefix: &lt;code&gt;MMdd_HH_mm_filename.js&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Browser Configuration
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headless&lt;/strong&gt;: &lt;code&gt;false&lt;/code&gt; (MANDATORY for debugging)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary&lt;/strong&gt;: WebKit (Safari)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secondary&lt;/strong&gt;: Chromium, Firefox&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Command Examples
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Navigate to correct directory first&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;tests/playwright

&lt;span class="c"&gt;# Run tests&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js

&lt;span class="c"&gt;# Debug mode&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js &lt;span class="nt"&gt;--debug&lt;/span&gt;

&lt;span class="c"&gt;# Specific test&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test &lt;/span&gt;tests/0830_17_52_test_admin.js &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;120
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Landing Page Tests (NEW)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Running Landing Page Tests
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Navigate to correct directory first&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;tests/playwright

&lt;span class="c"&gt;# Start web application first&lt;/span&gt;
python web_app.py &amp;amp; &lt;span class="nb"&gt;sleep &lt;/span&gt;10

&lt;span class="c"&gt;# Run accessibility tests (REQUIRED timeout prefix)&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test &lt;/span&gt;tests/0905_14_50_test_landing_page_accessibility.js &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js

&lt;span class="c"&gt;# Run UI tests&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test &lt;/span&gt;tests/0905_14_50_test_landing_page_ui.js &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js

&lt;span class="c"&gt;# Debug mode&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test &lt;/span&gt;tests/0905_14_50_test_landing_page_accessibility.js &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js &lt;span class="nt"&gt;--debug&lt;/span&gt;

&lt;span class="c"&gt;# Use convenience script&lt;/span&gt;
./0905_14_50_run_landing_page_tests.sh &lt;span class="nt"&gt;--accessibility&lt;/span&gt;
./0905_14_50_run_landing_page_tests.sh &lt;span class="nt"&gt;--ui&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Critical Security Issues
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Page.evaluate() Security Error
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: &lt;code&gt;SecurityError: The operation is insecure&lt;/code&gt; in WebKit&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Avoid &lt;code&gt;page.evaluate()&lt;/code&gt; for storage cleanup&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Safe cleanup&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&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;context&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;clearCookies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// WRONG - Causes SecurityError&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&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;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="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// SecurityError!&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;h3&gt;
  
  
  Navigation Timeout Prevention
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: &lt;code&gt;networkidle&lt;/code&gt; timeouts with WebSockets&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Use &lt;code&gt;domcontentloaded&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT&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;/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;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;domcontentloaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// WRONG - Times out&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;/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;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;networkidle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quality Standards
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;All tests must pass consistently&lt;/li&gt;
&lt;li&gt;No console errors (WebSocket, CORS, notifications)&lt;/li&gt;
&lt;li&gt;Proper cleanup after each test&lt;/li&gt;
&lt;li&gt;Clear, descriptive test names&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Generic Test Running Instructions (For Any Playwright Test)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Standard Test Execution Pattern
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. ALWAYS navigate to correct directory first&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;tests/playwright

&lt;span class="c"&gt;# 2. Start web application if needed (most tests require this)&lt;/span&gt;
python web_app.py &amp;amp; &lt;span class="nb"&gt;sleep &lt;/span&gt;10

&lt;span class="c"&gt;# 3. Verify app is running&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://127.0.0.1:5000 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-5&lt;/span&gt;

&lt;span class="c"&gt;# 4. Run test with MANDATORY timeout prefix and working config&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test &lt;/span&gt;tests/[TIMESTAMP]_test_[NAME].js &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js

&lt;span class="c"&gt;# 5. For debugging, add --debug flag&lt;/span&gt;
&lt;span class="nb"&gt;timeout &lt;/span&gt;120 npx playwright &lt;span class="nb"&gt;test &lt;/span&gt;tests/[TIMESTAMP]_test_[NAME].js &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0830_17_52_playwright.config.js &lt;span class="nt"&gt;--debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test File Pattern Recognition
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;All test files follow: &lt;code&gt;tests/MMdd_HH_mm_test_[description].js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Always use existing working config: &lt;code&gt;0830_17_52_playwright.config.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Always use timeout prefix: &lt;code&gt;timeout 120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Always run from &lt;code&gt;tests/playwright/&lt;/code&gt; directory&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Universal Prerequisites Checklist
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;✅ Navigate to &lt;code&gt;tests/playwright/&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;✅ Start web application: &lt;code&gt;python web_app.py &amp;amp; sleep 10&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ Verify app responds: &lt;code&gt;curl http://127.0.0.1:5000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ Use timeout prefix: &lt;code&gt;timeout 120&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ Use working config: &lt;code&gt;--config=0830_17_52_playwright.config.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ For debugging: add &lt;code&gt;--debug&lt;/code&gt; flag&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Common Error Prevention
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"No tests found"&lt;/strong&gt;: Check file path and use correct config&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout errors&lt;/strong&gt;: Ensure web app is running first&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation errors&lt;/strong&gt;: Use &lt;code&gt;domcontentloaded&lt;/code&gt; not &lt;code&gt;networkidle&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security errors&lt;/strong&gt;: Avoid &lt;code&gt;page.evaluate()&lt;/code&gt; for storage operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser errors&lt;/strong&gt;: Ensure browsers installed: &lt;code&gt;npx playwright install&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Verify web app running on &lt;code&gt;http://127.0.0.1:5000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Confirm admin/user accounts exist&lt;/li&gt;
&lt;li&gt;Check browser console for errors&lt;/li&gt;
&lt;li&gt;Use debug mode for step-by-step execution&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  AJAX Form Testing (Lessons Learned)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JavaScript Event Handling
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: JavaScript event listeners may not be properly attached or executed in Playwright.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Use direct element interaction and verify JavaScript execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Direct button click with proper waiting&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[type="submit"]&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;wait_for_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Wait for AJAX completion&lt;/span&gt;

&lt;span class="c1"&gt;// ALSO CORRECT - Verify JavaScript is executing&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;js_event_listener&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="dl"&gt;'''&lt;/span&gt;&lt;span class="s1"&gt;
    () =&amp;gt; {
        const form = document.querySelector(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;edit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;);
        if (form) {
            return form.onsubmit !== null;
        }
        return false;
    }
&lt;/span&gt;&lt;span class="dl"&gt;'''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`JavaScript event listener attached: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;js_event_listener&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Console Message Monitoring
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: JavaScript errors and AJAX responses may not be visible in test output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Set up real-time console message capture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Real-time console monitoring&lt;/span&gt;
&lt;span class="nx"&gt;console_messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;console_handler&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="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Console {msg.type}: {msg.text}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;console_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;   {message}&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;console&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;console_handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AJAX Form Submission Testing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Forms using AJAX may not trigger traditional form submission events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Test both direct interaction and verify AJAX responses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Test AJAX form submission&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#first_name&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;TestValue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button[type="submit"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Wait for AJAX completion&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;wait_for_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Verify success through console logs&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Response data: {success: true}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;console_messages&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="s2"&gt;✅ AJAX submission successful&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Page Reload Handling
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: AJAX forms that reload pages may cause timeout issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Use appropriate timeouts and verify page state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Handle page reloads after AJAX&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;wait_for_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Wait for reload&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;wait_for_selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#view-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Alternative - Check URL if page reloads&lt;/span&gt;
&lt;span class="nx"&gt;current_url&lt;/span&gt; &lt;span class="o"&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;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;current_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;✅ Page reload successful&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Form Validation Testing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: CSRF protection and form validation may fail silently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Verify form data and CSRF tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Check form structure and CSRF&lt;/span&gt;
&lt;span class="nx"&gt;form_html&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;inner_html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#edit-mode form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Form contains CSRF token: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;csrf_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form_html&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;// Verify form data submission&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="s2"&gt;Form data being submitted:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&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;h3&gt;
  
  
  Browser-Specific Behavior
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Different browsers may handle JavaScript and AJAX differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Test across browsers and use appropriate waits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Browser-agnostic testing&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browsers&lt;/span&gt; &lt;span class="o"&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;webkit&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;chromium&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;firefox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;browsers&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Test implementation&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Headless mode may hide JavaScript and AJAX issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Always use headless mode for debugging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CORRECT - Debug configuration&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webkit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headless&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// MANDATORY&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Add screenshots for debugging&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;debug_result.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test Organization for AJAX Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: AJAX functionality requires comprehensive testing of both client and server sides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Create dedicated test files for AJAX features:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/playwright/
├── test_profile_editing_functionality.py  # AJAX form tests
├── debug_profile_submission.py            # Debug scripts
└── utils/
    └── ajax_helpers.py                    # AJAX test utilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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