E2E testing
Playwright E2E testing
Section titled “Playwright E2E testing”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.
Test layers
Section titled “Test layers”| 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.
Layout
Section titled “Layout”e2e/ playwright.base.ts # shared config factory fixtures.ts # shared fixtures + Alpine boot helper server/ # deterministic fixture HTTP serverpackages/<name>/ playwright.config.ts # package-owned Playwright project e2e/ fixture/ index.html # minimal Alpine markup main.ts # registers the package plugin *.spec.ts # Playwright specsShared infrastructure lives at the repository root. Scenarios stay inside the owning package — there is no centralized e2e/packages/* directory.
Local commands
Section titled “Local commands”# Install Chromium (required baseline)pnpm run playwright:install
# Run every package project that defines playwright.config.tspnpm run test:e2e
# Run only packages affected by the current git diffpnpm run test:e2e:affected
# Run one package independentlypnpm --filter @ailuracode/alpine-theme test:e2e
# Cross-browser + mobile matrix (scheduled / manual full run)pnpm run playwright:install:allpnpm run test:e2e:fullOpen the HTML report after a failure:
pnpm --filter @ailuracode/alpine-theme test:e2e:reportAdding E2E to a package
Section titled “Adding E2E to a package”- 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.
Selectors and accessibility
Section titled “Selectors and accessibility”- 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.
Waiting policy
Section titled “Waiting policy”- 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).
Anti-flake rules
Section titled “Anti-flake rules”- 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).
CI policy
Section titled “CI policy”| 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.
Debugging
Section titled “Debugging”# Run headed locallyPWDEBUG=1 pnpm --filter @ailuracode/alpine-theme test:e2e
# UI modepnpm --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.
TypeScript
Section titled “TypeScript”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.
