| title | E2E testing |
|---|---|
| description | Per-package Playwright E2E infrastructure, local commands, CI policy, and anti-flake rules. |
End-to-end tests use Playwright directly (not Vitest browser mode). Each package that needs real-browser coverage owns its scenarios under packages/<name>/e2e/ and exposes an independent test:e2e script.
| Layer | Runner | Location | Purpose |
|---|---|---|---|
| Controller / unit | Vitest + happy-dom | packages/<name>/test/** |
State machines, events, cleanup, options |
| Alpine integration | Vitest + happy-dom | packages/<name>/test/** |
Store, magic, directive registration |
| Contract / packed consumer | Vitest | packages/<name>/test/**, test/** |
Published API and SSR-safe imports |
| E2E (real browser) | Playwright | packages/<name>/e2e/** |
Real markup, focus, keyboard, layout, browser APIs |
Vitest remains the default for fast feedback. Playwright is reserved for behavior that requires a real browser runtime.
e2e/
playwright.base.ts # shared config factory
fixtures.ts # shared fixtures + Alpine boot helper
server/ # deterministic fixture HTTP server
packages/<name>/
playwright.config.ts # package-owned Playwright project
e2e/
fixture/
index.html # minimal Alpine markup
main.ts # registers the package plugin
*.spec.ts # Playwright specs
Shared infrastructure lives at the repository root. Scenarios stay inside the owning package — there is no centralized e2e/packages/* directory.
# Install Chromium (required baseline)
pnpm run playwright:install
# Run every package project that defines playwright.config.ts
pnpm run test:e2e
# Run only packages affected by the current git diff
pnpm run test:e2e:affected
# Run one package independently
pnpm --filter @ailuracode/alpine-theme test:e2e
# Cross-browser + mobile matrix (scheduled / manual full run)
pnpm run playwright:install:all
pnpm run test:e2e:fullOpen the HTML report after a failure:
pnpm --filter @ailuracode/alpine-theme test:e2e:report- Create
packages/<name>/e2e/fixture/index.htmlandmain.ts. - Add specs under
packages/<name>/e2e/*.spec.ts. - Add
playwright.config.tsthat callsdefinePackagePlaywrightConfig()frome2e/playwright.base.ts. - Add
"test:e2e": "playwright test --config playwright.config.ts"to the packagepackage.json.
The shared fixture server bundles e2e/fixture/main.ts with esbuild, resolves workspace aliases from tsconfig.json, and serves /, /app.js, and /__health. Playwright starts and stops the server through webServer, so ports are not leaked between runs.
- Prefer roles and accessible names:
page.getByRole('button', { name: 'Save' }). - Use
data-testidonly when roles are insufficient. - Assert accessibility in E2E with role visibility/enabled checks; keep detailed ARIA contracts in happy-dom tests when DOM APIs are mocked.
- Avoid CSS classes, XPath, and positional selectors unless there is no semantic alternative.
- Rely on Playwright auto-waiting (
expect(locator)...,getByRole,click). - Do not use arbitrary
page.waitForTimeout(). - Use
waitForAlpineFixture()frome2e/fixtures.tsonly to gate initial Alpine boot (data-e2e-ready="true"). - Treat uncaught page errors as test failures (configured in shared fixtures).
- Keep fixtures minimal — one plugin, one page, deterministic markup.
- Reset state in HTML/fixture code, not by reloading storage manually in every spec.
- Run with
workers: 1in CI. - Use
retries: 2in CI only. - Capture
trace,screenshot, andvideoon failure (configured in the base config).
| Event | Browsers | Scope |
|---|---|---|
| Pull request | Chromium | Affected packages with Playwright projects |
master push / global tooling |
Chromium | All package E2E projects when infra changes |
| Weekly schedule | Chromium, Firefox, WebKit, Pixel 5 | Full matrix via E2E_BROWSER_PROFILE=full |
Failed CI runs upload packages/*/e2e/playwright-report/** and packages/*/e2e/test-results/** artifacts.
# Run headed locally
PWDEBUG=1 pnpm --filter @ailuracode/alpine-theme test:e2e
# UI mode
pnpm --filter @ailuracode/alpine-theme exec playwright test --config playwright.config.ts --uiWhen a spec fails locally:
- Open the HTML report (
test:e2e:report). - Inspect trace, screenshot, and video attachments.
- Re-run the single spec with
--debugor--headed.
packages/*/e2e/**/*.ts and e2e/**/*.ts are included in the root tsconfig.json. E2E specs are excluded from Vitest via vitest.config.ts exclude patterns.