184 lines
6.0 KiB
Markdown
184 lines
6.0 KiB
Markdown
# 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<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
|
|
|
|
```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`.
|