# OpenSpec Change: enterprise-browser-test-vite - **Change ID**: enterprise-browser-test-vite - **Package**: `@suaveplan/test-vite` - **Category**: browser - **Target path**: `browser/dev/test-vite` - **Status**: IN PROGRESS - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/test-vite.md` --- ## Summary Deliver `@suaveplan/test-vite` on the genesis branch at enterprise quality. The package is currently a stub (exports `const test = "hi"`). Genesis replaces the stub with real Vite + Vitest configuration factory functions: `createViteLibraryConfig`, `createViteAppConfig`, `createVitestConfig`, `createVitestBrowserConfig`, `setupBrowserEnvironment`, a tree-shake validator, a bundle-size snapshot helper, and typed custom browser matchers. All WSL2-safe defaults pre-applied. Scope is split from `@suaveplan/testing`: `test-vite` owns Vite/Vitest build config; `@suaveplan/testing` owns polyfills, test utilities, and fixtures. --- ## Current-state audit (genesis) Package exists as a stub only — exports `export const test = "hi"`. No real functionality. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/logger` (`workspace:^`) | Diagnostics logging inside factory helpers | | `tslib` (`catalog:build`) | Runtime helpers | `peerDependencies`: `vite`, `vitest` — consumers must have their own versions. The package exports **factories** that accept user config — it does not re-export `vite`/`vitest` APIs. Dev: `vitest`, `@vitest/coverage-istanbul`, `vite`, `@suaveplan/testing`. --- ## Preserved public API surface ```ts // Vite config factories function createViteLibraryConfig(options: ViteLibraryOptions): UserConfig function createViteAppConfig(options: ViteAppOptions): UserConfig // Vitest config factories function createVitestConfig(options?: VitestOptions): UserConfigExport function createVitestBrowserConfig(options?: VitestBrowserOptions): UserConfigExport // Environment setup function setupBrowserEnvironment(options?: BrowserEnvOptions): SetupResult // Validation utilities function verifyTreeShake(entry: string, expectedSymbols: string[]): Promise function snapshotBundleSize(entry: string, budgetBytes: number): Promise // Custom matchers (typed expect.extend) // expect(element).toBeAccessible() // expect(dataUrl).toMatchDataURL(expected) // expect(element).toHaveValidCSSVars(vars) // Port utilities function allocatePort(label: string): Promise function releasePort(label: string): Promise // Types interface ViteLibraryOptions { entry: string | Record; external?: string[]; dts?: boolean; outDir?: string } interface ViteAppOptions { root?: string; envDir?: string; plugins?: Plugin[] } interface VitestOptions { environment?: 'happy-dom' | 'jsdom' | 'node'; coverage?: boolean; pool?: 'forks' | 'vmForks'; setupFiles?: string[] } interface VitestBrowserOptions { browser?: 'chromium' | 'firefox' | 'webkit'; headless?: boolean } interface BrowserEnvOptions { mockLocalStorage?: boolean; mockServiceWorker?: boolean; mockMatchMedia?: boolean; mockResizeObserver?: boolean } ``` Subpath exports: `"."`, `"./config/vite-library"`, `"./config/vite-app"`, `"./config/vitest"`, `"./config/vitest-browser"`, `"./setup/browser"`, `"./utils/tree-shake"`, `"./utils/bundle-size"`, `"./matchers"`, `"./ports"`. --- ## New additions for genesis ### 1. Replace stub Delete `export const test = "hi"`. Implement all documented factories. ### 2. WSL2-safe Vitest defaults `createVitestConfig` defaults: `pool: 'forks'`, `setupFiles: ['@suaveplan/testing/polyfills']`, Istanbul coverage provider. `createVitestBrowserConfig` adds `fileParallelism: false`. ### 3. Scope split vs `@suaveplan/testing` Formal decision documented in this OpenSpec change: `test-vite` owns Vite build config + Vitest config factories; `@suaveplan/testing` retains polyfills, `FakeClock`, `Factory`, `MemoryStore`, etc. No overlap. ### 4. Tree-shake validator `verifyTreeShake(entry, expectedSymbols)` builds with Rollup, asserts only listed symbols in output. Catches accidental barrel-import pollution. ### 5. Bundle-size snapshot `snapshotBundleSize(entry, budgetBytes)` writes `.size.snap`; fails CI when budget exceeded. ### 6. Custom matchers `toBeAccessible` (axe-core), `toMatchDataURL`, `toHaveValidCSSVars` — typed `expect.extend` for browser API assertions. ### 7. Port helpers `allocatePort(label)` / `releasePort(label)` backed by a file lock (`/tmp/vite-ports.lock`) so parallel Storybook/Playwright runs don't collide on WSL2. --- ## File layout ```text browser/dev/test-vite/ package.json tsconfig.json vitest.config.ts src/ index.ts config/ vite-library/ vite-library.ts vite-library.test.ts vite-library.md index.ts vite-app/ vite-app.ts vite-app.test.ts vite-app.md index.ts vitest/ vitest.ts vitest.test.ts vitest.md index.ts vitest-browser/ vitest-browser.ts vitest-browser.test.ts vitest-browser.md index.ts setup/ browser/ browser.ts browser.test.ts browser.md index.ts utils/ tree-shake/ tree-shake.ts tree-shake.test.ts tree-shake.md index.ts bundle-size/ bundle-size.ts bundle-size.test.ts bundle-size.md index.ts matchers/ matchers.ts matchers.test.ts matchers.md index.ts ports/ ports.ts ports.test.ts ports.md index.ts types/ types.ts types.md constants/ index.ts tests/ integration.test.ts ``` --- ## Impact **Downstream**: every `@suaveplan/*` browser package that ships its own `vite.config.ts` / `vitest.config.ts`. Migration is opt-in; packages can adopt on their own schedule. **Breaking changes**: removes the `test = "hi"` placeholder; any consumer importing it (unlikely) must remove the import. **Prerequisites**: None at runtime. `vite` and `vitest` are `peerDependencies`.