/playwright-debugging
Use when Playwright scripts fail, tests are flaky, selectors stop working, or timeouts occur - provides systematic debugging approach for browser automation issues
$ npx -y skills add ed3dai/ed3d-plugins --skill playwright-debugging --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/playwright-debugging
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use when Playwright scripts fail, tests are flaky, selectors stop working, or timeouts occur - provides systematic debugging approach for browser automation issues
SKILL.md
playwright-debugging.SKILL.mdname: playwright-debugging
description: Use when Playwright scripts fail, tests are flaky, selectors stop working, or timeouts occur - provides systematic debugging approach for browser automation issues
user-invocable: false
Playwright Debugging
Overview
Browser automation failures fall into predictable categories. This skill provides a systematic approach to diagnose and fix issues quickly.
When to Use
- Scripts that worked before now fail
- Intermittent test failures (flakiness)
- "Element not found" errors
- Timeout errors
- Unexpected behavior in automation
- Elements not interactable
**When NOT to use:**
- Writing new automation (use playwright-patterns skill)
- API or backend debugging
Quick Reference
| Problem | First Action | |---------|-------------| | Timeout on locator | Run with `--ui` mode, check element state with `.count()`, `.isVisible()` | | Flaky test (passes sometimes) | Replace `waitForTimeout()` with condition-based waits | | "Element not visible" | Check computed styles, wait for overlays to disappear | | Works locally, fails CI | Use `waitForLoadState('networkidle')`, increase timeout | | Element not clickable | Check if covered by overlay, wait for animations to complete | | Stale element | Re-query after navigation instead of storing locator |
Diagnostic Framework
1. Reproduce and Isolate
**First step: Can you reproduce it?**
// Run single test to isolate issue
npx playwright test path/to/test.spec.js
// Run with headed mode to observe
npx playwright test --headed
// Run with slow motion
npx playwright test --headed --slow-mo=1000
**Questions to answer:**
- Does it fail consistently or intermittently?
- Does it fail in all browsers or just one?
- Does it fail in headed and headless mode?
- Did something change recently (site update, code change)?
2. Add Visibility
**Use UI Mode for interactive debugging:**
# Best for local development - provides time-travel debugging
npx playwright test --ui
UI Mode gives you:
- Visual timeline of all actions
- Watch mode for re-running on file changes
- Network and console tabs
- Time-travel through test execution
**Use Inspector to step through tests:**
# Step through test execution with live browser
npx playwright test --debug
Inspector allows:
- Stepping through actions one at a time
- Picking locators directly from the browser
- Editing selectors live and seeing results
- Viewing actionability logs
**Take screenshots at failure point:**
// Before failing action
await page.screenshot({ path: 'before-action.png', fullPage: true });
// Try action
try {
await page.click('.button');
} catch (error) {
await page.screenshot({ path: 'after-error.png', fullPage: true });
throw error;
}**Enable verbose logging:**
# API-level debugging
DEBUG=pw:api npx playwright test
# Browser DevTools with playwright object
PWDEBUG=console npx playwright test
With `PWDEBUG=console`, you get DevTools access to:
// In browser console
playwright.$('.selector') // Query with Playwright engine
playwright.$$('selector') // Get all matches
playwright.inspect('selector') // Highlight in Elements panel
playwright.locator('selector') // Create locator**Use trace viewer:**
// Record trace
await context.tracing.start({ screenshots: true, snapshots: true });
// ... your test code
await context.tracing.stop({ path: 'trace.zip' });
// View trace
npx playwright show-trace trace.zip**Organize traces with test steps:**
// Group actions in trace viewer
await test.step('Login', async () => {
await page.fill('input[name="username"]', 'user');
await page.click('button[type="submit"]');
});
await test.step('Navigate to dashboard', async () => {
await page.click('a[href="/dashboard"]');
});**Add descriptions to locators for clarity:**
// Descriptions appear in trace viewer and reports
const submitButton = page.locator('#submit').describe('Submit button');
await submitButton.click();**VS Code debugging:**
Install the Playwright VS Code extension for:
- Live debugging with breakpoints in VS Code
- Locator highlighting in browser while editing
- "Show Browser" option for real-time feedback
- Right-click "Debug Test" on any test
This integrates debugging directly into your editor workflow.
3. Inspect Element State
**Check if element exists:**
const element = page.locator('.button');
// Does it exist in DOM?
const count = await element.count();
console.log(`Found ${count} elements`);
// Is it visible?
const isVisible = await element.isVisible();
console.log(`Visible: ${isVisible}`);
// Is it enabled?
const isEnabled = await element.isEnabled();
console.log(`Enabled: ${isEnabled}`);
// Get all attributes
const attrs = await element.evaluate(el => ({
classes: el.className,
id: el.id,
display: window.getComputedStyle(el).display,
visibility: window.getComputedStyle(el).visibility,
opacity: window.getComputedStyle(el).opacity
}));
console.log(attrs);4. Verify Selector
**Test selector in browser console:**
// Use page.evaluate to test selector
const found = await page.evaluate(() => {
const el = document.querySelector('.button');
return el ? {
text: el.textContent,
visible: el.offsetParent !== null,
enabled: !el.disabled
} : null;
});
console.log('Selector test:', found);**Check for multiple matches:**
// Are there multiple elements?
const all = await page.locator('.button').all();
console.log(`Found ${all.length} matching elements`);
// Get text of all matches
const texts = await page.locator('.button').allTextContents();
console.log('All matching texts:', texts);Common Issues and Fixes
Issue: Element Not Found
**Causes:**
- Selector is wrong
- Element hasn't loaded yet
- Element is in iframe
- Element is dynamically created
**Deb
Read more
name: playwright-debugging description: Use when Playwright scripts fail, tests are flaky, selectors stop working, or timeouts occur - provides systematic debugging approach for browser automation issues user-invocable: false
Playwright Debugging
Overview
Browser automation failures fall into predictable categories. This skill provides a systematic approach to diagnose and fix issues quickly.
When to Use
- Scripts that worked before now fail
- Intermittent test failures (flakiness)
- "Element not found" errors
- Timeout errors
- Unexpected behavior in automation
- Elements not interactable
**When NOT to use:**
- Writing new automation (use playwright-patterns skill)
- API or backend debugging
Quick Reference
| Problem | First Action | |---------|-------------| | Timeout on locator | Run with `--ui` mode, check element state with `.count()`, `.isVisible()` | | Flaky test (passes sometimes) | Replace `waitForTimeout()` with condition-based waits | | "Element not visible" | Check computed styles, wait for overlays to disappear | | Works locally, fails CI | Use `waitForLoadState('networkidle')`, increase timeout | | Element not clickable | Check if covered by overlay, wait for animations to complete | | Stale element | Re-query after navigation instead of storing locator |
Diagnostic Framework
1. Reproduce and Isolate
**First step: Can you reproduce it?**
// Run single test to isolate issue npx playwright test path/to/test.spec.js // Run with headed mode to observe npx playwright test --headed // Run with slow motion npx playwright test --headed --slow-mo=1000
**Questions to answer:**
- Does it fail consistently or intermittently?
- Does it fail in all browsers or just one?
- Does it fail in headed and headless mode?
- Did something change recently (site update, code change)?
2. Add Visibility
**Use UI Mode for interactive debugging:**
# Best for local development - provides time-travel debugging npx playwright test --ui
UI Mode gives you:
- Visual timeline of all actions
- Watch mode for re-running on file changes
- Network and console tabs
- Time-travel through test execution
**Use Inspector to step through tests:**
# Step through test execution with live browser npx playwright test --debug
Inspector allows:
- Stepping through actions one at a time
- Picking locators directly from the browser
- Editing selectors live and seeing results
- Viewing actionability logs
**Take screenshots at failure point:**
// Before failing action
await page.screenshot({ path: 'before-action.png', fullPage: true });
// Try action
try {
await page.click('.button');
} catch (error) {
await page.screenshot({ path: 'after-error.png', fullPage: true });
throw error;
}**Enable verbose logging:**
# API-level debugging DEBUG=pw:api npx playwright test # Browser DevTools with playwright object PWDEBUG=console npx playwright test
With `PWDEBUG=console`, you get DevTools access to:
// In browser console
playwright.$('.selector') // Query with Playwright engine
playwright.$$('selector') // Get all matches
playwright.inspect('selector') // Highlight in Elements panel
playwright.locator('selector') // Create locator**Use trace viewer:**
// Record trace
await context.tracing.start({ screenshots: true, snapshots: true });
// ... your test code
await context.tracing.stop({ path: 'trace.zip' });
// View trace
npx playwright show-trace trace.zip**Organize traces with test steps:**
// Group actions in trace viewer
await test.step('Login', async () => {
await page.fill('input[name="username"]', 'user');
await page.click('button[type="submit"]');
});
await test.step('Navigate to dashboard', async () => {
await page.click('a[href="/dashboard"]');
});**Add descriptions to locators for clarity:**
// Descriptions appear in trace viewer and reports
const submitButton = page.locator('#submit').describe('Submit button');
await submitButton.click();**VS Code debugging:**
Install the Playwright VS Code extension for:
- Live debugging with breakpoints in VS Code
- Locator highlighting in browser while editing
- "Show Browser" option for real-time feedback
- Right-click "Debug Test" on any test
This integrates debugging directly into your editor workflow.
3. Inspect Element State
**Check if element exists:**
const element = page.locator('.button');
// Does it exist in DOM?
const count = await element.count();
console.log(`Found ${count} elements`);
// Is it visible?
const isVisible = await element.isVisible();
console.log(`Visible: ${isVisible}`);
// Is it enabled?
const isEnabled = await element.isEnabled();
console.log(`Enabled: ${isEnabled}`);
// Get all attributes
const attrs = await element.evaluate(el => ({
classes: el.className,
id: el.id,
display: window.getComputedStyle(el).display,
visibility: window.getComputedStyle(el).visibility,
opacity: window.getComputedStyle(el).opacity
}));
console.log(attrs);4. Verify Selector
**Test selector in browser console:**
// Use page.evaluate to test selector
const found = await page.evaluate(() => {
const el = document.querySelector('.button');
return el ? {
text: el.textContent,
visible: el.offsetParent !== null,
enabled: !el.disabled
} : null;
});
console.log('Selector test:', found);**Check for multiple matches:**
// Are there multiple elements?
const all = await page.locator('.button').all();
console.log(`Found ${all.length} matching elements`);
// Get text of all matches
const texts = await page.locator('.button').allTextContents();
console.log('All matching texts:', texts);Common Issues and Fixes
Issue: Element Not Found
**Causes:**
- Selector is wrong
- Element hasn't loaded yet
- Element is in iframe
- Element is dynamically created
**Deb
Showing the first part of this file.
This is my collection of plugins that I use on a day-to-day basis for getting stuff done with Claude Code. Most of these are development-oriented in some way or another, but also often end up being useful for other things.
Repo: ed3dai/ed3d-plugins
Other skills on ed3d-plugins.
- /doing-a-simple-two-stage-fanout
Use when analyzing a large corpus of text, code, or data that exceeds a single agent's effective context - orchestrates parallel Worker subagents, Critic review subagents, and a final Summarizer subagent with task tracking and failure recovery
Open skill - /using-generic-agents
Use to decide what kind of generic agent you should use
Open skill - /creating-a-plugin
Use when creating a new Claude Code plugin or setting up plugin structure - provides complete file organization, manifest format, and component definitions for commands, agents, skills, hooks, and MCP servers
Open skill - /creating-an-agent
Use when creating specialized subagents for Claude Code plugins or the Task tool - covers description writing for auto-delegation, tool selection, prompt structure, and testing agents
Open skill - /maintaining-a-marketplace
Use when creating, releasing, or maintaining a Claude Code Plugin Marketplace - covers marketplace.json schema, version management, release checklists, changelog conventions, and validation to prevent sync drift between plugin.json and marketplace.json
Open skill - /maintaining-project-context
Use when completing development phases or branches to identify and update CLAUDE.md or AGENTS.md files that may have become stale - analyzes what changed, determines affected contracts and documentation, and coordinates updates
Open skill

