A working end-to-end test suite you can run today, plus a repo layout that Claude Code can extend on its own. It tests the public demo store saucedemo.com — login, cart, and checkout flows — using TypeScript and the Page Object Model.
- Node.js 18+ and npm
- Claude Code installed (
npm install -g @anthropic-ai/claude-code), if you want Claude to drive this repo from your terminal
playwright-e2e-sample/
├── CLAUDE.md # context Claude Code reads automatically
├── playwright.config.ts # browsers, retries, reporters, base URL
├── eslint.config.mjs # flat config: typescript-eslint + Playwright rules
├── global-setup.ts # logs in once, saves storageState for reuse
├── pages/ # Page Objects (locators + actions)
│ ├── LoginPage.ts
│ ├── InventoryPage.ts
│ ├── CartPage.ts
│ └── CheckoutPage.ts
├── fixtures/
│ ├── pageFixtures.ts # injects Page Objects into `test`
│ └── testData.ts # shared users/credentials
├── tests/
│ ├── login.spec.ts
│ ├── cart.spec.ts
│ ├── checkout.spec.ts
│ └── accessibility.spec.ts # axe-core scans on key pages
├── allure/
│ └── config.ts # Allure environment info + defect categories
├── scripts/
│ ├── report-flaky.js # flags retried tests in the CI job summary
│ ├── strip-language-label.js # drops the redundant "language" chip
│ └── brand-allure-report.js # wordmark/favicon/tab-title branding
└── .github/workflows/playwright.yml
If you're starting a brand-new project rather than using this sample, this is the sequence:
mkdir my-e2e-suite && cd my-e2e-suite
npm init -y
npm init playwright@latest # scaffolds config, an example test, and CIThe npm init playwright@latest wizard asks: TypeScript or JavaScript,
test folder name, whether to add a GitHub Actions workflow, and whether to
install browsers now. This sample already answers all of those, so you can
skip the wizard and just run the install step below.
cd playwright-e2e-sample
npm install
npx playwright install --with-deps # downloads Chromium/Firefox/WebKit
npm test # run everything, headless, all 4 projects
npm run test:ui # interactive UI mode — best for authoring/debugging
npm run test:headed # watch the browser while it runs
npx playwright show-reportA passing run produces playwright-report/ (HTML report with traces,
screenshots, and video on failure) and test-results/.
Every run also writes raw results to allure-results/ via the
allure-playwright reporter. To view them as an Allure report (requires a
Java runtime locally; GitHub Actions runners already
have one):
npm run report:allure:generate # builds allure-report/ from allure-results/
npm run report:allure:open # serves it in a browserEvery merge to main also publishes the merged Allure report to
https://gunashekarryml.github.io/playwright-e2e/ automatically — see
.github/workflows/playwright.yml.
npm run report:allure:generate does three things in sequence (see the
script chain in package.json):
scripts/strip-language-label.jsremoves thelanguage: javascriptlabelallure-playwrightstamps on every result (it has no config option to disable it) — one less redundant chip on every test page.allure generatebuilds the report, reading:allure/config.ts→environment.properties(Environment tab) andcategories.json(Categories tab: Product defects / Test-framework defects / Environment issues / Ignored), wired in via theallure-playwrightreporter'senvironmentInfo/categoriesoptions inplaywright.config.ts.executor.json, written by a CI-only step inplaywright.yml(build number, link back to the GitHub Actions run, link to the published Pages report) — powers the Executions widget.
scripts/brand-allure-report.jsinjects a small "Code & Theory" wordmark, a monogram favicon, and a custom tab title via a linkedcustom/custom.css— deliberately CSS-only and scoped tobody/ scrollbar selectors rather than Allure's internal (minified, versioned) component classes, so it keeps working across Allure upgrades.
To swap the text wordmark for a real logo, drop assets/logo.svg or
assets/logo.png into the repo — the branding script already copies it
into the report's custom/ folder; reference it from custom.css to
replace the body::before text with an <img>/background-image. Override
the wordmark text or accent color without code changes via
ALLURE_BRAND_NAME / ALLURE_BRAND_ACCENT env vars.
- Smoke vs. full regression — pull requests run only tests tagged
@smoke(fast feedback); pushes tomain, the nightly cron, and manual runs (suite: full) run everything. Tag a test with a second argument —test('...', { tag: '@smoke' }, async (...) => { ... })— to add it to the fast gate. Run the same subset locally withnpm run test:smoke. - Authenticated session reuse —
global-setup.tslogs in once asstandard_userand savesstorageState;cart.spec.tsandcheckout.spec.tsreuse it (test.use({ storageState: ... })) instead of repeating the login flow in every test.login.spec.tsitself stays unauthenticated since it's testing the login flow. - Accessibility checks —
accessibility.spec.tsruns an axe-core scan against login/inventory/cart/checkout and fails on anycriticalorseriousviolation (SauceDemo's few pre-existingmoderateissues are left as-is rather than chased). - Flaky-test visibility —
scripts/report-flaky.jsreads the JSON reporter output after each run and lists any test that only passed after a retry in that job's summary, so retries don't silently hide flakiness. - Lint & type-check gate — a standalone
lintjob runstsc --noEmitandnpm run lint(ESLint, flat config ineslint.config.mjs) on every push/PR, independently of the browser test matrix. It combinestypescript-eslint's type-aware rules witheslint-plugin-playwright(catches missingawaits, focused/skipped tests left in by accident,page.waitForTimeoutusage, etc.). Run it locally withnpm run lint(ornpm run lint:fixfor auto-fixable issues).
CLAUDE.md in this repo tells Claude the folder conventions (Page Object
pattern, where fixtures live, how specs should import test/expect) so
generated code matches the existing style instead of reinventing it. Point
Claude Code at this folder and it can:
- Generate new tests from a description — "Add a spec that verifies the cart persists after a page reload" — Claude reads the existing Page Objects and fixtures first, then writes a spec that fits the pattern.
- Turn a recorded flow into a test — run
npm run codegento record clicks in a real browser, paste the generated code to Claude, and ask it to refactor that into a Page Object + spec. - Debug a failing/flaky test — point Claude at the trace file Playwright
writes on failure (
npx playwright show-trace test-results/.../trace.zip) or just ask it to runnpx playwright test --debugand reason about the output. - Keep the suite in sync with UI changes — paste a diff or describe a UI change, and ask Claude to update the affected Page Object's locators.
- Extend CI — ask Claude to add sharding, a nightly cron run, or Slack
notifications to
.github/workflows/playwright.yml.
Example prompts are listed at the bottom of CLAUDE.md.
npm run mcp:playwright starts the Playwright MCP server
(@playwright/mcp, launched on demand via npx — no install step). It's a
plain Model Context Protocol server with
no dependency on any specific AI tool or vendor — it lets any MCP client
drive a real, visible browser directly (navigate, click, fill forms, read
the accessibility tree) instead of writing a throwaway script just to see
what a page looks like. It's independent of this repo's own
playwright.config.ts/test suite; think of it as a live "hands on the
keyboard" tool for exploring SauceDemo, debugging a selector, or sanity
checking a flow before turning it into a Page Object + spec, complementing
npm run codegen.
To use it, point your MCP client of choice at the same command
(npx -y @playwright/mcp@latest, or npm run mcp:playwright from this
directory) in whatever config format that client expects, for example:
- Claude Code:
claude mcp add playwright -- npx -y @playwright/mcp@latest(or add it to a project's own.mcp.jsonif you want it checked in and shared with a team) - Cursor: add the same command under
mcpServersin.cursor/mcp.json - VS Code (Copilot): add it under
serversin.vscode/mcp.json
It can also run as a standalone network server instead of being spawned
per-client — npx @playwright/mcp@latest --port 8931 starts it listening
over SSE/HTTP, so multiple MCP clients (or machines) can connect to the
same instance; add --shared-browser-context to have them share one
browser instead of each getting their own.
- Change
use.baseURLinplaywright.config.ts(or setBASE_URLenv var). - Replace
pages/*.tswith Page Objects for your app's screens. - Replace
fixtures/testData.tswith your own test accounts/data — never commit real production credentials; use a.envfile (already gitignored) andprocess.envfor anything sensitive. - Update selectors to prefer accessible queries (
getByRole,getByLabel) or stabledata-testidattributes your app exposes.
SauceDemo intentionally ships a few broken users for testing error paths:
locked_out_user (blocked), problem_user (broken images/UI), and
performance_glitch_user (slow responses) — useful for practicing
resilient locators and negative-path tests.