11 KiB
11 KiB
Archived 2026-04-19: all tasks retroactively ticked; package shipped under universal/dev/testing.
1. Surface inventory & catalog setup
- 1.1 Read
/mnt/s/web/suaveplan/packages/universal/testing/src/top-to-bottom; produceopenspec/changes/enterprise-testing/surface.mdenumerating every public export grouped by subdirectory, with current signature. This is the preservation contract for the rewrite. - 1.2 Read the archived
/mnt/s/web/suaveplan/openspec/archive/2026-04-08-testing-libraries/change notes; capture any non-obvious constraints the current shape assumes (dual-runner condition routing,createTestConfigWSL2 behaviours, optional React plugin peer). - 1.3 Extend root
package.jsoncatalogs: addzod@^4.1.5tocatalogs.forms, createcatalogs.observabilitywith@opentelemetry/api@^1.9.0, addfast-check@^3.23.2andmitata@^1.0.34tocatalogs.testing. Runbun install, confirm lockfile updates cleanly.
2. Package skeleton
- 2.1 Create
packages/universal/testing/withpackage.json(version0.1.0,type: "module",sideEffects: false, dual-runnerexportsmap from design D5, external catalog deps only per spec "No@suaveplan/*workspace dependencies") - 2.2 Create
tsconfig.lib.jsonextending../../../tsconfig.base.jsonwithoutDir: ./distandinclude: ["src"] - 2.3 Create
vite.config.tsproducingpreserveModules: trueESM output so every source file maps to a dist file (required for subpath exports to resolve) - 2.4 Create
vitest.config.tsusing a minimal inline config (cannot self-referencecreateTestConfigyet — this is the package that defines it) - 2.5 Create
README.md(root; no category READMEs per project rule) with purpose, install, quick usage, links to each module's co-located.md - 2.6 Add
@suaveplan/testingrow toCLAUDE.mdpackage listing (when the section is re-populated) and toSTRUCTURE.yml(when the file exists)
3. Foundational primitives (context, errors, observability)
- 3.1 Implement
src/context/context.ts:ClockandRnginterfaces;defaultClock(readsDate.now/performance.now);cryptoRng(readscrypto.getRandomValues);seededRng(seed)(xorshift or similar deterministic) - 3.2 Co-locate
src/context/context.test.ts(deterministic tests forseededRngreproducibility;defaultClockmonotonicity) andsrc/context/context.md(≥ 200 words, simple + advanced examples) - 3.3 Co-locate
src/context/context.schemas.tswith Zod schemas forClock/Rngshapes (for callers who want to runtime-check they've passed a compatible object) - 3.4 Implement
src/errors/testing-error.ts:TestingErrorbase class + per-domain subclasses (ClockError,FixturesError,FactoryError,StoreError,HelpersError,BuilderError,ConfigError) as per design D2 - 3.5 Implement
src/errors/codes.ts: string-literal-union constants for everyTESTING.<DOMAIN>.<REASON>code used in the package - 3.6 Co-locate tests (
instanceofbranch coverage,cause/contextround-trip) +.mddocs +*.schemas.ts - 3.7 Implement
src/observability/tracer.tsandsrc/observability/with-observability.tsper design D4: counters, histograms, spans via@opentelemetry/api; span-only-for-iterative gate - 3.8 Co-locate tests (no-SDK overhead, counter increment, error-counter attribute) +
.mddocs
4. Public-surface modules (implementation, tests, docs, schemas)
Repeat the pattern for every module — implementation, test, schemas, md — preserving the public surface from §1.1:
- 4.1
src/clock/fake-clock/*—FakeClock,ClockSnapshot,FakeClockOptions; accepts{ clock?, rng?, signal? }; throwsClockError("TESTING.CLOCK.*", …); implementsClockinterface - 4.2
src/builders/request-builder/*—RequestBuilder,get/post/put/patch/del; state-machine transitions throwBuilderErroron invalid state - 4.3
src/builders/response-builder/*—ResponseBuilder,ok/created/noContent/badRequest/unauthorized/notFound/serverError - 4.4
src/factories/factory/*—defineFactory,Factory,BatchBuildResult,FactoryBuildOptions,FactoryDefaults,FactoryDefinition;traitsplugin surface per design D7's factory analogue;buildBatch(n, { signal })checks abort every 256 items - 4.5
src/fixtures/fixture-manager/*—FixtureManager,SetupAllResult,TeardownAllResult,FixtureDefinition,FixtureState,FixtureManagerPlugin;setupAll/teardownAllaccept{ signal }; plugin hooks fire around each fixture - 4.6
src/storage/memory-store/*—MemoryStore,MemoryStoreEvent,MemoryStoreStats,MemoryStoreOptions,StoreEntry; TTL expiry via injected clock; eviction sweeps honoursignal - 4.7
src/helpers/test-helpers.ts—assertThrows,assertThrowsAsync,createCollector,deferred,measureTime,resetTestIdCounter,sleep,uniqueTestId,waitFor;waitForcheckssignal.abortedevery poll; all reads of time/randomness routed through context - 4.8
src/constants/constants.ts—DEFAULT_CLOCK_OPTIONS,DEFAULT_HTTP_STATUS,DEFAULT_RESPONSE_LATENCY_MS,DEFAULT_STORE_OPTIONS,DEFAULT_WAIT_OPTIONS,MAX_FIXTURES,MAX_STORE_ENTRIES,MAX_TIMERS - 4.9
src/types/testing.types.ts— shared public types; co-locatetesting.types.md(types/ subdirectory requires.mdper project convention)
5. Runner and config subpaths
- 5.1
src/runner/vitest.ts— re-export vitest primitives under thedefaultcondition - 5.2
src/runner/bun-test.ts— bun-test shim exposing the same surface under thebuncondition - 5.3
src/runner/mocks.ts—spy,stub,fn,mock,fakeClock,restoreMocks,restoreTimersbacked by the host runner - 5.4
src/runner/index.ts— combined barrel for the default vitest path - 5.5
src/config/index.ts—createTestConfig()factory per design D9 - 5.6
src/config/vitest-config.ts— vitest config builder (pool: forks, polyfills, fileParallelism) - 5.7
src/config/bun-test-config.ts— bun-test config builder - 5.8
src/config/detect-environment.ts,src/config/detect-runner.ts— runner + environment detection - 5.9
src/setup/polyfills.ts— side-effecting module installing happy-dom-needed globals on WSL2 - 5.10
src/utils/index.ts— re-export every non-runner symbol for single-import convenience
6. Root barrel
- 6.1
src/index.ts— explicit named re-exports (noexport *) covering the full public surface; in the order of §1.1 so diffing against the surface inventory is trivial
7. Property-based tests (fast-check)
- 7.1
FakeClockarithmetic properties (advance + schedule commute within a tick, no timer duplication) - 7.2
RequestBuilder/ResponseBuilderstate-machine transitions (associativity of preset composition) - 7.3
Factorydeterminism under fixedrng - 7.4
MemoryStoreTTL expiry monotonicity + capacity-limit invariant - 7.5
waitForpolling correctness under arbitrary predicate schedules - 7.6
seededRngreproducibility (same seed → same sequence)
8. Benchmarks (mitata)
- 8.1
src/__benchmarks__/clock.bench.ts— FakeClock advance/schedule throughput - 8.2
src/__benchmarks__/builders.bench.ts— RequestBuilder and ResponseBuilder build throughput - 8.3
src/__benchmarks__/factory.bench.ts— Factory single build + batch build - 8.4
src/__benchmarks__/memory-store.bench.ts— set/get/evict under load - 8.5
src/__benchmarks__/helpers.bench.ts— waitFor overhead; assertThrows overhead - 8.6
src/__benchmarks__/observability.bench.ts— OTEL-wrapped vs unwrapped overhead comparison (enforces <5% in CI) - 8.7
benchmarks/baselines.json— initial baseline commit (reviewer-approved, separate from functional changes) - 8.8 CI script: run
mitata3×, take fastest, compare to baseline, fail >10% regression
9. Examples
- 9.1
examples/basic-usage.ts— runnable script usingFactory,FakeClock,waitFor - 9.2
examples/fixture-plugin.ts— runnable script registering aFixtureManagerPlugin - 9.3
examples/deterministic-factory.ts— runnable script demonstratingseededRngreproducibility - 9.4
examples/custom-clock.ts— runnable script swappingdefaultClockforFakeClockend-to-end - 9.5 Verify every example runs via
bun examples/<name>.tswithout error
10. Tree-shake and dep-graph guards
- 10.1
src/__tests__/tree-shake.test.ts— asserts that./uint/clock(for example) does not pullMemoryStore,RequestBuilder, orFactoryidentifiers into its built output - 10.2
src/__tests__/dep-graph.test.ts— readspackage.jsonand asserts no@suaveplan/*appears independencies,peerDependencies, ordevDependencies - 10.3
src/__tests__/no-disallowed.test.ts— grepssrc/forany,ts-ignore,ts-expect-error,TODO,FIXME,@deprecated,.skip,.only; fails on any match
11. Docs
- 11.1 Verify every implementation file has a sibling
.mdof ≥ 200 words, simple + advanced examples, API reference, implementation notes - 11.2 Rewrite
packages/universal/testing/README.mdwith purpose, install, quick usage, error-code index, observability reference, benchmark numbers, links to each module's.md - 11.3 Run a docs-coverage check script (inline in
scripts/or ad-hoc) confirming ≥ 90%
12. Security review
- 12.1 Invoke the
security-reviewskill on the final diff - 12.2 Address every finding (prototype pollution in
MemoryStore.set, ReDoS in any regex helper, payload bombs inFactory.buildBatch); re-run until clean - 12.3
bun auditclean — zero advisories introduced by catalog additions
13. Pre-publish gate + publish + archive
- 13.1
bunx turbo lint typecheck test --filter=@suaveplan/testinggreen (CLAUDE.md non-negotiable) - 13.2
bunx turbo test:coverage --filter=@suaveplan/testingmeets ≥ 95% statement + branch - 13.3
bunx turbo lint typecheckacross all catalogs reaching@suaveplan/testing— green (only@suaveplan/testingon genesis today; confirm build graph is clean) - 13.4
bun scripts/publish.ts --package @suaveplan/testing --dry-runproduces a sane diff - 13.5
bun scripts/publish.ts --package @suaveplan/testing— publish@suaveplan/testing@0.0.0to Verdaccio - 13.6
openspec validate enterprise-testing --type change— passes - 13.7 Fold the
specs/testing/spec.mddelta intoopenspec/specs/testing/spec.md(create) and move this change folder toopenspec/archive/<yyyy-mm-dd>-enterprise-testing/ - 13.8 Mark
@suaveplan/testing✅ Enterprise in the genesisREADME.md(when the file exists) and inopenspec/project.mdpackage taxonomy