Claude Code Prompts for Playwright E2E Tests

Copy-paste Claude Code prompts for Playwright — writing stable role-based selectors, killing flaky tests, network-mocking, and visual-regression baselines.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Playwright tests are flaky for three reasons: brittle selectors, hardcoded waits, and unstable network. The prompts below force Claude to write tests that hold up under CI variance.

Prompt 1 — Write a robust login + create-resource flow

Write a Playwright test at tests/e2e/projects-create.spec.ts that:
1. Logs in as the seeded test user (use the existing 'authenticatedUser' fixture
   from tests/fixtures/auth.ts — read it first).
2. Navigates to /projects/new.
3. Fills name + description, picks visibility=private, submits.
4. Asserts the URL is /projects/.
5. Asserts the project name appears in the page heading.
6. Cleans up by deleting via API (use the apiClient fixture).

Constraints:
- getByRole / getByLabel only. NEVER CSS selectors.
- NO page.waitForTimeout. Use auto-wait via web-first assertions.
- await expect(page.getByRole('heading', { name: 'My project' })).toBeVisible()
  is the only correct pattern.
- Network: do not mock; this is an integration test against the local server.
- Place the test in the 'authenticated' project group in playwright.config.ts.

Prompt 2 — Anti-flake refactor of an existing test

tests/e2e/checkout.spec.ts has flake rate ~12% on CI. Read it.

Identify each potential flake source:
- page.waitForTimeout(...) calls
- selectors that depend on element index (.nth(2), .first()) where order
  could vary
- assertions on non-deterministic text (timestamps, counts)
- network state that depends on prior test leakage
- click followed by assertion on the same element (race with rerender)

For each issue, propose the smallest fix:
- Replace waitForTimeout with the actual condition (toBeVisible, toHaveURL).
- Replace .nth() with a getByRole that filters by accessible name.
- Stabilise timestamps via fixed clock: await page.clock.install({ time: ... }).
- Reset DB state in beforeEach via the seedDatabase fixture.

Output as a unified diff. Run the test 20× in your head and confirm each path
is deterministic now.

Prompt 3 — Mock a flaky third-party API

The /signup test occasionally fails because it calls the real Stripe API in
test mode and the Stripe sandbox is slow. Mock Stripe.

Constraints:
- Use page.route('**/api.stripe.com/**', async route => route.fulfill({
  status: 200, json:  }))
- Fixtures live in tests/fixtures/stripe/. Read the existing ones — match
  filenames like checkout-session.created.json.
- Mock at the test fixture level (define a 'stripeMocked' fixture in
  tests/fixtures/index.ts) so the same setup is reusable.
- For tests that DO need real Stripe (the contract test in
  tests/contracts/), exclude them from the mock fixture.
- Confirm the mock fires by asserting route.request().url() includes 'stripe'
  in a sentinel test.

CLAUDE.md for Playwright

## Playwright policy
- Selectors: getByRole / getByLabel / getByPlaceholder / getByTestId.
  Never CSS, never XPath.
- No page.waitForTimeout. Use web-first assertions (toBeVisible, toHaveText,
  toHaveURL) which auto-wait up to expect timeout.
- Tests are independent. Each beforeEach reseeds. No relying on test order.
- Network: mock external APIs (Stripe, Postmark) via page.route. Local API
  is real.
- One assertion per logical step. No assertion-free clicks.

Related: testing prompts.

Frequently asked questions

Will Claude write CSS selectors or role selectors?
Default is role-based (getByRole, getByLabel). If your codebase has heavy CSS selectors, Claude will mimic them — but that's the wrong default. State `getByRole / getByLabel / getByTestId only. Never CSS or XPath selectors.` in CLAUDE.md.
How do I get Claude to write tests that don't flake?
Use the anti-flake prompt below — it bans hardcoded waits, requires auto-wait assertions (toHaveText, toBeVisible), and pins the network state with route mocking.
Page Object Model or not?
Tell Claude. The prompts below use fixtures + helpers, not POM. If your team uses POM, say `Tests use the Page Object Model — page objects live in tests/pages/.` Claude will follow either pattern.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript