6.0 KiB
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
// 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<void>
function snapshotBundleSize(entry: string, budgetBytes: number): Promise<void>
// Custom matchers (typed expect.extend)
// expect(element).toBeAccessible()
// expect(dataUrl).toMatchDataURL(expected)
// expect(element).toHaveValidCSSVars(vars)
// Port utilities
function allocatePort(label: string): Promise<number>
function releasePort(label: string): Promise<void>
// Types
interface ViteLibraryOptions { entry: string | Record<string, string>; 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 <entry>.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
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.