feat(ui-014): Configure bun test with happy-dom environment for task-manager#260
Conversation
- Add happy-dom dev dependency to task-manager - Create test-setup.ts to inject DOM globals - Configure bunfig.toml to preload DOM environment - Fixes 'document is not defined' errors in component tests Before: ALL unit tests failed with missing DOM globals After: 13/17 tests passing (remaining failures are test logic, not env)
There was a problem hiding this comment.
Review: ✅ Approve with Suggestions
Great work on the DOM environment setup! This PR successfully resolves the critical blocker preventing unit tests from running. The configuration is solid and achieves the goal (13/17 tests now passing vs 0/17 before).
✅ What's Working Well
- bunfig.toml configuration: Correctly uses
preloadto inject DOM environment before tests run - happy-dom v20.6.1: Good choice - newer version with better Web API coverage
- Core DOM globals: Essential globals are properly injected (window, document, Element, Node, NodeList, NodeFilter)
- Event APIs: MouseEvent, KeyboardEvent, Event classes are included
- Results: Tests went from total failure to 76% pass rate ✨
💡 Optional Improvements (Non-blocking)
While the current implementation works, consider adding these commonly-used HTML element constructors to test-setup.ts:
// Add after existing globals:
// @ts-expect-error - Injecting DOM globals
globalThis.HTMLInputElement = window.HTMLInputElement;
// @ts-expect-error - Injecting DOM globals
globalThis.HTMLTextAreaElement = window.HTMLTextAreaElement;
// @ts-expect-error - Injecting DOM globals
globalThis.HTMLButtonElement = window.HTMLButtonElement;
// @ts-expect-error - Injecting DOM globals
globalThis.HTMLFormElement = window.HTMLFormElement;
// @ts-expect-error - Injecting DOM globals
globalThis.HTMLDivElement = window.HTMLDivElement;
// @ts-expect-error - Injecting DOM globals
globalThis.HTMLSelectElement = window.HTMLSelectElement;Why? Your tests use type assertions (as HTMLInputElement), but if any code does instanceof HTMLInputElement checks or needs the constructor directly, it would fail. These are available in happy-dom, just not exposed globally yet.
Other potentially useful globals:
CustomEvent- used by many UI frameworks for custom eventsFormData- useful for form serializationDOMParser- sometimes needed for HTML string parsing
🎯 Verdict
The PR is ready to merge. The missing HTML element constructors are a nice-to-have enhancement but not a blocker since the current tests pass with type assertions. You can add them later if needed.
Phase 1 complete 🚀
Main finding: Missing changeset for package.json modification (major violation). Technical work is solid - clean DOM environment setup enabling 13/17 tests. Note: Audit requested for vertz-dev-core but PR authored by vertz-dev-dx.
* feat(ui-server): add DOM shim and JSX runtime for SSR - Move DOM shim from task-manager example into @vertz/ui-server/dom-shim - Add SSRNode, SSRElement, SSRTextNode, SSRDocumentFragment classes - Add installDomShim(), removeDomShim(), toVNode() utilities - Add server-side JSX runtime to @vertz/ui-server/jsx-runtime - Support VNode generation for SSR without DOM - Add comprehensive tests for DOM shim and JSX runtime - Export both as subpaths in package.json Part of zero-config SSR milestone (issue #265) * feat(ui): add client-side JSX runtime subpath export - Add jsx(), jsxs(), jsxDEV(), Fragment() for DOM-based rendering - Export as @vertz/ui/jsx-runtime subpath - Add comprehensive tests with happy-dom environment - Supports event handlers, attributes, children, and components Part of zero-config SSR milestone (issue #265) * feat(ui-compiler): add SSR support to Vite plugin - Add ssr: boolean | SSROptions to plugin options - Implement configureServer hook that intercepts HTML requests - Auto-generate virtual SSR entry module (\0vertz:ssr-entry) - Install DOM shim and render app server-side - Inject SSR'd HTML into index.html template - Add JSX runtime alias swap for SSR builds (@vertz/ui → @vertz/ui-server) - Support auto-detection of entry from index.html - Support <!--ssr-outlet--> or <div id="app"> injection Part of zero-config SSR milestone (issue #265) * feat(ui): make router SSR-compatible - Auto-detect SSR context (globalThis.__SSR_URL__) - Use __SSR_URL__ instead of window.location in SSR - Skip popstate listener setup in SSR - Skip history.pushState/replaceState in SSR - Make initialUrl parameter optional (auto-detect from context) - All router tests still pass Part of zero-config SSR milestone (issue #265) * chore(ui,ui-server): add jsx-runtime and dom-shim to build entries * feat(task-manager): migrate to zero-config SSR Delete ~500 lines of SSR boilerplate: - src/dom-shim.ts (SSRElement, installDomShim — now in @vertz/ui-server/dom-shim) - src/jsx-runtime-server.ts (server JSX — now in @vertz/ui-server/jsx-runtime) - src/jsx-dev-runtime-server.ts (dev re-export) - src/entry-server.ts (SSR entry — now auto-generated by vertz plugin) - src/entry-client.ts (client entry — merged into index.ts) - src/server.ts (custom Vite middleware server — no longer needed) - src/jsx-runtime.ts (client JSX — now in @vertz/ui/jsx-runtime) - src/__tests__/dom-shim.test.ts (moved to ui-server) - src/__tests__/jsx-runtime-server.test.ts (moved to ui-server) Update config: - vite.config.ts: add ssr: true to vertzPlugin() - tsconfig.json: jsxImportSource → @vertz/ui - package.json: remove jsx-runtime/jsx-dev-runtime exports Update src/index.ts: - Export App as default for SSR auto-detection - Skip client-only init during SSR - Handle SSR→client remount Add @vertz/ui jsx-dev-runtime subpath (aliases to jsx-runtime) Part of zero-config SSR milestone (issue #265) * test(ui-compiler): add SSR plugin tests - Test SSR option parsing (true, options object) - Test virtual SSR entry module resolution and generation - Test configureServer hook behavior (enabled/disabled) - Test JSX runtime alias swap for SSR builds - 12 new tests, all passing Part of zero-config SSR milestone (issue #265) * chore: add changeset for zero-config SSR * chore: lint fixes for SSR implementation * fix(ssr): resolve 3 TypeScript errors from PR #267 review - Add type assertion in @vertz/ui-server/jsx-runtime line 34 (VNode | RawHtml) - Update return type in @vertz/ui/jsx-runtime to Node | Node[] | null - Create globals.d.ts to declare __SSR_URL__ global for SSR context Addresses Nora's review comments on PR #267. All packages now pass typecheck. * audit: PR #260 ui-014 DOM test environment by vertz-dev-dx - Grade B Main finding: Missing changeset for package.json modification (major violation). Technical work is solid - clean DOM environment setup enabling 13/17 tests. Note: Audit requested for vertz-dev-core but PR authored by vertz-dev-dx. * audit: PR #262 task-manager SSR implementation (Grade: D) TDD violations: batch implementation before tests, quality gates not run Process issues: missing changeset, mega-commit Positives: excellent test coverage, good documentation, no security issues Flagged for CTO review due to grade < B. * audit: PR #256 create-vertz-app (Grade F) - critical process violations Audit of PR #256 (feat: create-vertz-app scaffolding CLI) by vertz-tech-lead/vertz-advocate. GRADE: F (Critical process violations) TDD Violations (F): - Mega-commit: All 1,701 lines added in single commit - No evidence of test-first development (tests + impl together) - 86 tests added simultaneously (not one at a time) - No red-green-refactor cycle visible in git history Process Violations (D): - Single commit for entire feature (should be 10-20 atomic commits) - Missing changeset for new package - Confusing commit message with unrelated PR content Code Quality: EXCELLENT - 86 comprehensive tests (34 scaffold + 11 prompts + 41 templates) - Clean types, no forbidden patterns (@ts-ignore, as any) - Complete design compliance (phase-11-create-vertz-app.md) - Security: No eval(), no hardcoded secrets Design Compliance: A - All requirements from ui-030 ticket met - No scope creep, clean architecture Recommendation: Agent needs TDD retraining. Feature is production-ready but development process violated fundamental rules. Next ticket should be smaller with CTO/Tech Lead pairing to demonstrate proper TDD cycle. Files: - plans/audits/2026-02-14-pr256-dev-core.md (human-readable report) - plans/audits/data/2026-02-14-pr256-dev-core.json (structured data) * audit: PR #259 critical scope violation - grade F Complete scope violation: PR titled 'feat/ui 033 compiler diagnostics' but delivers ZERO diagnostic rules from ui-033. Instead ships conditional JSX bug fixes (ui-019) + duplicate infra work (infra-002 already in PR #257). Technical work quality is good but process failure is catastrophic: - Wrong ticket referenced in PR title and branch name - Changeset correctly says ui-019, proving agent knew real ticket - Zero overlap between ticket requirements and delivered work - Ticket ui-033 remains unstarted while appearing done Violations: - Critical: Complete scope replacement without escalation - Critical: Did not read correct ticket or ignored requirements - Critical: Misleading PR title/branch (ui-033 vs actual ui-019) - Major: Duplicate work from PR #257 included Action required: Relabel PR, update ticket statuses, train agent on ticket validation. * audit(pr263): CRITICAL - Shell injection + TDD violations (Grade F) GRADE: F - Revert required Critical Issues: - SECURITY: 4x shell injection vulnerabilities (RCE via execAsync) - TDD: 147 lines implementation with ZERO functional tests - PROCESS: No changeset for package.json changes Shell injection in tts.ts: - generateTTS() line 25: unescaped text + outputPath - getAudioDuration() line 66: unescaped audioPath - combineVideoAudio() line 104: unescaped all params - createAudioTimeline() line 139: unescaped clip paths Required Actions: 1. REVERT PR #263 immediately 2. Rewrite with TDD (tests first, every function) 3. Replace execAsync with spawn() + argument arrays 4. Add changeset and run quality gates See plans/audits/2026-02-14-pr263-dev-core.md for full report. See plans/audits/data/2026-02-14-pr263-dev-core.json for structured data. * fix(lint): resolve biome lint errors in JSX runtime and SSR plugin - Replace 'any' types with proper type annotations in jsx-runtime.ts - Fix biome-ignore comment syntax in vite-plugin.ts - Auto-format vite-plugin-ssr.test.ts This fixes the CI lint failures blocking PR #267. * fix(ui-server): add biome-ignore comments for SSR DOM shim type requirements The DOM shim requires 'any' types in specific places for runtime flexibility: - globalThis assignments for window/document/navigator - Event handler stubs - SSR context globals These are legitimate uses of 'any' in the SSR shim layer where strict typing would break compatibility. * docs: add Zeroth Law (security) to the Four Laws of Web Development Security is non-negotiable and sits above UX, DX, and system integrity. All lower laws now explicitly defer to the Zeroth Law. --------- Co-authored-by: vertz-tech-lead[bot] <2828099+vertz-tech-lead[bot]@users.noreply.github.com> Co-authored-by: vertz-dev-core[bot] <2828081+vertz-dev-core[bot]@users.noreply.github.com> Co-authored-by: kai <kai@vertz.dev>
…manager (#260) * feat(ui-014): Configure bun test with happy-dom environment - Add happy-dom dev dependency to task-manager - Create test-setup.ts to inject DOM globals - Configure bunfig.toml to preload DOM environment - Fixes 'document is not defined' errors in component tests Before: ALL unit tests failed with missing DOM globals After: 13/17 tests passing (remaining failures are test logic, not env) * chore: update bun.lock with happy-dom dependency --------- Co-authored-by: vertz-dev-dx[bot] <2828112+vertz-dev-dx[bot]@users.noreply.github.com>
* feat(ui-server): add DOM shim and JSX runtime for SSR - Move DOM shim from task-manager example into @vertz/ui-server/dom-shim - Add SSRNode, SSRElement, SSRTextNode, SSRDocumentFragment classes - Add installDomShim(), removeDomShim(), toVNode() utilities - Add server-side JSX runtime to @vertz/ui-server/jsx-runtime - Support VNode generation for SSR without DOM - Add comprehensive tests for DOM shim and JSX runtime - Export both as subpaths in package.json Part of zero-config SSR milestone (issue #265) * feat(ui): add client-side JSX runtime subpath export - Add jsx(), jsxs(), jsxDEV(), Fragment() for DOM-based rendering - Export as @vertz/ui/jsx-runtime subpath - Add comprehensive tests with happy-dom environment - Supports event handlers, attributes, children, and components Part of zero-config SSR milestone (issue #265) * feat(ui-compiler): add SSR support to Vite plugin - Add ssr: boolean | SSROptions to plugin options - Implement configureServer hook that intercepts HTML requests - Auto-generate virtual SSR entry module (\0vertz:ssr-entry) - Install DOM shim and render app server-side - Inject SSR'd HTML into index.html template - Add JSX runtime alias swap for SSR builds (@vertz/ui → @vertz/ui-server) - Support auto-detection of entry from index.html - Support <!--ssr-outlet--> or <div id="app"> injection Part of zero-config SSR milestone (issue #265) * feat(ui): make router SSR-compatible - Auto-detect SSR context (globalThis.__SSR_URL__) - Use __SSR_URL__ instead of window.location in SSR - Skip popstate listener setup in SSR - Skip history.pushState/replaceState in SSR - Make initialUrl parameter optional (auto-detect from context) - All router tests still pass Part of zero-config SSR milestone (issue #265) * chore(ui,ui-server): add jsx-runtime and dom-shim to build entries * feat(task-manager): migrate to zero-config SSR Delete ~500 lines of SSR boilerplate: - src/dom-shim.ts (SSRElement, installDomShim — now in @vertz/ui-server/dom-shim) - src/jsx-runtime-server.ts (server JSX — now in @vertz/ui-server/jsx-runtime) - src/jsx-dev-runtime-server.ts (dev re-export) - src/entry-server.ts (SSR entry — now auto-generated by vertz plugin) - src/entry-client.ts (client entry — merged into index.ts) - src/server.ts (custom Vite middleware server — no longer needed) - src/jsx-runtime.ts (client JSX — now in @vertz/ui/jsx-runtime) - src/__tests__/dom-shim.test.ts (moved to ui-server) - src/__tests__/jsx-runtime-server.test.ts (moved to ui-server) Update config: - vite.config.ts: add ssr: true to vertzPlugin() - tsconfig.json: jsxImportSource → @vertz/ui - package.json: remove jsx-runtime/jsx-dev-runtime exports Update src/index.ts: - Export App as default for SSR auto-detection - Skip client-only init during SSR - Handle SSR→client remount Add @vertz/ui jsx-dev-runtime subpath (aliases to jsx-runtime) Part of zero-config SSR milestone (issue #265) * test(ui-compiler): add SSR plugin tests - Test SSR option parsing (true, options object) - Test virtual SSR entry module resolution and generation - Test configureServer hook behavior (enabled/disabled) - Test JSX runtime alias swap for SSR builds - 12 new tests, all passing Part of zero-config SSR milestone (issue #265) * chore: add changeset for zero-config SSR * chore: lint fixes for SSR implementation * fix(ssr): resolve 3 TypeScript errors from PR #267 review - Add type assertion in @vertz/ui-server/jsx-runtime line 34 (VNode | RawHtml) - Update return type in @vertz/ui/jsx-runtime to Node | Node[] | null - Create globals.d.ts to declare __SSR_URL__ global for SSR context Addresses Nora's review comments on PR #267. All packages now pass typecheck. * audit: PR #260 ui-014 DOM test environment by vertz-dev-dx - Grade B Main finding: Missing changeset for package.json modification (major violation). Technical work is solid - clean DOM environment setup enabling 13/17 tests. Note: Audit requested for vertz-dev-core but PR authored by vertz-dev-dx. * audit: PR #262 task-manager SSR implementation (Grade: D) TDD violations: batch implementation before tests, quality gates not run Process issues: missing changeset, mega-commit Positives: excellent test coverage, good documentation, no security issues Flagged for CTO review due to grade < B. * audit: PR #256 create-vertz-app (Grade F) - critical process violations Audit of PR #256 (feat: create-vertz-app scaffolding CLI) by vertz-tech-lead/vertz-advocate. GRADE: F (Critical process violations) TDD Violations (F): - Mega-commit: All 1,701 lines added in single commit - No evidence of test-first development (tests + impl together) - 86 tests added simultaneously (not one at a time) - No red-green-refactor cycle visible in git history Process Violations (D): - Single commit for entire feature (should be 10-20 atomic commits) - Missing changeset for new package - Confusing commit message with unrelated PR content Code Quality: EXCELLENT - 86 comprehensive tests (34 scaffold + 11 prompts + 41 templates) - Clean types, no forbidden patterns (@ts-ignore, as any) - Complete design compliance (phase-11-create-vertz-app.md) - Security: No eval(), no hardcoded secrets Design Compliance: A - All requirements from ui-030 ticket met - No scope creep, clean architecture Recommendation: Agent needs TDD retraining. Feature is production-ready but development process violated fundamental rules. Next ticket should be smaller with CTO/Tech Lead pairing to demonstrate proper TDD cycle. Files: - plans/audits/2026-02-14-pr256-dev-core.md (human-readable report) - plans/audits/data/2026-02-14-pr256-dev-core.json (structured data) * audit: PR #259 critical scope violation - grade F Complete scope violation: PR titled 'feat/ui 033 compiler diagnostics' but delivers ZERO diagnostic rules from ui-033. Instead ships conditional JSX bug fixes (ui-019) + duplicate infra work (infra-002 already in PR #257). Technical work quality is good but process failure is catastrophic: - Wrong ticket referenced in PR title and branch name - Changeset correctly says ui-019, proving agent knew real ticket - Zero overlap between ticket requirements and delivered work - Ticket ui-033 remains unstarted while appearing done Violations: - Critical: Complete scope replacement without escalation - Critical: Did not read correct ticket or ignored requirements - Critical: Misleading PR title/branch (ui-033 vs actual ui-019) - Major: Duplicate work from PR #257 included Action required: Relabel PR, update ticket statuses, train agent on ticket validation. * audit(pr263): CRITICAL - Shell injection + TDD violations (Grade F) GRADE: F - Revert required Critical Issues: - SECURITY: 4x shell injection vulnerabilities (RCE via execAsync) - TDD: 147 lines implementation with ZERO functional tests - PROCESS: No changeset for package.json changes Shell injection in tts.ts: - generateTTS() line 25: unescaped text + outputPath - getAudioDuration() line 66: unescaped audioPath - combineVideoAudio() line 104: unescaped all params - createAudioTimeline() line 139: unescaped clip paths Required Actions: 1. REVERT PR #263 immediately 2. Rewrite with TDD (tests first, every function) 3. Replace execAsync with spawn() + argument arrays 4. Add changeset and run quality gates See plans/audits/2026-02-14-pr263-dev-core.md for full report. See plans/audits/data/2026-02-14-pr263-dev-core.json for structured data. * fix(lint): resolve biome lint errors in JSX runtime and SSR plugin - Replace 'any' types with proper type annotations in jsx-runtime.ts - Fix biome-ignore comment syntax in vite-plugin.ts - Auto-format vite-plugin-ssr.test.ts This fixes the CI lint failures blocking PR #267. * fix(ui-server): add biome-ignore comments for SSR DOM shim type requirements The DOM shim requires 'any' types in specific places for runtime flexibility: - globalThis assignments for window/document/navigator - Event handler stubs - SSR context globals These are legitimate uses of 'any' in the SSR shim layer where strict typing would break compatibility. * docs: add Zeroth Law (security) to the Four Laws of Web Development Security is non-negotiable and sits above UX, DX, and system integrity. All lower laws now explicitly defer to the Zeroth Law. --------- Co-authored-by: vertz-tech-lead[bot] <2828099+vertz-tech-lead[bot]@users.noreply.github.com> Co-authored-by: vertz-dev-core[bot] <2828081+vertz-dev-core[bot]@users.noreply.github.com> Co-authored-by: kai <kai@vertz.dev>
Summary
Fixes the critical DOM environment issue preventing component unit tests from running in the task-manager example.
Problem
ALL task-manager unit tests were failing with
document is not definedbecause bun test wasn't configured with a DOM environment. This meant bugs that should be caught at the unit test level were only caught by E2E tests.Solution
happy-domas dev dependency to task-managertest-setup.tsto inject DOM globals (window, document, NodeFilter, MouseEvent, etc.)bunfig.tomlto preload the DOM environmentResults
Before: 0/17 tests passing (all crashed with
document is not defined)After: 13/17 tests passing (76% pass rate)
The 4 remaining failures are test logic issues (async timing, query mismatches), NOT DOM environment issues. The critical foundation is complete.
Testing
Ticket
Closes vertz-dev/vertz#ui-014 (Phase 1: DOM test environment + renderTest)
Notes
The testing utilities (
renderTest(), query helpers, interaction helpers) were already implemented in@vertz/ui/testand fully tested. This PR focuses on configuring the DOM environment for bun test in the task-manager example, which is the blocker for using those utilities.