Files
2026-05-27 23:29:53 +01:00

3.1 KiB

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`"ANDsrc/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)