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

5.4 KiB

Proposal — Migrate @suaveplan/test-vite to genesis

  • Design: ./design.md
  • Spec delta: ./specs/test-vite/spec.md

Why

Upstream @suaveplan/test-vite (/mnt/s/web/suaveplan/packages/browser/test-vite/) ships as a one-symbol stub (export const test = "hi") despite extensive README copy describing planned factories (createViteLibraryConfig, createVitestConfig, setupBrowserEnvironment, tree-shake validator, bundle-size snapshot, custom matchers). The genesis enterprise/test-vite.md audit calls this "the kind of scaffolding CLAUDE.md explicitly forbids" and lays out the full enterprise scope. Every genesis browser-tier package currently rewrites a near-identical vite.config.ts/vitest.config.ts pair by hand; this package owns those factories and the WSL2 safety defaults documented in CLAUDE.md ("Vitest / WSL2").

What

Land @suaveplan/test-vite@0.1.0 at packages/devtools/tooling/test-vite/ with these feature modules (one folder per feature, sibling .md per implementation file):

  • vite-library-config/ — createViteLibraryConfig(opts) factory producing a UserConfig for internal library packages: vite-plugin-dts, ESM-first output, preserveModules: true tree-shaking, external auto-extended with @suaveplan/* + /^node:/ + tslib.
  • vite-app-config/ — createViteAppConfig(opts) factory for consumer apps: hashed asset names, env-prefix declaration, optional framework plugin slot.
  • vitest-config/ — createVitestConfig(opts) factory: pool: 'forks', Istanbul provider, setupFiles, 100/100/100/100 thresholds, fileParallelism switch.
  • vitest-browser-config/ — createVitestBrowserConfig(opts) factory: Playwright provider, fileParallelism: false, multi-browser matrix.
  • browser-environment/ — setupBrowserEnvironment(opts) runtime helper installing happy-dom / jsdom shims (localStorage, matchMedia, ResizeObserver, IntersectionObserver, crypto.webcrypto).
  • tree-shake-validator/ — verifyTreeShake({ entry, expectedSymbols, bundle }) that statically parses a bundle (Rollup-emitted text) and asserts the emitted exports match the allow-list.
  • bundle-size-snapshot/ — snapshotBundleSize({ entry, snapshot, fs }) that compares a bundle byte-size against a snapshot file and enforces a configurable budget tolerance.
  • port-allocator/ — allocatePort / releasePort backed by an injectable lock-file store; fixes WSL2 parallel-Storybook/Playwright collisions.
  • hmr-tester/ — withHMR({ server, edit, expectEvents }) round-trips a Vite HMR cycle via an injectable server adapter (no real network).
  • matchers/ — expect.extend matchers: toBeAccessibleNode, toMatchDataURL, toHaveValidCSSVars. Universal (work in node + jsdom + happy-dom).
  • error-codes/ — TEST_VITE_CODES via defineCodes("TEST_VITE", […]) + TestViteError.
  • telemetry/ — OTel counters + histograms for factory invocations and validator runs.
  • types/ — shared option/result types.

Parity Checklist

Capability Upstream Migrated Notes
export const test = "hi" placeholder ✅ 🚫 Removed — explicit goal of the enterprise plan.
createViteLibraryConfig 📝 (README only) ✅ New implementation per enterprise plan §4.
createViteAppConfig 📝 (README only) ✅ New implementation.
createVitestConfig (WSL2-safe) 📝 (README only) ✅ New; defaults: pool: 'forks', Istanbul, setupFiles.
createVitestBrowserConfig 📝 (README only) ✅ New; Playwright provider.
setupBrowserEnvironment 📝 (README only) ✅ New.
Tree-shake validator 📝 ✅ New.
Bundle-size snapshot 📝 ✅ New.
Custom matchers 📝 ✅ New.
Port allocator 📝 ✅ New.
HMR tester 📝 ✅ New.
Error-code registry 🚫 ⬆️ Enhanced — required by genesis.
OTel self-telemetry 🚫 ⬆️ Enhanced — required by genesis.
Subpath exports 🚫 ⬆️ Enhanced — every feature is its own subpath.

The "Upstream 📝" rows track features that existed only as README copy upstream; they are net-new implementations on genesis.

Scope split vs @suaveplan/testing

@suaveplan/testing/config already owns the generic createTestConfig({ environment }) used across packages. This package, @suaveplan/test-vite, owns the Vite-specific build factories and Vitest configurations that surface Vite/Rollup-specific options (vite-plugin-dts, preserveModules, Playwright browser-mode, HMR round-trip). They are complementary: @suaveplan/testing is runner-agnostic; @suaveplan/test-vite is Vite-aware.

Impact

Affected dependents

Net-new package — no current consumers. Downstream browser-tier packages MAY opt into the factories incrementally; the enterprise plan flags react-tour as the first migration target.

Risks

  • Vite/Vitest type surface drift. The factories return UserConfig from the pinned Vite / Vitest catalog versions. Mitigated by importing config types directly from those packages.
  • WSL2 fork-pool requirement. createVitestConfig defaults MUST stay pool: 'forks'; deviation will silently re-break vmThreads consumers. Pinned by explicit test + spec requirement.
  • Bundle-size snapshot file IO. The validator accepts an injectable fs adapter so tests don't touch the real filesystem; production callers pass node:fs/promises.