# 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`.