59 lines
3.1 KiB
Markdown
59 lines
3.1 KiB
Markdown
# Capability Spec Delta: testing-e2e (testing-e2e-async-and-fixtures-hardening)
|
|
|
|
**Package**: `@suaveplan/testing-e2e`
|
|
**Status**: PROPOSED
|
|
|
|
## ADDED Requirements
|
|
|
|
### Requirement: `extendedTest.apiContext` is browser-free
|
|
|
|
The `apiContext` fixture in `extendedTest` SHALL NOT request the `browser` fixture from Playwright's dependency graph. Playwright spins up requested deps eagerly, so destructuring `browser` would launch a Chromium instance for every API-only test, blowing the per-suite startup budget.
|
|
|
|
#### Scenario: Source-level guard
|
|
|
|
- **WHEN** `src/fixtures/extended-test.ts` is parsed
|
|
- **THEN** the apiContext fixture body destructures an empty object AND its destructure list contains no `browser` token
|
|
|
|
#### Scenario: extendedTest export shape
|
|
|
|
- **WHEN** a consumer imports `extendedTest` from `@suaveplan/testing-e2e/fixtures`
|
|
- **THEN** the value is a callable Playwright test extension exposing `.extend(...)`
|
|
|
|
**Verified by:** `src/fixtures/extended-test.test.ts::"apiContext fixture does not destructure \`browser\`"` AND `src/fixtures/extended-test.test.ts::"extendedTest is exported as a Playwright test extension"`
|
|
|
|
---
|
|
|
|
### Requirement: `instrumented()` ends spans only after async fns settle
|
|
|
|
`instrumented(name, fn)` SHALL detect when the wrapped function returns a PromiseLike value and SHALL defer `span.end()` and the duration histogram record until the returned promise settles. On rejection, the span SHALL `recordException` (wrapping non-Error rejections in `new Error(String(reason))`) before ending. On resolution, the duration recorded SHALL reflect the wall-clock interval between invocation and settlement.
|
|
|
|
#### Scenario: async resolve
|
|
|
|
- **WHEN** the wrapped fn awaits ≥10ms before returning
|
|
- **THEN** the awaited result equals the inner return value AND the elapsed wall-clock time is ≥10ms
|
|
|
|
#### Scenario: async reject
|
|
|
|
- **WHEN** the wrapped async fn throws an `Error`
|
|
- **THEN** the returned promise rejects with the same error
|
|
|
|
#### Scenario: async reject with non-Error reason
|
|
|
|
- **WHEN** the wrapped async fn rejects with a string
|
|
- **THEN** the returned promise rejects with the same string AND `recordException` is invoked with a wrapped `Error`
|
|
|
|
**Verified by:** `src/observability/instrumented.test.ts::"ends span only after async fn settles (resolved)"` AND `src/observability/instrumented.test.ts::"ends span only after async fn settles (rejected)"` AND `src/observability/instrumented.test.ts::"ends span only after async fn settles (rejected with non-Error)"`
|
|
|
|
## MODIFIED Requirements
|
|
|
|
### Requirement: Coverage and docs gates
|
|
|
|
Istanbul statement + branch + function + line coverage across `packages/dev/testing-e2e/src/` (excluding `*.bench.ts`, `*.schemas.ts`, barrel `index.ts` files) MUST be 100% on every dimension. Every implementation file MUST have a sibling `.md` (≥ 200 words, simple + advanced examples).
|
|
|
|
#### Scenario: CI coverage gate
|
|
|
|
- **WHEN** `bunx turbo test:coverage --filter=@suaveplan/testing-e2e` runs
|
|
- **THEN** statement / branch / function / line coverage all = 100%
|
|
|
|
**Verified by:** CI gate (`bunx turbo test:coverage --filter=@suaveplan/testing-e2e` exits non-zero on regression)
|