Files
suaveplan/openspec/archive/2026-05-25-enterprise-test-vite/design.md
2026-05-27 23:29:53 +01:00

5.3 KiB

Design — @suaveplan/test-vite

Tier and dependency allowlist

Tier: universal-ish-tooling — runs in Node-build contexts (vite build) and Vitest test files. Not browser-runtime.

Dependency allowlist (production):

  • @suaveplan/error (workspace) — defineCodes + SuaveplanError for TestViteError.
  • @suaveplan/types (workspace) — Clock, LoggerLike injection contracts.
  • @suaveplan/opentelemetry (workspace, transitive) — meter wiring via @opentelemetry/api.
  • @opentelemetry/api (catalog:observability) — counters + histograms.
  • vite (catalog:build) — UserConfig type + defineConfig re-imported by factories.
  • vitest (catalog:testing) — UserConfig / defineConfig from vitest/config.
  • vite-plugin-dts (catalog:build) — used inside createViteLibraryConfig.
  • zod (catalog:forms) — boundary validation of every public option object.
  • tslib (catalog:build) — helper runtime.

Dev-only: @suaveplan/testing for ./runner wrapper, @opentelemetry/sdk-metrics for in-memory MeterProvider test setup, @types/node, typescript, @vitest/coverage-istanbul.

vite / vitest / vite-plugin-dts are production deps because callers inherit them via this package (matching the upstream convention from the enterprise plan §2).

Folder layout

src/
  index.ts                                      # explicit named re-exports
  vite-library-config/
    vite-library-config.ts                      # createViteLibraryConfig(opts)
    vite-library-config.md
    vite-library-config.test.ts
  vite-app-config/
    vite-app-config.ts                          # createViteAppConfig(opts)
    vite-app-config.md
    vite-app-config.test.ts
  vitest-config/
    vitest-config.ts                            # createVitestConfig(opts)
    vitest-config.md
    vitest-config.test.ts
  vitest-browser-config/
    vitest-browser-config.ts                    # createVitestBrowserConfig(opts)
    vitest-browser-config.md
    vitest-browser-config.test.ts
  browser-environment/
    browser-environment.ts                      # setupBrowserEnvironment
    browser-environment.md
    browser-environment.test.ts
  tree-shake-validator/
    tree-shake-validator.ts                     # verifyTreeShake
    tree-shake-validator.md
    tree-shake-validator.test.ts
  bundle-size-snapshot/
    bundle-size-snapshot.ts                     # snapshotBundleSize
    bundle-size-snapshot.md
    bundle-size-snapshot.test.ts
  port-allocator/
    port-allocator.ts                           # allocate/releasePort
    port-allocator.md
    port-allocator.test.ts
  hmr-tester/
    hmr-tester.ts                               # withHMR
    hmr-tester.md
    hmr-tester.test.ts
  matchers/
    matchers.ts                                 # createMatchers
    matchers.md
    matchers.test.ts
  error-codes/
    error-codes.ts                              # TEST_VITE_CODES, TestViteError
    error-codes.md
    error-codes.test.ts
  telemetry/
    telemetry.ts                                # OTel instruments
    telemetry.md
    telemetry.test.ts
  types/
    test-vite.types.ts                          # shared interfaces
tests/
  setup/
    polyfills.ts                                # in-memory MeterProvider + webcrypto

Error-code plan

defineCodes("TEST_VITE", [...]) with these codes:

  • INVALID_OPTIONS — Zod parse failure on any factory option object.
  • MISSING_ENTRY — bundle file required by verifyTreeShake / snapshotBundleSize cannot be read.
  • TREE_SHAKE_VIOLATION — bundle exports a symbol not in expectedSymbols.
  • SIZE_BUDGET_EXCEEDED — bundle size exceeds snapshot + tolerance.
  • SNAPSHOT_MISSING — snapshot file not found and update: false.
  • PORT_EXHAUSTED — no port in the configured range is available.
  • PORT_NOT_HELD — release of an unheld port.
  • HMR_TIMEOUT — HMR round-trip exceeded timeout.

8 codes — every one is exercised by a test (see spec deltas).

OTel instrument plan

Meter name: @suaveplan/test-vite. Instruments:

  • test_vite_config_built_total (counter) — one per factory invocation; attribute kind = vite_library/vite_app/vitest/vitest_browser.
  • test_vite_validator_runs_total (counter) — one per verifyTreeShake or snapshotBundleSize call.
  • test_vite_validator_violations_total (counter) — one per detected violation.
  • test_vite_port_allocations_total (counter) — one per successful allocatePort.
  • test_vite_hmr_round_trip_ms (histogram) — recorded on every withHMR resolution.

All wired into a single telemetry.ts module with a real MeterProvider asserted in telemetry.test.ts.

Boundary validation

Every public factory accepts an options object validated by a Zod schema. Invalid input → TestViteError(TEST_VITE_CODES.INVALID_OPTIONS, …) carrying the Zod issue list on details.

Test-runner discipline

All *.test.ts files import from @suaveplan/testing/runner (rule 11). No vitest or bun:test direct imports.

File-size budget

Every implementation file stays under 300 lines hard / 250 soft. Where logic is dense (tree-shake-validator, bundle-size-snapshot), shared helpers are extracted into private module-local functions; if necessary they spill into a sibling <feature>.helpers.ts (still inside the feature folder, with its own .md).