Initial Commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# testing-dom: runner generics + matchers ambient + async-span hardening
|
||||
|
||||
**Package**: `@suaveplan/testing-dom`
|
||||
**Status**: PROPOSED
|
||||
**Type**: bug-fix
|
||||
|
||||
## Why
|
||||
|
||||
Three latent defects in `@suaveplan/testing-dom` block correct downstream typing and produce wrong observability data:
|
||||
|
||||
1. **Runner-generic erasure on the bun-test path.** `src/runner/bun-test.ts#fn<TArgs,TReturn>` returns `ReturnType<typeof bunMock>` — an opaque type. The vitest path returns `Mock` and (after this change) `RunnerMock<TArgs, TReturn>`. A consumer writing `const m = fn<[string], number>()` gets a typed callable under vitest and an opaque mock under bun-test, breaking the dual-runner contract.
|
||||
2. **jest-dom matchers have no ambient type augmentation.** `src/matchers/matchers.ts` calls `expect.extend(matchers)` at runtime but consumers see `Property 'toBeInTheDocument' does not exist` because the file never pulls in the `@testing-library/jest-dom` ambient module declaration.
|
||||
3. **`instrumented()` ends spans synchronously even for async fns.** Async-wrapped functions get a span duration of ~0 ms regardless of how long they actually run, corrupting every histogram. Plus `setupUser` hard-imports `vitest`, defeating the bun-test conditional path.
|
||||
|
||||
## What changes
|
||||
|
||||
- ADDED: `RunnerMock<TArgs, TReturn>` type alias — exported from `./runner/index.js`, `./runner/vitest.js`, `./runner/bun-test.js`, and the package barrel `./index.js`. Mirrors on both runner paths.
|
||||
- ADDED: `SpyHandle` re-export at the package barrel.
|
||||
- MODIFIED: `fn<TArgs,TReturn>()` (both runner paths) — now returns `RunnerMock<TArgs, TReturn>` carrying the precise call signature.
|
||||
- MODIFIED: `spy<T,K>()` and `stub<T,K>()` on the bun-test path — return `SpyHandle` (alias for `ReturnType<typeof bunSpyOn>`).
|
||||
- MODIFIED: `src/matchers/matchers.ts` — adds `import type {} from "@testing-library/jest-dom"` so the ambient module declaration ships with the side-effect import.
|
||||
- MODIFIED: `src/user/setup-user.ts` — routes `vi` through `../runner/index.js` instead of hard-importing `vitest`.
|
||||
- MODIFIED: `src/observability/instrumented.ts` — detects PromiseLike return values and ends the OTel span (and records the histogram) only after the promise settles.
|
||||
- MODIFIED: `openspec/specs/testing-dom/spec.md` — coverage gate raised from ≥95% to 100% to match `CLAUDE.md`'s pre-publish gate. Path reference updated from `packages/universal/testing-dom/` to `packages/dev/testing-dom/`.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Re-organising the runner barrel — the existing dual-runner conditional-exports shape is preserved.
|
||||
- Refactoring `instrumented()` away from `tracer.startActiveSpan` — keeping the same OTel surface, only fixing span lifetime.
|
||||
- Introducing a runner-detection helper inside `setupUser` — the runner adapter already exists.
|
||||
|
||||
## Verification approach
|
||||
|
||||
- `src/runner/runner.spec-conformance.test.ts` — pins `fn<TArgs,TReturn>()` typing on the vitest path AND symmetric typing on the bun-test path via `import type`; pins the `RunnerMock` / `SpyHandle` exports at both runner barrels and the package barrel. Uses `expectTypeOf`.
|
||||
- `src/matchers/matchers.spec-conformance.test.tsx` — pins `expectTypeOf(expect(el).toBeInTheDocument).toBeFunction()` etc., proving the ambient augmentation reached the consumer.
|
||||
- `src/user/setup-user.test.ts::"imports vi via the runner adapter (no direct vitest hard-import)"` — source-level guard against regression.
|
||||
- `src/observability/instrumented.test.ts::"ends span only after async fn settles (resolved)"` — observable timing assertion (`elapsed >= 10ms`).
|
||||
- `src/observability/instrumented.test.ts::"ends span only after async fn settles (rejected)"` and `"… (rejected with non-Error)"` — pin the rejection branch including `recordException` for non-Error throws.
|
||||
|
||||
## Migration impact
|
||||
|
||||
None — additive types and bug-fix-only behavioral change. Consumers that previously typed mocks with `ReturnType<typeof fn>` continue to compile.
|
||||
Reference in New Issue
Block a user