Playwright Testing
chongdashu/vibejam-starter-pack
Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y.
Write production-grade Playwright tests in TypeScript: Page Object Model, fixtures, auto-waiting, user-facing locators, parallel execution, CI integration, sharding, and 2025-2026 feature awareness.
$ npx skills add petrkindlmann/qa-skills --skill playwright-automation -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install petrkindlmann/qa-skills playwright-automation --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/petrkindlmann/qa-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/playwright-automation .claude/skills/playwright-automation && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "playwright-automation" agent skill from https://github.com/petrkindlmann/qa-skills/tree/main/skills/playwright-automation into .claude/skills/playwright-automation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "playwright-automation", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/petrkindlmann/qa-skills/tree/main/skills/playwright-automationType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add petrkindlmann/qa-skills --skill playwright-automation -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install petrkindlmann/qa-skills playwright-automation --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/petrkindlmann/qa-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/playwright-automation .agents/skills/playwright-automation && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "playwright-automation" agent skill from https://github.com/petrkindlmann/qa-skills/tree/main/skills/playwright-automation into .agents/skills/playwright-automation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "playwright-automation", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add petrkindlmann/qa-skills --skill playwright-automation -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install petrkindlmann/qa-skills playwright-automation --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/petrkindlmann/qa-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/playwright-automation .cursor/skills/playwright-automation && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "playwright-automation" agent skill from https://github.com/petrkindlmann/qa-skills/tree/main/skills/playwright-automation into .cursor/skills/playwright-automation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "playwright-automation", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/petrkindlmann/qa-skills.git --path skills/playwright-automation--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add petrkindlmann/qa-skills --skill playwright-automation -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install petrkindlmann/qa-skills playwright-automation --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/petrkindlmann/qa-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/playwright-automation .gemini/skills/playwright-automation && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "playwright-automation" agent skill from https://github.com/petrkindlmann/qa-skills/tree/main/skills/playwright-automation into .gemini/skills/playwright-automation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "playwright-automation", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install petrkindlmann/qa-skills playwright-automationInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add petrkindlmann/qa-skills --skill playwright-automation -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/petrkindlmann/qa-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/playwright-automation .github/skills/playwright-automation && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "playwright-automation" agent skill from https://github.com/petrkindlmann/qa-skills/tree/main/skills/playwright-automation into .github/skills/playwright-automation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "playwright-automation", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add petrkindlmann/qa-skills --skill playwright-automation -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install petrkindlmann/qa-skills playwright-automation --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/petrkindlmann/qa-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/playwright-automation .opencode/skills/playwright-automation && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "playwright-automation" agent skill from https://github.com/petrkindlmann/qa-skills/tree/main/skills/playwright-automation into .opencode/skills/playwright-automation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "playwright-automation", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
playwright-automationWrite production-grade Playwright tests in TypeScript: Page Object Model, fixtures, auto-waiting, user-facing locators, parallel execution, CI integration, sharding, and 2025-2026 feature awareness.
Playwright Automation is an agent skill from petrkindlmann/qa-skills. Write production-grade Playwright tests in TypeScript: Page Object Model, fixtures, auto-waiting, user-facing locators, parallel execution, CI integration, sharding, and 2025-2026 feature awareness. Includes an explicit "do not" list for AI agents. Use when: "Playwright," "write E2E test," "page object," "new Playwright suite," "Playwright config." Not for: fixing one flaky test at runtime — use test-reliability. Not for: bulk regenerating selectors after a UI refactor — use selector-drift-recovery. Not for…
Its SKILL.md is about 5.5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 9 other files, including reference files (for example `references/anti-patterns.md`, `references/auth-patterns.md` and `references/ci-recipes.md`).
It sits in Testing & QA, covering Accessibility, Browser testing and End-to-end testing. It works with Playwright and TypeScript. The repository describes itself as: 50 QA and test-automation skills for Claude Code, Codex, Cursor, and any Agent Skills Standard runtime. The licence is MIT.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit b3bb61b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npxopencodeFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use npx, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
TEST_USER_PASSWORDAPI_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Playwright Automation loads about 5.5k tokens when it runs, and up to ~31k if it reads all its reference files. Until then it costs about 194 tokens; SKILL.md has 1,669 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from petrkindlmann/qa-skills at commit b3bb61b, republished under its MIT licence (© petrkindlmann). 1,669 words, ~5,473 tokens.
.claude/skills/playwright-automation/SKILL.md (or your agent's skills folder). This skill also uses 8 other files; get the full folder from GitHub.<objective>
How an expert agent writes stable, maintainable, production-grade Playwright tests in TypeScript. The failure this prevents: AI agents reflexively reach for the three patterns that produce suites which pass once and flake forever — never use `waitForTimeout`, never default to CSS selectors, and avoid the legacy `page.click()` family. This skill encodes the auto-waiting, user-facing-locator, fixture-based discipline that makes a suite survive a refactor.
</objective>
Check .agents/qa-project-context.md first — if it exists, use it and skip any question answered there. Then ask only what's missing:
references/multi-site-architecture.md.getByRole > getByLabel > getByTestId > CSS (last resort). Locators must reflect what the user sees, not how the DOM is structured. See references/selector-strategies.md.waitForTimeout. Every Playwright action and web-first assertion auto-waits. If you think you need a timeout, you need a better locator or assertion.BrowserContext. Tests must never depend on other tests' state or execution order.fullyParallel: true. Reserve test.describe.serial for flows that genuinely cannot be isolated (rare).beforeEach/afterEach for anything non-trivial. See references/fixtures-and-projects.md.Calibrate to your team maturity (set
team_maturityin.agents/qa-project-context.md):
- startup — Chromium only, 5–10 critical-path tests, basic CI run on PR. Skip sharding and visual baselines until the suite is stable.
- growing — Chromium + Firefox, POM structure, parallel execution, sharding in CI, HTML report artifacts.
- established — Full browser matrix, auth fixtures, API mocking layer, visual regression baseline, trace-on-failure, flakiness tracking.
project-root/
├── playwright.config.ts
├── e2e/
│ ├── fixtures/ # base.fixture.ts, auth.fixture.ts, data.fixture.ts
│ ├── pages/ # Page objects by feature
│ │ ├── base.page.ts
│ │ ├── dashboard.page.ts
│ │ └── components/ # Reusable component objects (data-table, modal)
│ ├── tests/ # Test files by feature (auth/, dashboard/, settings/)
│ ├── helpers/ # test-data.ts, api-client.ts
│ └── global-setup.ts
├── .auth/ # Git-ignored storageState files
└── test-results/ # Git-ignored artifactsimport { defineConfig, devices } from '@playwright/test';
const isCI = !!process.env.CI;
const baseURL = process.env.BASE_URL ?? 'http://localhost:3000';
export default defineConfig({
testDir: './e2e/tests',
fullyParallel: true,
forbidOnly: isCI,
retries: isCI ? 2 : 0,
workers: isCI ? '50%' : undefined,
reporter: isCI
? [['blob'], ['github'], ['json', { outputFile: 'test-results/results.json' }]]
: [['html', { open: 'on-failure' }]],
use: {
baseURL,
trace: isCI ? 'on-first-retry' : 'retain-on-failure',
screenshot: 'only-on-failure',
video: isCI ? 'on-first-retry' : 'off',
navigationTimeout: 30_000,
// Avoid a global actionTimeout — it can mask a genuinely slow auto-waited
// action. Set per-action only where a known-slow widget needs it.
},
projects: [
{ name: 'setup', testMatch: /global-setup\.ts/, teardown: 'teardown' },
{ name: 'teardown', testMatch: /global-teardown\.ts/ },
{ name: 'chromium', use: { ...devices['Desktop Chrome'], storageState: '.auth/user.json' }, dependencies: ['setup'] },
{ name: 'firefox', use: { ...devices['Desktop Firefox'], storageState: '.auth/user.json' }, dependencies: ['setup'] },
{ name: 'webkit', use: { ...devices['Desktop Safari'], storageState: '.auth/user.json' }, dependencies: ['setup'] },
],
webServer: isCI ? undefined : {
command: 'npm run dev', url: baseURL, reuseExistingServer: !isCI, timeout: 120_000,
},
});The blob reporter in CI is what makes sharded runs mergeable — see the sharding section. The setup project writes storageState once before the browser projects depend on it.
import { test as setup, expect } from '@playwright/test';
setup('authenticate as default user', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill(process.env.TEST_USER_EMAIL!);
await page.getByLabel('Password').fill(process.env.TEST_USER_PASSWORD!);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/.*dashboard/);
await page.context().storageState({ path: '.auth/user.json' });
});This is the setup project pattern: the setup project (or a globalSetup file) runs UI login once, and every browser project replays the saved cookies/localStorage via storageState in config. For multi-role auth (admin/user/guest) and token seeding, see references/auth-patterns.md.
import { type Page, type Locator, expect } from '@playwright/test';
export abstract class BasePage {
constructor(protected readonly page: Page) {}
abstract readonly path: string;
async goto(): Promise<void> {
await this.page.goto(this.path);
await this.page.waitForLoadState('domcontentloaded');
}
}Component objects represent reusable UI fragments (modals, tables, nav). They take a root Locator, not a Page:
export class DataTable {
readonly rows: Locator;
constructor(private readonly root: Locator) {
this.rows = root.getByRole('row');
}
getRowByText(text: string | RegExp): Locator {
return this.rows.filter({ hasText: text });
}
}Compose, don't inherit deep. A page holds its components; it does not extend a five-level hierarchy:
export class UsersPage extends BasePage {
readonly path = '/admin/users';
readonly table: DataTable;
constructor(page: Page) {
super(page);
this.table = new DataTable(page.getByRole('table', { name: 'Users' }));
}
}Inject page objects via fixtures, not constructors in test files:
export const test = base.extend<{ usersPage: UsersPage }>({
usersPage: async ({ page }, use) => { await use(new UsersPage(page)); },
});
export { expect } from '@playwright/test';POM methods return state (locators, values); they do not assert. Assertions live in the test so failures point at the test, not the page object.
Wrap logical action groups in test.step() for readable trace-viewer output:
test('submits a multi-step form', async ({ page }) => {
await page.goto('/onboarding');
await test.step('fill personal info', async () => {
await page.getByLabel('First name').fill('Jane');
await page.getByRole('button', { name: 'Next' }).click();
});
await test.step('submit', async () => {
await page.getByRole('button', { name: 'Complete setup' }).click();
});
await expect(page).toHaveURL('/dashboard');
});// Mock a response
await page.route('**/api/products*', async (route) => {
await route.fulfill({ json: { items: [{ id: '1', name: 'Widget', price: 29.99 }] } });
});
// Modify a real response
await page.route('**/api/feature-flags', async (route) => {
const response = await route.fetch();
const body = await response.json();
body.flags['new-checkout'] = true;
await route.fulfill({ response, json: body });
});
// Simulate an error
await page.route('**/api/products*', (route) => route.fulfill({ status: 500 }));
// WebSocket (v1.48+)
await page.routeWebSocket('**/ws/notifications', (ws) => {
ws.onMessage(() => ws.send(JSON.stringify({ type: 'alert', title: 'Deployed' })));
});See references/network-and-mocking.md for HAR replay and conditional routing.
For seeding data or asserting backend state without driving the UI, inject a pre-authenticated APIRequestContext. Acquire the token in the fixture; never hardcode it:
import { test, request, type APIRequestContext } from '@playwright/test';
// test.extend adds an `api` fixture to the base test object.
export const apiTest = test.extend<{ api: APIRequestContext }>({
api: async ({ baseURL }, use) => {
const ctx = await request.newContext({
baseURL,
extraHTTPHeaders: { Authorization: `Bearer ${process.env.API_TOKEN!}` },
});
await use(ctx);
await ctx.dispose();
},
});test('checkout @smoke', async ({ page }) => { /* npx playwright test --grep @smoke */ });
test.slow(); // Triples timeout
test.skip(({ browserName }) => browserName === 'webkit', 'WebKit bug');
test.fixme('known issue tracked in JIRA-1234', async ({ page }) => { /* ... */ });Always prefer web-first assertions — they auto-retry until the condition holds or the timeout expires:
await expect(page.getByRole('alert')).toBeVisible();
await expect(page.getByRole('heading')).toHaveText('Dashboard');
await expect(page).toHaveURL('/dashboard');
await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled();
await expect(page.getByRole('listitem')).toHaveCount(5);
await expect(page.getByRole('listitem')).toHaveText(['Apple', 'Banana', 'Cherry']);Soft assertions collect all failures instead of stopping at the first:
await expect.soft(page.getByLabel('Name')).toHaveValue('Jane Doe');
await expect.soft(page.getByLabel('Email')).toHaveValue('jane@example.com');ARIA snapshots verify accessibility-tree structure and catch semantic regressions:
await expect(page.getByRole('navigation', { name: 'Main' })).toMatchAriaSnapshot(`
- navigation "Main":
- link "Home"
- link "Products"
`);Playwright's built-in toHaveScreenshot auto-retries and writes a baseline on first run. Mask dynamic regions; do not precede it with waitForTimeout:
await expect(page.getByTestId('product-card')).toHaveScreenshot('product-card.png', {
mask: [page.getByTestId('price')],
});For baseline management, thresholds (maxDiffPixelRatio, maskColor, stylePath), and review workflows, use visual-testing — that is where visual baselines belong.
ARIA snapshots above check structure, not WCAG rules. For rule-based scanning, add @axe-core/playwright:
import AxeBuilder from '@axe-core/playwright';
test('dashboard has no a11y violations', async ({ page }) => {
await page.goto('/dashboard');
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});For WCAG levels, rule tuning, and remediation guidance, use accessibility-testing.
Split the suite across matrix jobs, then merge the shard reports into one HTML report. Sharding earns its place at growing+ maturity; a startup suite of 5–10 tests should not shard.
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- run: npx playwright test --shard=${{ matrix.shard }}/4Each shard uploads its blob-report/; a final job runs npx playwright merge-reports --reporter=html ./all-blob-reports. The blob reporter (set in the config above) is what makes merge work — --shard alone produces fragmented HTML reports. See references/ci-recipes.md for the full GitHub Actions workflow, blob upload/download, and artifact patterns.
npx playwright show-trace test-results/.../trace.zip — timeline of actions, network, DOM snapshots, console.npx playwright test --ui — live, step-by-step, time-travel.npx playwright test my-test.spec.ts --debug — headed, pauses each action.ms-playwright.playwright — run/debug from gutter, pick locators, watch mode.page.pause() opens the Inspector mid-test. Local only — never commit it.See references/debugging-and-triage.md for flaky-test triage and artifact analysis.
Current latest is Playwright 1.60.0 (May 2026). Pin the same version in package.json and your CI Docker image. Recent additions worth knowing:
| Version | Feature | What it does |
|---|---|---|
| v1.45 | Clock API | page.clock.install() / fastForward() — control time without monkey-patching Date |
| v1.45 | --fail-on-flaky-tests | Fail the CI run if any test needed a retry to pass |
| v1.46 | --only-changed | Run only tests affected by changed files (git-diff aware) |
| v1.46 | ARIA snapshots | toMatchAriaSnapshot() for accessibility-tree assertions |
| v1.48 | routeWebSocket | First-class WebSocket interception (replaces CDP hacks) |
| v1.55 | Test Migrator | Automated Cypress→/Selenium→Playwright via npx playwright migrate |
| v1.56 | Test Agents | npx playwright init-agents --loop=claude|vscode|opencode — planner/generator/healer agents inside the coding agent's loop |
| v1.57 | Chrome for Testing default | Headed uses chrome, headless uses chrome-headless-shell instead of bundled Chromium. Caveat: a high-memory regression was reported (microsoft/playwright #38489) — pin a known-good image tag for CI. |
| v1.57 | toHaveScreenshot options | maskColor, stylePath, pathTemplate for masking color, custom stylesheet, and output path control |
| v1.59 | Screencast API | page.screencast.start() / .stop() for mid-test video with start/stop control — an alternative to recordVideo, not a replacement. Adds action annotations, chapter markers, custom HTML overlays, and screencast.showOverlays() / hideOverlays(). Useful for agent self-verification: a coding agent can hand off a reviewable video receipt. |
| v1.59 | --debug=cli | Pause-and-attach so an agent can step through a test |
| v1.60 | locator.drop() | Simulate an external file/clipboard drag-and-drop onto an element |
| v1.60 | tracing.startHar() | HAR recording as a first-class tracing API |
Two integration paths — pick based on whether the agent runs inside your editor loop or drives a real browser remotely.
Path A — Test Agents (npx playwright init-agents --loop=claude): scaffolds planner/generator/healer agents the coding agent loads during its loop. Token-efficient — no MCP server, no inter-process traffic. Best for "Claude/VS Code/opencode writes Playwright tests for me."
Path B — @playwright/mcp: an MCP server exposing browser actions to any MCP-aware agent. Higher overhead (process boundary, JSON marshalling) but the right choice when the agent must drive a live browser interactively rather than author tests offline. Config: { "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest"] } } } in .mcp.json.
For test-failure repair, see test-reliability. For first-time generation from PRDs/specs, see ai-test-generation.
Design-time mistakes that quietly rot a suite. The code-level "never do X" list lives in references/anti-patterns.md with BAD/GOOD pairs — load it when writing test bodies.
One class for the whole app turns into a 2000-line file every test imports and nothing can refactor safely. Split by page/feature and compose component objects.
A page object whose methods call expect hides the assertion from the test. When it fails, the stack points at the page object, not the failing scenario. Return locators/state; assert in the test.
Tests keyed to CSS classes, DOM nesting, or internal IDs break on every refactor without a real behavior change. Assert what the user perceives — visible text, roles, URLs.
A fixture that mutates shared module state, or assumes another test ran first, fails the moment tests parallelize or run in isolation. Each fixture must stand alone.
data-testid where getByRole would workSprinkling test ids onto buttons and headings that already have an accessible name skips the cheapest accessibility signal you get for free. Reserve getByTestId for elements with no stable role/label.
The most damaging runtime mistake — synchronizing with waitForTimeout instead of an auto-waiting locator:
// BAD — slow on fast machines, flaky on slow ones, hides the real condition
await page.waitForTimeout(2000);
await page.click('#submit');
// GOOD — the action auto-waits for actionability
await page.getByRole('button', { name: 'Submit' }).click();The other nine code-level offenders (CSS over roles, page.* over locators, force: true, shared state, per-test login, locator.all() without a stability check, allTextContents() over toHaveText(), hitting real third-party services, committed test.only) are in references/anti-patterns.md.
Run these against the generated artifact, smallest first:
npx playwright test --list # tests are discovered and parse
grep -rn 'waitForTimeout\|page.pause' e2e/ # must print nothing
npx tsc --noEmit # locator/assertion types compileEnforce the "never do X" rules in CI with eslint-plugin-playwright — rules no-wait-for-timeout, no-force-option, no-element-handle, no-page-pause turn this skill's prose bans into a failing lint.
playwright.config.ts exists with projects for at least Chromium (Firefox + WebKit added when targeting CI), and forbidOnly: !!process.env.CI.e2e/pages/ (or equivalent), with component objects composed via a root Locator and no expect inside POM methods.grep -rn 'waitForTimeout' e2e/ returns nothing, and eslint-plugin-playwright's no-wait-for-timeout is enabled.getByRole / getByLabel / getByTestId — grep -rn 'page.locator(\|xpath=\|css=' e2e/ returns nothing (or only justified, commented exceptions).growing+ maturity it shards across matrix jobs with the blob reporter and a merge-reports step, uploading the HTML report as an artifact on failure.toHaveScreenshot check.APIRequestContext patterns.references/)| File | Purpose |
|---|---|
anti-patterns.md | BAD vs GOOD code pairs for every code-level mistake |
fixtures-and-projects.md | Auth fixtures, data fixtures, multi-env projects, composition |
selector-strategies.md | Locator decision tree, getByRole examples, stability scoring |
auth-patterns.md | storageState, multi-role, token seeding, session expiry |
multi-site-architecture.md | Shared fixtures, per-site config, monorepo patterns |
network-and-mocking.md | page.route, route.fetch, HAR, WebSocket, conditional routing |
debugging-and-triage.md | Trace viewer, flaky-test triage, retries, artifacts |
ci-recipes.md | Reporters, sharding + merge, --only-changed, browser caching, Docker |
© petrkindlmann, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 8 other files (references) in skills/playwright-automation of petrkindlmann/qa-skills.
Open the folder on GitHubat commit b3bb61b
Playwright Automation next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Playwright Automation this skillpetrkindlmann/qa-skills | 170 | — | ~5.5k | Automated safety check: Pass | MIT | |
| Playwright Testingchongdashu/vibejam-starter-pack | 149 | — | ~2.2k | Automated safety check: Pass | None | |
| Web Testing with Playwright and Vitestwithkynam/vibecode-pro-max-kit | 1.1k | — | ~892 | Automated safety check: Pass | Apache-2.0 | |
| Test CommanderEliasOulkadi/shokunin | 114 | — | ~3k | Automated safety check: Notes | MIT | |
| Playwright Testingchongdashu/vibejam-starter-pack | 149 | — | ~2.1k | Automated safety check: Pass | None | |
| Common Tasksidavidov13/agentic-playwright | 225 | — | ~2.5k | Automated safety check: Pass | MIT |
chongdashu/vibejam-starter-pack
Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y.
withkynam/vibecode-pro-max-kit
Covers web testing from unit to E2E, load, visual, accessibility and security checks, with Playwright, Vitest and k6 guides plus a Playwright setup script.
EliasOulkadi/shokunin
Generate unit, integration, E2E, and visual regression tests following the Testing Trophy methodology (80% integration).
chongdashu/vibejam-starter-pack
Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y.
idavidov13/agentic-playwright
Copy-paste AI prompt templates for common Playwright scaffold development tasks — adding page objects, functional/E2E/API tests, Zod schemas, factories, fixtures, and components.
cin12211/orca-q
Playwright E2E testing expert for browser automation, cross-browser testing, visual regression, network interception, and CI integration.
petrkindlmann/qa-skills
Test for WCAG 2.2 AA compliance with axe-core + Playwright, keyboard navigation audits, screen reader testing, ARIA pattern validation, and legal compliance mapping (ADA, EAA, Section 508).
petrkindlmann/qa-skills
Goal-driven E2E testing where a browser agent (Playwright MCP / computer-use) reads a natural-language goal and explores the app via the accessibility tree to assert outcomes — no pre-written script.
petrkindlmann/qa-skills
Use AI to write NEW test code from specs, PRDs, user stories, code diffs, bug reports, or OpenAPI specs.
petrkindlmann/qa-skills
Test REST and GraphQL APIs with Playwright APIRequestContext, Supertest, or standalone HTTP clients.
petrkindlmann/qa-skills
Design CI/CD pipelines that run test suites. An agent skill from petrkindlmann/qa-skills.
petrkindlmann/qa-skills
Test for regulatory compliance: GDPR/CMP consent verification, Google Consent Mode v2, Global Privacy Control (GPC), CCPA/US state opt-out, EU AI Act Article 50 transparency, Better Ads Standards…
Works with
Categories
Write production-grade Playwright tests in TypeScript: Page Object Model, fixtures, auto-waiting, user-facing locators, parallel execution, CI integration, sharding, and 2025-2026 feature awareness. Playwright Automation is an agent skill from petrkindlmann/qa-skills. Write production-grade Playwright tests in TypeScript: Page Object Model, fixtures, auto-waiting, user-facing locators, parallel execution, CI integration, sharding, and 2025-2026 feature awareness.
Playwright Automation fits situations like: new Playwright suite; playwright config. Not for: fixing one flaky test at runtime — use test-reliability.
Run `npx skills add petrkindlmann/qa-skills --skill playwright-automation -a claude-code`. Or copy the skill folder (skills/playwright-automation in petrkindlmann/qa-skills) into .claude/skills/playwright-automation in your project. Claude Code loads it when a task matches its description.
Run `npx skills add petrkindlmann/qa-skills --skill playwright-automation -a codex`. Or copy the skill folder (skills/playwright-automation in petrkindlmann/qa-skills) into .agents/skills/playwright-automation in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add petrkindlmann/qa-skills --skill playwright-automation -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/playwright-automation, .gemini/skills/playwright-automation, .github/skills/playwright-automation and .opencode/skills/playwright-automation in your project.
Going by SKILL.md and its folder, Playwright Automation needs the command-line tools its instructions call (npx and opencode) and credentials named TEST_USER_PASSWORD and API_TOKEN. Our summary lists: Node.js; A credential in API_TOKEN.
SKILL.md contains no URLs. Its commands use npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Playwright Automation is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.5k tokens (SKILL.md is roughly 22k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 25k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Playwright Automation: Playwright Testing (chongdashu/vibejam-starter-pack, 149 stars), Web Testing with Playwright and Vitest (withkynam/vibecode-pro-max-kit, 1.1k stars), Test Commander (EliasOulkadi/shokunin, 114 stars) and Playwright Testing (chongdashu/vibejam-starter-pack, 149 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
petrkindlmann (a GitHub user) maintains it in petrkindlmann/qa-skills, which has 170 GitHub stars. The repository holds 45 skills in this directory. The repository was last updated on June 10, 2026.
Source: petrkindlmann/qa-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.