89 lines
4.3 KiB
Markdown
89 lines
4.3 KiB
Markdown
## Context
|
|
|
|
`@suaveplan/testing-e2e` is the third Layer 0 testing-infrastructure package on genesis. It wraps Playwright with conventions, page objects, and a config factory.
|
|
|
|
Layer 0 dependency profile: external catalog deps only. No `@suaveplan/*` workspace deps in runtime closure. `@suaveplan/testing` permitted as `devDependency` for the package's own tests.
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
|
|
- Thin, conventional Playwright wrapper. No forking of Playwright internals.
|
|
- `createPlaywrightConfig()` absorbs WSL2 + CI defaults so every consumer gets stable runs without copy-paste.
|
|
- `PageObject` base class for the typed page-object pattern.
|
|
- Local `TestingE2eError` hierarchy with stable `TESTING_E2E.<DOMAIN>.<REASON>` codes.
|
|
- ≥ 95% coverage on every dimension; co-located unit tests + cross-cutting `tests/` per the genesis test-placement hard rule.
|
|
|
|
**Non-Goals:**
|
|
|
|
- A full Playwright re-implementation. We re-export, we don't rebuild.
|
|
- Browser launching automation. Playwright already handles that; we expose its config.
|
|
- React-specific helpers. Those live in `@suaveplan/testing-dom`.
|
|
- Real-browser E2E tests of the package itself — the unit tests for our helpers run under vitest with happy-dom; real Playwright E2E of the package would be circular and impractical.
|
|
|
|
## Decisions
|
|
|
|
### D1: Local `TestingE2eError` hierarchy
|
|
|
|
Mirrors the shape from `@suaveplan/testing` and `@suaveplan/testing-dom`. Subclasses: `NavigationError`, `WaitTimeoutError`, `ConfigError`, `FixtureError`, `AbortedError`. Codes follow `TESTING_E2E.<DOMAIN>.<REASON>` pattern.
|
|
|
|
### D2: `createPlaywrightConfig(options)`
|
|
|
|
Factory accepting `{ baseURL, projects, reporter, ...overrides }` and returning a `PlaywrightTestConfig`:
|
|
|
|
- `fullyParallel: false` by default (WSL2 stability)
|
|
- `forbidOnly: !!process.env.CI`
|
|
- `retries: process.env.CI ? 2 : 0`
|
|
- `workers: process.env.CI ? 1 : undefined`
|
|
- `use.trace: "on-first-retry"`
|
|
- `use.screenshot: "only-on-failure"`
|
|
- `use.video: "retain-on-failure"`
|
|
- Caller can override every default via `options`.
|
|
|
|
### D3: `PageObject` base class
|
|
|
|
```ts
|
|
export abstract class PageObject {
|
|
constructor(protected readonly page: Page) {}
|
|
abstract readonly path: string;
|
|
async navigate(): Promise<void> { ... }
|
|
async waitForReady(opts?: { signal? }): Promise<void> { ... }
|
|
findByRole(role, options?): Locator { ... }
|
|
findByLabel(text): Locator { ... }
|
|
findByText(text): Locator { ... }
|
|
}
|
|
```
|
|
|
|
Extension by composition: subclasses add typed locators and domain methods.
|
|
|
|
### D4: Test fixtures via Playwright's `test.extend`
|
|
|
|
`extendedTest` exposes:
|
|
|
|
- `apiContext`: a `request` instance auto-created per test
|
|
- `freshPage`: a new browser context + page (isolated from any auth fixtures)
|
|
- `defaultTimeout`: configurable per-suite default
|
|
|
|
### D5: Helpers
|
|
|
|
- `waitForNetworkIdle(page, opts?)` — wait until N consecutive ticks with no in-flight requests
|
|
- `screenshotOnFailure(testInfo, page)` — manual fallback for non-fixture-driven captures
|
|
- `dismissDialog(page)` — registers a one-shot dialog handler
|
|
- `mockGeolocation(page, coords)` — install a geolocation override via context.grantPermissions + setGeolocation
|
|
- `mockClipboard(page)` — install a programmatic clipboard via `page.evaluate`
|
|
|
|
### D6: OTEL gated behind env flag
|
|
|
|
Same pattern as testing-dom: counters/histograms behind `process.env.TESTING_E2E_OTEL_ENABLED === "1"`.
|
|
|
|
### D7: Tests run under vitest (not Playwright)
|
|
|
|
Counter-intuitive but correct: testing-e2e is a LIBRARY exposing Playwright helpers. Its OWN unit tests run under vitest because vitest is faster and the helpers themselves don't need a real browser. We test the typed shapes, error throws, config defaults, etc. Real Playwright tests live in app packages that consume testing-e2e.
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- **Playwright version churn** — major Playwright bumps occasionally change `PlaywrightTestConfig` shapes. Mitigation: pin via catalog; bump deliberately.
|
|
- **Page-object generality** — a one-size base class can't anticipate every consumer's pattern. Mitigation: keep `PageObject` minimal; document the intended subclassing pattern.
|
|
- **Helpers tested under vitest, not Playwright** — covers shape but not real-browser behavior. Mitigation: mark helpers as "best effort" in docs; recommend integration tests in consumer apps.
|
|
- **`devDependency on @suaveplan/testing`** — same as testing-dom; documented exception.
|