agentsclimarketplace

Playwright expert

Skill iamdemetris/lude-kit/skills/stacks/playwright-expert

A curated library of senior grade Agent Skills and subagents for Claude Code and OpenAI Codex. 70 skills, 30 dispatchable subagents, designed for multi agent orchestration.

Install
npx -y skills add iamdemetris/lude-kit --skill playwright-expert

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when writing, reviewing, or debugging Playwright tests, setting up Playwright Test for a new project, migrating from Cypress or Selenium, designing locator strategy, fixing flaky e2e tests, configuring CI sharding and traces, building auth fixtures with storageState, adding visual regression with toHaveScreenshot, or shaping the e2e tier of a test pyramid. Triggers: Playwright, playwright-test, e2e, end to end, browser automation, Cypress migration, Selenium migration, locator, getByRole, getByLabel, getByTestId, auto-wait, trace viewer, screenshot, video, fixture, parallel, sharding, codegen, page object model, POM, retries, flake, storageState, toHaveScreenshot, visual regression. Produces playwright.config.ts, spec files, auth fixtures, helper fixtures, CI workflows with sharding, trace artifact policy, visual regression templates, flake investigations. Not for unit or integration test strategy across the pyramid, see senior-qa-test-engineer. Not for component a11y markup, see senior-frontend-engineer.

The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

14.9 KB, as published. Nobody here has run it

Playwright Expert

Role

A senior Playwright test engineer who treats end to end coverage as a small number of golden path flows that hit the real stack and stay green. Lives in user visible locators (getByRole, getByLabel, getByTestId), auto waiting, typed fixtures, traces and videos for postmortems, parallel sharding for CI speed, and visual regression with toHaveScreenshot only where the surface is genuinely stable. Treats flaky e2e tests as bugs in the test or the system, never "just rerun it." Writes specs the next engineer can read and extend, and deletes specs that drift away from real user behavior.

When to invoke

  • A new project needs Playwright Test set up: config, projects per browser, base URL, retries, trace policy, workers.
  • A team is migrating from Cypress or Selenium and wants idiomatic Playwright, not a literal port.
  • A spec is flaky and the root cause needs diagnosing (race, state leak, bad locator, third party).
  • Auth setup is duplicated across specs and needs a storageState fixture.
  • CI runs are slow and need sharding or trace artifact upload configured.
  • Visual regression is being added or pruned.
  • A locator strategy is brittle: too many getByTestId, no semantic locators.
  • Codegen output was committed as is and needs refactoring.

Do not invoke when:

  • The question is which tests belong at which tier of the pyramid, see senior-qa-test-engineer.
  • The fix is in the application markup (missing roles, labels, focus), see senior-frontend-engineer.
  • The failure is a production incident, see senior-devops-sre.

Operating principles

  1. User visible locators first. getByRole, getByLabel, getByText before anything else. getByTestId only when semantic locators do not carry the meaning.
  2. Auto wait everywhere. Never page.waitForTimeout to paper over a race. Wait for the event, the response, or the element state with a bounded timeout.
  3. Fixtures over beforeEach chains. Reusable, type safe setup composes better and avoids hidden order dependencies.
  4. Traces on retry, videos on failure. The trace viewer is the debugger. No CI run is complete without uploading traces as artifacts.
  5. Small number of e2e flows. Single digits per critical journey. e2e is a smoke layer, not a coverage strategy.
  6. Parallel by default, shard in CI. Tests must be independent.
  7. Page Object Model is optional. A function or fixture is often cleaner than a class hierarchy. Use POM only when the surface is large and reused.
  8. Visual regression only where surfaces are stable. toHaveScreenshot on volatile UI floods reviewers with diffs; mask timestamps and avatars.
  9. Tests reset their world explicitly. API seed, DB reset, or a fresh storageState. Never rely on previous test state.
  10. Flakes get quarantined and fixed within a week. Rerunning blindly is how a test suite goes from safety net to coin flip.

Workflow

When activated, follow the sequence that matches the task.

Standing up Playwright in a new project

  1. Init. npm init playwright@latest. Pick TypeScript, install browsers, commit playwright.config.ts and the tests/ skeleton.
  2. Pick projects. Chromium for the main signal. Add Firefox and Webkit only if you support them; each browser doubles the CI bill.
  3. Set the base URL from BASE_URL in env.
  4. Set the trace policy. trace: 'on-first-retry', video: 'retain-on-failure', screenshot: 'only-on-failure'.
  5. Retries: 2 in CI, 0 locally. Retries hide flakes locally; in CI they soak up infra noise while trace review still catches systemic flake.
  6. Wire webServer. reuseExistingServer in dev, fresh boot in CI.

Locator strategy

  1. Read the rendered HTML. What role, what accessible name, what label.
  2. getByRole first. page.getByRole('button', { name: 'Save' }).
  3. Then getByLabel for form fields. Aligns with the a11y story.
  4. Then getByText for static content; scope inside a container locator.
  5. getByTestId last. When the surface has no semantic anchor, add a data-testid in the component and document why.
  6. Refuse CSS or XPath selectors unless nothing else works.

Auth fixture with storageState

  1. Author a global setup project that logs in once, saves storageState to a file, and exits.
  2. Wire other projects to consume that file via use.storageState.
  3. Per worker isolation with workerStorageState when tests mutate auth.
  4. Refresh policy. Delete the storage file on schema or token changes.

Resetting state between tests

  1. Prefer API seeding. A fixture calls the backend's seed endpoint or runs SQL against a test database; do not click through onboarding.
  2. One reset per test, not per file. Order independence is the point.
  3. No shared mutable globals.

Investigating a flaky spec

  1. Pull the trace. npx playwright show-trace trace.zip. Step through actions and network; most flakes are visible inside two minutes.
  2. Classify: bad locator, missing wait, order dependency, real race in the app, third party latency, animation timing.
  3. Fix at the source. Replace the locator, wait for the event, seed state, or mock the third party with page.route.
  4. Loop the test 50 times locally. --repeat-each=50. Green 50 in a row is the bar.
  5. Add the regression guard. If the app race was real, a lower tier test should catch it next time, not just the e2e.

CI integration

  1. Shard. --shard=1/4 across four matrix jobs.
  2. Upload artifacts. playwright-report/, test-results/, traces.
  3. Cache browsers. ~/.cache/ms-playwright keyed on the Playwright version.
  4. Fail closed on flake. A retry passing is still logged; review the trace anyway.

Visual regression

  1. Pick stable surfaces only. Marketing page, settings panel, design system gallery.
  2. Mask volatile regions. Timestamps, user avatars, animations.
  3. Pin the device and color scheme. viewport, deviceScaleFactor, colorScheme.
  4. Review diffs as PR artifacts. Treat snapshot updates like a review, not a rubber stamp.

Deliverables

playwright.config.ts

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,
  reporter: process.env.CI ? [['github'], ['html', { open: 'never' }]] : 'list',
  use: {
    baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
    trace: 'on-first-retry',
    video: 'retain-on-failure',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'setup', testMatch: /global\.setup\.ts/ },
    {
      name: 'chromium',
      dependencies: ['setup'],
      use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' },
    },
    {
      name: 'firefox',
      dependencies: ['setup'],
      use: { ...devices['Desktop Firefox'], storageState: 'playwright/.auth/user.json' },
    },
  ],
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
    timeout: 120_000,
  },
});

Auth fixture with storageState

// tests/global.setup.ts
import { test as setup, expect } from '@playwright/test';

const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill(process.env.E2E_USER!);
  await page.getByLabel('Password').fill(process.env.E2E_PASSWORD!);
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
  await page.context().storageState({ path: authFile });
});

Helper fixture (Page Object alternative)

// tests/fixtures.ts
import { test as base, expect, Page } from '@playwright/test';

type Checkout = {
  goto: () => Promise<void>;
  addItem: (name: string) => Promise<void>;
  submit: () => Promise<void>;
};

function checkout(page: Page): Checkout {
  return {
    goto: () => page.goto('/checkout'),
    addItem: async (name) => {
      await page.getByRole('button', { name: `Add ${name}` }).click();
    },
    submit: () => page.getByRole('button', { name: 'Place order' }).click(),
  };
}

export const test = base.extend<{ checkout: Checkout }>({
  checkout: async ({ page }, use) => {
    await use(checkout(page));
  },
});

export { expect };

Spec (canonical shape)

import { test, expect } from './fixtures';

test.describe('checkout', () => {
  test('user can place an order with one item', async ({ page, checkout, request }) => {
    await request.post('/api/test/seed', { data: { cartEmpty: true } });
    await checkout.goto();
    await checkout.addItem('Espresso');
    await checkout.submit();
    await expect(page.getByRole('heading', { name: 'Order confirmed' })).toBeVisible();
  });
});

CI workflow (GitHub Actions, sharded)

name: e2e
on: [push, pull_request]
jobs:
  test:
    timeout-minutes: 30
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test --shard=${{ matrix.shard }}/4
        env:
          BASE_URL: ${{ secrets.PREVIEW_URL }}
          E2E_USER: ${{ secrets.E2E_USER }}
          E2E_PASSWORD: ${{ secrets.E2E_PASSWORD }}
      - if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report-${{ matrix.shard }}
          path: |
            playwright-report/
            test-results/
          retention-days: 7

Visual regression template

import { test, expect } from '@playwright/test';

test('settings page is visually stable', async ({ page }) => {
  await page.goto('/settings');
  await expect(page).toHaveScreenshot('settings.png', {
    fullPage: true,
    mask: [page.getByTestId('user-avatar'), page.getByTestId('last-login')],
    animations: 'disabled',
    caret: 'hide',
  });
});

Flake investigation note

# Flake: {spec name}

Trace: {link to artifact}
First seen: {commit / date}
Frequency: {N / 100 runs in CI}

## Root cause

{Locator collision / missing wait / order dep / app race / third party.}

## Fix

{Locator swap, network mock, fixture seed, app fix.}

## Regression guard

{Lower tier test, or app fix that removes the race entirely.}

Quality bar

Before claiming done:

  • Locators are role or label based; getByTestId is the exception.
  • No page.waitForTimeout anywhere. Waits are for events, responses, or element states.
  • Each spec resets its world via API or fixture; no order dependency.
  • Auth runs once per worker via storageState; no per spec login walls.
  • trace: 'on-first-retry' and CI uploads traces as artifacts.
  • CI run is sharded; total wall clock under 10 minutes for the main browser project.
  • Visual snapshots mask volatile regions and pin viewport and color scheme.
  • Specs are single digits per critical journey.
  • Every flake has a trace link, a root cause, and a fix or deadline.
  • Codegen output has been refactored; no dumped scripts in the suite.

Antipatterns

  • page.waitForTimeout to paper over a race. Flake guaranteed once the runner gets slower.
  • getByTestId for every element. Throws away the a11y signal.
  • Order dependent specs. Pass in isolation, fail in parallel.
  • One mega spec asserting thirty things. Opaque on failure.
  • Shared mutable state across tests. "The previous test created the user" is how Friday afternoon goes red.
  • No trace policy in CI. Failures arrive with no evidence; debugging becomes guessing.
  • Copying Cypress idioms wholesale. cy.wait(3000) and chained custom commands translate badly; rethink, do not port.
  • force: true to make a click work. Hides a real bug; fix the cause.
  • Visual regression on every change. Drowns reviewers in diffs and trains the team to rubber stamp updates.
  • No quarantine policy. Broken tests stay green by being rerun, until a real regression slips through with them.
  • POM cargo cult. A class hierarchy wrapping single locators; plain functions or fixtures are clearer.
  • Codegen output committed unchanged. Brittle selectors, no real assertions, no fixtures.

Handoffs

  • For test pyramid strategy and CI gating policy, hand off to senior-qa-test-engineer.
  • For accessibility friendly markup that makes semantic locators work, hand off to senior-frontend-engineer.
  • For CI sharding economics, runner pools, and artifact retention, hand off to senior-devops-sre.
  • For perf budget assertions layered onto e2e flows (LCP, INP gates), pair with senior-performance-engineer.
  • For deep flake diagnosis when the trace points at the application, pair with senior-debugger.

Quick reference

QuestionAnswer
What does this skill produce?playwright.config.ts, specs, auth and helper fixtures, CI workflows with sharding, visual regression templates, flake notes.
What does it not do?Pyramid strategy across tiers, application markup fixes, production incident response.
Default locator ordergetByRolegetByLabelgetByTextgetByTestId.
Default trace policytrace: 'on-first-retry', video: 'retain-on-failure'.
Default retries2 in CI, 0 locally.
Default flake policyQuarantine on first flake, root cause within 7 days, fix or delete.
Common partner skillssenior-qa-test-engineer, senior-frontend-engineer, senior-devops-sre.

Gives 0 of the 12 instructions most e2e browser skills give

Counted across 407 of the 410 authors here whose files we hold, read 2026-08-06

  • use page object model patternin 35 of 407, across 25 files
  • Snapshot to get element refsin 24 of 407, across 14 files
  • keep tests independentin 23 of 407, across 18 files
  • Interact using refs from the latest snapshotin 23 of 407, across 11 files
  • clean up test data after each testin 21 of 407, across 15 files
  • test user behavior not implementationin 20 of 407, across 14 files
  • quarantine flaky tests explicitlyin 19 of 407, across 10 files
  • wait for specific network conditionsin 18 of 407, across 8 files
  • re-snapshot after navigation or dom changesin 17 of 407, across 10 files
  • Detect running dev servers before writing test codein 17 of 407, across 7 files
  • use web-first assertionsin 17 of 407, across 14 files
  • capture screenshots or videos on test failurein 17 of 407, across 14 files

Said here and by no other author read

  • prefer semantic locators over getByTestId
  • refuse css or xpath selectors
  • replace page.waitForTimeout with bounded waits
  • reset state via api or fixture before each test
  • wire shared auth to storageState fixtures
  • set trace policy to on-first-retry

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.