Initial Commit
This commit is contained in:
115
openspec/archive/2026-04-19-enterprise-testing/tasks.md
Normal file
115
openspec/archive/2026-04-19-enterprise-testing/tasks.md
Normal file
@@ -0,0 +1,115 @@
|
||||
> Archived 2026-04-19: all tasks retroactively ticked; package shipped under universal/dev/testing.
|
||||
|
||||
## 1. Surface inventory & catalog setup
|
||||
|
||||
- [x] 1.1 Read `/mnt/s/web/suaveplan/packages/universal/testing/src/` top-to-bottom; produce `openspec/changes/enterprise-testing/surface.md` enumerating every public export grouped by subdirectory, with current signature. This is the preservation contract for the rewrite.
|
||||
- [x] 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, `createTestConfig` WSL2 behaviours, optional React plugin peer).
|
||||
- [x] 1.3 Extend root `package.json` catalogs: add `zod@^4.1.5` to `catalogs.forms`, create `catalogs.observability` with `@opentelemetry/api@^1.9.0`, add `fast-check@^3.23.2` and `mitata@^1.0.34` to `catalogs.testing`. Run `bun install`, confirm lockfile updates cleanly.
|
||||
|
||||
## 2. Package skeleton
|
||||
|
||||
- [x] 2.1 Create `packages/universal/testing/` with `package.json` (version `0.1.0`, `type: "module"`, `sideEffects: false`, dual-runner `exports` map from design D5, external catalog deps only per spec "No `@suaveplan/*` workspace dependencies")
|
||||
- [x] 2.2 Create `tsconfig.lib.json` extending `../../../tsconfig.base.json` with `outDir: ./dist` and `include: ["src"]`
|
||||
- [x] 2.3 Create `vite.config.ts` producing `preserveModules: true` ESM output so every source file maps to a dist file (required for subpath exports to resolve)
|
||||
- [x] 2.4 Create `vitest.config.ts` using a minimal inline config (cannot self-reference `createTestConfig` yet — this is the package that defines it)
|
||||
- [x] 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`
|
||||
- [x] 2.6 Add `@suaveplan/testing` row to `CLAUDE.md` package listing (when the section is re-populated) and to `STRUCTURE.yml` (when the file exists)
|
||||
|
||||
## 3. Foundational primitives (context, errors, observability)
|
||||
|
||||
- [x] 3.1 Implement `src/context/context.ts`: `Clock` and `Rng` interfaces; `defaultClock` (reads `Date.now` / `performance.now`); `cryptoRng` (reads `crypto.getRandomValues`); `seededRng(seed)` (xorshift or similar deterministic)
|
||||
- [x] 3.2 Co-locate `src/context/context.test.ts` (deterministic tests for `seededRng` reproducibility; `defaultClock` monotonicity) and `src/context/context.md` (≥ 200 words, simple + advanced examples)
|
||||
- [x] 3.3 Co-locate `src/context/context.schemas.ts` with Zod schemas for `Clock` / `Rng` shapes (for callers who want to runtime-check they've passed a compatible object)
|
||||
- [x] 3.4 Implement `src/errors/testing-error.ts`: `TestingError` base class + per-domain subclasses (`ClockError`, `FixturesError`, `FactoryError`, `StoreError`, `HelpersError`, `BuilderError`, `ConfigError`) as per design D2
|
||||
- [x] 3.5 Implement `src/errors/codes.ts`: string-literal-union constants for every `TESTING.<DOMAIN>.<REASON>` code used in the package
|
||||
- [x] 3.6 Co-locate tests (`instanceof` branch coverage, `cause` / `context` round-trip) + `.md` docs + `*.schemas.ts`
|
||||
- [x] 3.7 Implement `src/observability/tracer.ts` and `src/observability/with-observability.ts` per design D4: counters, histograms, spans via `@opentelemetry/api`; span-only-for-iterative gate
|
||||
- [x] 3.8 Co-locate tests (no-SDK overhead, counter increment, error-counter attribute) + `.md` docs
|
||||
|
||||
## 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:
|
||||
|
||||
- [x] 4.1 `src/clock/fake-clock/*` — `FakeClock`, `ClockSnapshot`, `FakeClockOptions`; accepts `{ clock?, rng?, signal? }`; throws `ClockError("TESTING.CLOCK.*", …)`; implements `Clock` interface
|
||||
- [x] 4.2 `src/builders/request-builder/*` — `RequestBuilder`, `get`/`post`/`put`/`patch`/`del`; state-machine transitions throw `BuilderError` on invalid state
|
||||
- [x] 4.3 `src/builders/response-builder/*` — `ResponseBuilder`, `ok`/`created`/`noContent`/`badRequest`/`unauthorized`/`notFound`/`serverError`
|
||||
- [x] 4.4 `src/factories/factory/*` — `defineFactory`, `Factory`, `BatchBuildResult`, `FactoryBuildOptions`, `FactoryDefaults`, `FactoryDefinition`; `traits` plugin surface per design D7's factory analogue; `buildBatch(n, { signal })` checks abort every 256 items
|
||||
- [x] 4.5 `src/fixtures/fixture-manager/*` — `FixtureManager`, `SetupAllResult`, `TeardownAllResult`, `FixtureDefinition`, `FixtureState`, `FixtureManagerPlugin`; `setupAll`/`teardownAll` accept `{ signal }`; plugin hooks fire around each fixture
|
||||
- [x] 4.6 `src/storage/memory-store/*` — `MemoryStore`, `MemoryStoreEvent`, `MemoryStoreStats`, `MemoryStoreOptions`, `StoreEntry`; TTL expiry via injected clock; eviction sweeps honour `signal`
|
||||
- [x] 4.7 `src/helpers/test-helpers.ts` — `assertThrows`, `assertThrowsAsync`, `createCollector`, `deferred`, `measureTime`, `resetTestIdCounter`, `sleep`, `uniqueTestId`, `waitFor`; `waitFor` checks `signal.aborted` every poll; all reads of time/randomness routed through context
|
||||
- [x] 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`
|
||||
- [x] 4.9 `src/types/testing.types.ts` — shared public types; co-locate `testing.types.md` (types/ subdirectory requires `.md` per project convention)
|
||||
|
||||
## 5. Runner and config subpaths
|
||||
|
||||
- [x] 5.1 `src/runner/vitest.ts` — re-export vitest primitives under the `default` condition
|
||||
- [x] 5.2 `src/runner/bun-test.ts` — bun-test shim exposing the same surface under the `bun` condition
|
||||
- [x] 5.3 `src/runner/mocks.ts` — `spy`, `stub`, `fn`, `mock`, `fakeClock`, `restoreMocks`, `restoreTimers` backed by the host runner
|
||||
- [x] 5.4 `src/runner/index.ts` — combined barrel for the default vitest path
|
||||
- [x] 5.5 `src/config/index.ts` — `createTestConfig()` factory per design D9
|
||||
- [x] 5.6 `src/config/vitest-config.ts` — vitest config builder (pool: forks, polyfills, fileParallelism)
|
||||
- [x] 5.7 `src/config/bun-test-config.ts` — bun-test config builder
|
||||
- [x] 5.8 `src/config/detect-environment.ts`, `src/config/detect-runner.ts` — runner + environment detection
|
||||
- [x] 5.9 `src/setup/polyfills.ts` — side-effecting module installing happy-dom-needed globals on WSL2
|
||||
- [x] 5.10 `src/utils/index.ts` — re-export every non-runner symbol for single-import convenience
|
||||
|
||||
## 6. Root barrel
|
||||
|
||||
- [x] 6.1 `src/index.ts` — explicit named re-exports (no `export *`) 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)
|
||||
|
||||
- [x] 7.1 `FakeClock` arithmetic properties (advance + schedule commute within a tick, no timer duplication)
|
||||
- [x] 7.2 `RequestBuilder` / `ResponseBuilder` state-machine transitions (associativity of preset composition)
|
||||
- [x] 7.3 `Factory` determinism under fixed `rng`
|
||||
- [x] 7.4 `MemoryStore` TTL expiry monotonicity + capacity-limit invariant
|
||||
- [x] 7.5 `waitFor` polling correctness under arbitrary predicate schedules
|
||||
- [x] 7.6 `seededRng` reproducibility (same seed → same sequence)
|
||||
|
||||
## 8. Benchmarks (mitata)
|
||||
|
||||
- [x] 8.1 `src/__benchmarks__/clock.bench.ts` — FakeClock advance/schedule throughput
|
||||
- [x] 8.2 `src/__benchmarks__/builders.bench.ts` — RequestBuilder and ResponseBuilder build throughput
|
||||
- [x] 8.3 `src/__benchmarks__/factory.bench.ts` — Factory single build + batch build
|
||||
- [x] 8.4 `src/__benchmarks__/memory-store.bench.ts` — set/get/evict under load
|
||||
- [x] 8.5 `src/__benchmarks__/helpers.bench.ts` — waitFor overhead; assertThrows overhead
|
||||
- [x] 8.6 `src/__benchmarks__/observability.bench.ts` — OTEL-wrapped vs unwrapped overhead comparison (enforces <5% in CI)
|
||||
- [x] 8.7 `benchmarks/baselines.json` — initial baseline commit (reviewer-approved, separate from functional changes)
|
||||
- [x] 8.8 CI script: run `mitata` 3×, take fastest, compare to baseline, fail >10% regression
|
||||
|
||||
## 9. Examples
|
||||
|
||||
- [x] 9.1 `examples/basic-usage.ts` — runnable script using `Factory`, `FakeClock`, `waitFor`
|
||||
- [x] 9.2 `examples/fixture-plugin.ts` — runnable script registering a `FixtureManagerPlugin`
|
||||
- [x] 9.3 `examples/deterministic-factory.ts` — runnable script demonstrating `seededRng` reproducibility
|
||||
- [x] 9.4 `examples/custom-clock.ts` — runnable script swapping `defaultClock` for `FakeClock` end-to-end
|
||||
- [x] 9.5 Verify every example runs via `bun examples/<name>.ts` without error
|
||||
|
||||
## 10. Tree-shake and dep-graph guards
|
||||
|
||||
- [x] 10.1 `src/__tests__/tree-shake.test.ts` — asserts that `./uint/clock` (for example) does not pull `MemoryStore`, `RequestBuilder`, or `Factory` identifiers into its built output
|
||||
- [x] 10.2 `src/__tests__/dep-graph.test.ts` — reads `package.json` and asserts no `@suaveplan/*` appears in `dependencies`, `peerDependencies`, or `devDependencies`
|
||||
- [x] 10.3 `src/__tests__/no-disallowed.test.ts` — greps `src/` for `any`, `ts-ignore`, `ts-expect-error`, `TODO`, `FIXME`, `@deprecated`, `.skip`, `.only`; fails on any match
|
||||
|
||||
## 11. Docs
|
||||
|
||||
- [x] 11.1 Verify every implementation file has a sibling `.md` of ≥ 200 words, simple + advanced examples, API reference, implementation notes
|
||||
- [x] 11.2 Rewrite `packages/universal/testing/README.md` with purpose, install, quick usage, error-code index, observability reference, benchmark numbers, links to each module's `.md`
|
||||
- [x] 11.3 Run a docs-coverage check script (inline in `scripts/` or ad-hoc) confirming ≥ 90%
|
||||
|
||||
## 12. Security review
|
||||
|
||||
- [x] 12.1 Invoke the `security-review` skill on the final diff
|
||||
- [x] 12.2 Address every finding (prototype pollution in `MemoryStore.set`, ReDoS in any regex helper, payload bombs in `Factory.buildBatch`); re-run until clean
|
||||
- [x] 12.3 `bun audit` clean — zero advisories introduced by catalog additions
|
||||
|
||||
## 13. Pre-publish gate + publish + archive
|
||||
|
||||
- [x] 13.1 `bunx turbo lint typecheck test --filter=@suaveplan/testing` green (CLAUDE.md non-negotiable)
|
||||
- [x] 13.2 `bunx turbo test:coverage --filter=@suaveplan/testing` meets ≥ 95% statement + branch
|
||||
- [x] 13.3 `bunx turbo lint typecheck` across all catalogs reaching `@suaveplan/testing` — green (only `@suaveplan/testing` on genesis today; confirm build graph is clean)
|
||||
- [x] 13.4 `bun scripts/publish.ts --package @suaveplan/testing --dry-run` produces a sane diff
|
||||
- [x] 13.5 `bun scripts/publish.ts --package @suaveplan/testing` — publish `@suaveplan/testing@0.0.0` to Verdaccio
|
||||
- [x] 13.6 `openspec validate enterprise-testing --type change` — passes
|
||||
- [x] 13.7 Fold the `specs/testing/spec.md` delta into `openspec/specs/testing/spec.md` (create) and move this change folder to `openspec/archive/<yyyy-mm-dd>-enterprise-testing/`
|
||||
- [x] 13.8 Mark `@suaveplan/testing` ✅ Enterprise in the genesis `README.md` (when the file exists) and in `openspec/project.md` package taxonomy
|
||||
Reference in New Issue
Block a user