Files
2026-05-27 23:29:53 +01:00

5.9 KiB

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/.