agent-browser/skills/web-test/SKILL.md
Use to debug a live web page and convert findings into Playwright regression tests — investigate UI bugs, fix flaky tests, generate E2E tests from exploration. Orchestrates the debug-to-test workflow. Not for writing standalone tests with no exploration (use playwright).
npx skillsauth add musingfox/cc-plugins web-testInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill orchestrates a four-phase workflow: explore a web page with agent-browser to identify issues, diagnose problems, map element references to Playwright locators, and generate test scripts that capture findings as regression tests.
Prerequisites: agent-browser CLI installed (npm install -g agent-browser && agent-browser install) and @playwright/test installed in the project (npm install -D @playwright/test && npx playwright install).
The four phases:
Explore (agent-browser) → Diagnose → Map refs to locators → Generate Playwright test
Navigate to the target page and systematically inspect its state:
agent-browser open <url>
agent-browser snapshot -i
Investigation checklist:
screenshot to observe layout, visual state, and obvious defects.snapshot -i to list all interactive elements with refs.snapshot -s ".section" to isolate specific areas of interest.scroll down N then re-snapshot to find below-fold content.screenshot --annotate to visually confirm ref-to-element mapping.Record every interaction step — these become the basis for test cases in Phase 4.
Exploration is complete when all visible sections have been inspected, all interactive elements have been tested, and all observed defects have been recorded.
Categorize findings from exploration:
| Category | Detection Method | Example | |----------|-----------------|---------| | Missing element | Expected ref absent from snapshot | Button in spec but not in DOM | | Wrong text | Snapshot shows incorrect label/content | "Save" button labeled "Svae" | | Broken interaction | Action produces no or wrong state change | Submit button doesn't navigate | | Visual defect | Screenshot shows layout/style issues | Overlapping elements, clipped text | | Accessibility gap | Snapshot shows missing roles/labels | Input without associated label |
When agent-browser cannot diagnose the root cause (console errors, network failures, JavaScript state, iframes, shadow DOM), switch to Playwright library mode. Use page.on('console') for console errors, page.on('response') for network failures, and page.evaluate() for JavaScript state inspection.
For diagnostic code templates and the full fallback scenario reference, consult references/playwright-diagnostics.md.
Convert agent-browser snapshot information to Playwright locators. Apply the locator precision order from the playwright skill (getByTestId > getByRole > getByLabel > getByPlaceholder > getByText > data attributes > CSS).
agent-browser reports element roles from the accessibility tree. Map them directly to Playwright locators:
data-testid attribute → getByTestId() (always preferred)button "Submit") → getByRole('button', { name: 'Submit' })textbox "Email") → getByLabel('Email'){ exact: true } to text-based locators.filter({ hasText: 'unique' }) or scope to parentSnapshot output: Playwright locator:
─────────────────────────────────────────────────────────────
@e1: button "Submit" → getByRole('button', { name: 'Submit' })
@e2: textbox "Email" → getByLabel('Email')
@e3: link "Learn more" → getByRole('link', { name: 'Learn more' })
@e4: heading "Dashboard" [level=1] → getByRole('heading', { name: 'Dashboard', level: 1 })
@e5: checkbox "Remember me" → getByLabel('Remember me')
@e6: combobox "Country" → getByLabel('Country')
Transform exploration steps and diagnosed issues into a structured test file:
import { test, expect } from '@playwright/test';
test.describe('<Feature or Page Name>', () => {
test.beforeEach(async ({ page }) => {
await page.goto('<url>');
});
// Happy path — captures the successful interaction flow
test('should <expected behavior description>', async ({ page }) => {
// Arrange
const emailField = page.getByLabel('Email');
const submitButton = page.getByRole('button', { name: 'Submit' });
// Act
await emailField.fill('[email protected]');
await submitButton.click();
// Assert
await expect(page.getByText('Success', { exact: true })).toBeVisible();
});
// Regression test — prevents a diagnosed bug from reappearing
test('should not show error when <fixed scenario>', async ({ page }) => {
// Reproduce the scenario that previously failed
const deleteButton = page.getByRole('button', { name: 'Delete' });
await deleteButton.click();
// Verify the fix holds
await expect(page.getByText('Item deleted', { exact: true })).toBeVisible();
await expect(page.getByRole('alert')).not.toBeVisible();
});
});
'should navigate to dashboard after login', not 'test login'.await expect(locator).toBeVisible(), never expect(await locator.isVisible()).toBe(true).When console or network issues were diagnosed during Phase 2, convert them into test assertions. For diagnostic test patterns (console error detection, network health, JavaScript error tests), consult references/playwright-diagnostics.md.
1. agent-browser open https://app.example.com/login
2. agent-browser snapshot -i
→ @e1: textbox "Email"
→ @e2: textbox "Password"
→ @e3: button "Sign In"
3. agent-browser fill @e1 "[email protected]"
4. agent-browser fill @e2 "password123"
5. agent-browser click @e3
6. agent-browser snapshot -i
→ @e4: heading "Dashboard"
→ @e5: button "Logout"
7. agent-browser screenshot
→ Dashboard loaded correctly
Generated test:
test('should login and reach dashboard', async ({ page }) => {
await page.goto('https://app.example.com/login');
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password').fill('password123');
await page.getByRole('button', { name: 'Sign In' }).click();
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Logout' })).toBeVisible();
});
data-ai
Unified entry point for Obsidian daily-note captures and long-form notes. Triggers on "記一下 / log / 紀錄 / capture this / 寫到 journal" (→ cap mode) and "建立筆記 / new note / 寫一份筆記 / create a note on" (→ note mode). Also via `/obw:cap` and `/obw:note`. Requires `.obsidian.yaml`.
tools
Use the `gog` CLI to operate Google Workspace — Gmail (read/search/send/labels/drafts), Calendar (events/RSVP/freebusy/focus-time/out-of-office), and Drive (list/search/upload/ download/share/move). Triggers on any Gmail, inbox, email, calendar, agenda, meeting, schedule, RSVP, Drive, Google Doc/Sheet/Slides, file share, or upload/download request.
documentation
Interactively create .obsidian.yaml for a project and install starter templates (task / doc / adr) into the vault's Templates folder. Skips templates that already exist; never overwrites.
tools
Manage project hook-guard installation — set up, diagnose, or update Claude Code hooks, git pre-commit, and commit-msg scripts with security checks, code-quality gates, and CLAUDECODE skip logic. Triggers on "set up hooks", "configure pre-commit", "add linting hooks", "initialize hook-guard", "check hooks", "hook doctor", "verify hook setup", "troubleshoot hooks", "update hooks", "regenerate hooks", "sync hooks with current tools", or similar requests.