# Tasks: enterprise-browser-test-vite **Change ID**: enterprise-browser-test-vite **Package**: `@suaveplan/test-vite` **Target path**: `browser/dev/test-vite` **Prerequisite packages on Verdaccio**: none (no workspace runtime deps) --- ## 0. Pre-flight (non-negotiable) - [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each) - [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest. ## 1. Scaffold - [ ] Create directory tree per `proposal.md`. - [ ] `package.json` v0.0.0, `"sideEffects": false`. - `dependencies`: `@suaveplan/logger workspace:^`, `tslib catalog:build` - `peerDependencies`: `vite`, `vitest` - `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `vite catalog:build`, `@suaveplan/testing workspace:^` - Subpath exports: `"."`, `"./config/vite-library"`, `"./config/vite-app"`, `"./config/vitest"`, `"./config/vitest-browser"`, `"./setup/browser"`, `"./utils/tree-shake"`, `"./utils/bundle-size"`, `"./matchers"`, `"./ports"` - [ ] `tsconfig.json`, `vitest.config.ts` (pool: forks). - [ ] **Delete** `export const test = "hi"` placeholder from `src/index.ts`. --- ## 2. Types (`src/types/types.ts`) - [ ] `ViteLibraryOptions`, `ViteAppOptions`, `VitestOptions`, `VitestBrowserOptions`, `BrowserEnvOptions`, `SetupResult`, `TreeShakeResult`, `BundleSizeResult`. - [ ] All option types validated by Zod with sensible defaults. - [ ] Write `types.md`. --- ## 3. Scope split documentation - [ ] Document formal scope split in this change's OpenSpec entry: `test-vite` = Vite/Vitest build config factories; `@suaveplan/testing` = polyfills + test utilities + fixtures. No overlap. --- ## 4. `createViteLibraryConfig` (`src/config/vite-library/`) - [ ] `vite-library.ts` — `preserveModules: true`, `vite-plugin-dts`, external `@suaveplan/*` peers, ESM-first output, configurable `entry`. - [ ] Options validated by Zod. - [ ] Write `vite-library.test.ts` (options validation, externals list, DTS flag). Write `vite-library.md`. --- ## 5. `createViteAppConfig` (`src/config/vite-app/`) - [ ] `vite-app.ts` — React/Vue plugin switch, env-var type declarations, hashing strategy. - [ ] Write `vite-app.test.ts`. Write `vite-app.md`. --- ## 6. `createVitestConfig` (`src/config/vitest/`) - [ ] `vitest.ts` — defaults: `pool: 'forks'`, `setupFiles: ['@suaveplan/testing/polyfills']`, Istanbul provider, reporters tuned for CI. - [ ] Accepts `environment`, `coverage`, `pool` overrides. - [ ] Write `vitest.test.ts` (default pool is forks, Istanbul provider selected, polyfills in setupFiles). Write `vitest.md`. --- ## 7. `createVitestBrowserConfig` (`src/config/vitest-browser/`) - [ ] `vitest-browser.ts` — Playwright provider; `fileParallelism: false`; configurable `browser` (chromium/firefox/webkit); `headless` toggle. - [ ] Write `vitest-browser.test.ts`. Write `vitest-browser.md`. --- ## 8. `setupBrowserEnvironment` (`src/setup/browser/`) - [ ] `browser.ts` — happy-dom / jsdom helper with switches: `mockLocalStorage`, `mockServiceWorker`, `mockMatchMedia`, `mockResizeObserver`. - [ ] Implementations use typed adapters — no `vi.stubGlobal`. - [ ] Write `browser.test.ts` (each mock flag). Write `browser.md`. --- ## 9. Tree-shake validator (`src/utils/tree-shake/`) - [ ] `tree-shake.ts` — `verifyTreeShake(entry, expectedSymbols)` builds with Rollup, asserts only listed symbols in output chunk. - [ ] Write `tree-shake.test.ts` (synthetic package — verify dead code eliminated). Write `tree-shake.md`. --- ## 10. Bundle-size snapshot (`src/utils/bundle-size/`) - [ ] `bundle-size.ts` — `snapshotBundleSize(entry, budgetBytes)` writes `.size.snap`; fails when budget exceeded. - [ ] Write `bundle-size.test.ts`. Write `bundle-size.md`. --- ## 11. Custom matchers (`src/matchers/`) - [ ] `matchers.ts` — typed `expect.extend`: `toBeAccessible` (axe-core), `toMatchDataURL`, `toHaveValidCSSVars`. - [ ] Write `matchers.test.ts` (each matcher pass + fail case). Write `matchers.md`. --- ## 12. Port helpers (`src/ports/`) - [ ] `ports.ts` — `allocatePort(label)` / `releasePort(label)` backed by a file lock; deterministic port assignment; `getPortMap()` for diagnostics. - [ ] Write `ports.test.ts` (allocate, release, conflict avoidance). Write `ports.md`. --- ## 13. Proof-of-concept consumer migration - [ ] Migrate one browser consumer (e.g., `@suaveplan/react-tour`) off its handwritten `vite.config.ts` + `vitest.config.ts` onto the new factories. - [ ] Document the migration as an example in `README.md`. --- ## 14. Integration test (`tests/integration.test.ts`) - [ ] Build a synthetic library package end-to-end using `createViteLibraryConfig`; assert ESM output, DTS files, externals. - [ ] Run `createVitestConfig` in a child process; assert `pool: forks` and Istanbul provider. - [ ] `verifyTreeShake` on a test module; assert dead export eliminated. --- ## 15. Docs + verify - [ ] Write `.md` per module (≥200 words, API reference, options table, example). - [ ] Write `README.md` with scope-split table, subpath table, migration example. - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/test-vite` — green. - [ ] `bunx turbo test:coverage` — 100% (currently near-zero). - [ ] No `@ts-expect-error` in `src/` or tests. No placeholder exports. - [ ] At least one consumer package migrated to new factories. - [ ] `bun scripts/publish.ts --package @suaveplan/test-vite`. - [ ] Archive to `openspec/archive/2026-04-24-enterprise-browser-test-vite/`.