[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-anthropics-skills-skills-webapp-testing":3},{"error":4,"detail":5,"metadata":53,"markdownContent":55,"rawMarkdown":50},false,{"repo_full_name":6,"owner":7,"repo_name":8,"repo_forks":9,"skill_path":10,"repo_stars":11,"name":12,"category_id":13,"description":14,"file_tree":15,"skill_md_content":50,"skill_id":51,"skill_key":52},"anthropics/skills","anthropics","skills",10483,"skills/webapp-testing",97092,"webapp-testing",1,"Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.",[16,21,25,42],{"name":17,"path":18,"size":19,"type":20},"LICENSE.txt","skills/webapp-testing/LICENSE.txt",11357,"file",{"name":22,"path":23,"size":24,"type":20},"SKILL.md","skills/webapp-testing/SKILL.md",3913,{"name":26,"path":27,"type":28,"children":29},"examples","skills/webapp-testing/examples","folder",[30,34,38],{"name":31,"path":32,"size":33,"type":20},"console_logging.py","skills/webapp-testing/examples/console_logging.py",1027,{"name":35,"path":36,"size":37,"type":20},"element_discovery.py","skills/webapp-testing/examples/element_discovery.py",1463,{"name":39,"path":40,"size":41,"type":20},"static_html_automation.py","skills/webapp-testing/examples/static_html_automation.py",953,{"name":43,"path":44,"type":28,"children":45},"scripts","skills/webapp-testing/scripts",[46],{"name":47,"path":48,"size":49,"type":20},"with_server.py","skills/webapp-testing/scripts/with_server.py",3693,"---\nname: webapp-testing\ndescription: Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Web Application Testing\n\nTo test local web applications, write native Python Playwright scripts.\n\n**Helper Scripts Available**:\n- `scripts/with_server.py` - Manages server lifecycle (supports multiple servers)\n\n**Always run scripts with `--help` first** to see usage. DO NOT read the source until you try running the script first and find that a customized solution is abslutely necessary. These scripts can be very large and thus pollute your context window. They exist to be called directly as black-box scripts rather than ingested into your context window.\n\n## Decision Tree: Choosing Your Approach\n\n```\nUser task → Is it static HTML?\n    ├─ Yes → Read HTML file directly to identify selectors\n    │         ├─ Success → Write Playwright script using selectors\n    │         └─ Fails/Incomplete → Treat as dynamic (below)\n    │\n    └─ No (dynamic webapp) → Is the server already running?\n        ├─ No → Run: python scripts/with_server.py --help\n        │        Then use the helper + write simplified Playwright script\n        │\n        └─ Yes → Reconnaissance-then-action:\n            1. Navigate and wait for networkidle\n            2. Take screenshot or inspect DOM\n            3. Identify selectors from rendered state\n            4. Execute actions with discovered selectors\n```\n\n## Example: Using with_server.py\n\nTo start a server, run `--help` first, then use the helper:\n\n**Single server:**\n```bash\npython scripts/with_server.py --server \"npm run dev\" --port 5173 -- python your_automation.py\n```\n\n**Multiple servers (e.g., backend + frontend):**\n```bash\npython scripts/with_server.py \\\n  --server \"cd backend && python server.py\" --port 3000 \\\n  --server \"cd frontend && npm run dev\" --port 5173 \\\n  -- python your_automation.py\n```\n\nTo create an automation script, include only Playwright logic (servers are managed automatically):\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode\n    page = browser.new_page()\n    page.goto('http://localhost:5173') # Server already running and ready\n    page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute\n    # ... your automation logic\n    browser.close()\n```\n\n## Reconnaissance-Then-Action Pattern\n\n1. **Inspect rendered DOM**:\n   ```python\n   page.screenshot(path='/tmp/inspect.png', full_page=True)\n   content = page.content()\n   page.locator('button').all()\n   ```\n\n2. **Identify selectors** from inspection results\n\n3. **Execute actions** using discovered selectors\n\n## Common Pitfall\n\n❌ **Don't** inspect the DOM before waiting for `networkidle` on dynamic apps\n✅ **Do** wait for `page.wait_for_load_state('networkidle')` before inspection\n\n## Best Practices\n\n- **Use bundled scripts as black boxes** - To accomplish a task, consider whether one of the scripts available in `scripts/` can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use `--help` to see usage, then invoke directly. \n- Use `sync_playwright()` for synchronous scripts\n- Always close the browser when done\n- Use descriptive selectors: `text=`, `role=`, CSS selectors, or IDs\n- Add appropriate waits: `page.wait_for_selector()` or `page.wait_for_timeout()`\n\n## Reference Files\n\n- **examples/** - Examples showing common patterns:\n  - `element_discovery.py` - Discovering buttons, links, and inputs on a page\n  - `static_html_automation.py` - Using file:// URLs for local HTML\n  - `console_logging.py` - Capturing console logs during automation","1ee7eb51-ff87-5ef8-85a4-93044ec04b55","anthropics-skills-skills-webapp-testing",{"name":12,"description":14,"license":54},"Complete terms in LICENSE.txt","\u003Ch1>Web Application Testing\u003C/h1>\n\u003Cp>To test local web applications, write native Python Playwright scripts.\u003C/p>\n\u003Cp>\u003Cstrong>Helper Scripts Available\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Ccode>scripts/with_server.py\u003C/code> - Manages server lifecycle (supports multiple servers)\u003C/li>\n\u003C/ul>\n\u003Cp>\u003Cstrong>Always run scripts with \u003Ccode>--help\u003C/code> first\u003C/strong> to see usage. DO NOT read the source until you try running the script first and find that a customized solution is abslutely necessary. These scripts can be very large and thus pollute your context window. They exist to be called directly as black-box scripts rather than ingested into your context window.\u003C/p>\n\u003Ch2>Decision Tree: Choosing Your Approach\u003C/h2>\n\u003Cdiv class=\"md-code-block\">\u003Cpre>\u003Ccode class=\"hljs language-plaintext\">User task → Is it static HTML?\n    ├─ Yes → Read HTML file directly to identify selectors\n    │         ├─ Success → Write Playwright script using selectors\n    │         └─ Fails/Incomplete → Treat as dynamic (below)\n    │\n    └─ No (dynamic webapp) → Is the server already running?\n        ├─ No → Run: python scripts/with_server.py --help\n        │        Then use the helper + write simplified Playwright script\n        │\n        └─ Yes → Reconnaissance-then-action:\n            1. Navigate and wait for networkidle\n            2. Take screenshot or inspect DOM\n            3. Identify selectors from rendered state\n            4. Execute actions with discovered selectors\u003C/code>\u003C/pre>\u003C/div>\u003Ch2>Example: Using with_server.py\u003C/h2>\n\u003Cp>To start a server, run \u003Ccode>--help\u003C/code> first, then use the helper:\u003C/p>\n\u003Cp>\u003Cstrong>Single server:\u003C/strong>\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">bash\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-bash\">python scripts/with_server.py --server \u003Cspan class=\"hljs-string\">&quot;npm run dev&quot;\u003C/span> --port 5173 -- python your_automation.py\u003C/code>\u003C/pre>\u003C/div>\u003Cp>\u003Cstrong>Multiple servers (e.g., backend + frontend):\u003C/strong>\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">bash\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-bash\">python scripts/with_server.py \\\n  --server \u003Cspan class=\"hljs-string\">&quot;cd backend &amp;&amp; python server.py&quot;\u003C/span> --port 3000 \\\n  --server \u003Cspan class=\"hljs-string\">&quot;cd frontend &amp;&amp; npm run dev&quot;\u003C/span> --port 5173 \\\n  -- python your_automation.py\u003C/code>\u003C/pre>\u003C/div>\u003Cp>To create an automation script, include only Playwright logic (servers are managed automatically):\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">python\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-python\">\u003Cspan class=\"hljs-keyword\">from\u003C/span> playwright.sync_api \u003Cspan class=\"hljs-keyword\">import\u003C/span> sync_playwright\n\n\u003Cspan class=\"hljs-keyword\">with\u003C/span> sync_playwright() \u003Cspan class=\"hljs-keyword\">as\u003C/span> p:\n    browser = p.chromium.launch(headless=\u003Cspan class=\"hljs-literal\">True\u003C/span>) \u003Cspan class=\"hljs-comment\"># Always launch chromium in headless mode\u003C/span>\n    page = browser.new_page()\n    page.goto(\u003Cspan class=\"hljs-string\">&#x27;http://localhost:5173&#x27;\u003C/span>) \u003Cspan class=\"hljs-comment\"># Server already running and ready\u003C/span>\n    page.wait_for_load_state(\u003Cspan class=\"hljs-string\">&#x27;networkidle&#x27;\u003C/span>) \u003Cspan class=\"hljs-comment\"># CRITICAL: Wait for JS to execute\u003C/span>\n    \u003Cspan class=\"hljs-comment\"># ... your automation logic\u003C/span>\n    browser.close()\u003C/code>\u003C/pre>\u003C/div>\u003Ch2>Reconnaissance-Then-Action Pattern\u003C/h2>\n\u003Col>\n\u003Cli>\u003Cp>\u003Cstrong>Inspect rendered DOM\u003C/strong>:\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">python\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-python\">page.screenshot(path=\u003Cspan class=\"hljs-string\">&#x27;/tmp/inspect.png&#x27;\u003C/span>, full_page=\u003Cspan class=\"hljs-literal\">True\u003C/span>)\ncontent = page.content()\npage.locator(\u003Cspan class=\"hljs-string\">&#x27;button&#x27;\u003C/span>).\u003Cspan class=\"hljs-built_in\">all\u003C/span>()\u003C/code>\u003C/pre>\u003C/div>\u003C/li>\n\u003Cli>\u003Cp>\u003Cstrong>Identify selectors\u003C/strong> from inspection results\u003C/p>\n\u003C/li>\n\u003Cli>\u003Cp>\u003Cstrong>Execute actions\u003C/strong> using discovered selectors\u003C/p>\n\u003C/li>\n\u003C/ol>\n\u003Ch2>Common Pitfall\u003C/h2>\n\u003Cp>❌ \u003Cstrong>Don&#39;t\u003C/strong> inspect the DOM before waiting for \u003Ccode>networkidle\u003C/code> on dynamic apps\n✅ \u003Cstrong>Do\u003C/strong> wait for \u003Ccode>page.wait_for_load_state(&#39;networkidle&#39;)\u003C/code> before inspection\u003C/p>\n\u003Ch2>Best Practices\u003C/h2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Use bundled scripts as black boxes\u003C/strong> - To accomplish a task, consider whether one of the scripts available in \u003Ccode>scripts/\u003C/code> can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use \u003Ccode>--help\u003C/code> to see usage, then invoke directly. \u003C/li>\n\u003Cli>Use \u003Ccode>sync_playwright()\u003C/code> for synchronous scripts\u003C/li>\n\u003Cli>Always close the browser when done\u003C/li>\n\u003Cli>Use descriptive selectors: \u003Ccode>text=\u003C/code>, \u003Ccode>role=\u003C/code>, CSS selectors, or IDs\u003C/li>\n\u003Cli>Add appropriate waits: \u003Ccode>page.wait_for_selector()\u003C/code> or \u003Ccode>page.wait_for_timeout()\u003C/code>\u003C/li>\n\u003C/ul>\n\u003Ch2>Reference Files\u003C/h2>\n\u003Cul>\n\u003Cli>\u003Cstrong>examples/\u003C/strong> - Examples showing common patterns:\u003Cul>\n\u003Cli>\u003Ccode>element_discovery.py\u003C/code> - Discovering buttons, links, and inputs on a page\u003C/li>\n\u003Cli>\u003Ccode>static_html_automation.py\u003C/code> - Using file:// URLs for local HTML\u003C/li>\n\u003Cli>\u003Ccode>console_logging.py\u003C/code> - Capturing console logs during automation\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003C/ul>\n"]