Skip to content

/playwright-debugging

Use when Playwright scripts fail, tests are flaky, selectors stop working, or timeouts occur - provides systematic debugging approach for browser automation issues

shell
$ npx -y skills add ed3dai/ed3d-plugins --skill playwright-debugging --agent claude-code

How 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
How auto-invocation works

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.md
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

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withed3d-plugins

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.

Get the whole plugin, auto-invoked