Add JavaScript testing framework with Vitest + jsdom#378
Add JavaScript testing framework with Vitest + jsdom#378rvanmaanen wants to merge 3 commits intomainfrom
Conversation
Summary: Introduced comprehensive JavaScript unit testing using Vitest and jsdom, covering all 9 JS files with 114 tests. Integrated into CI/CD pipelines and local Run command. Removed unused TocDebug feature. Implementation: • Added Vitest + jsdom dev dependencies and vitest.config.js • Created 9 test files in tests/javascript/ covering all client-side JS modules • Integrated JavaScript tests into TechHubRunner.psm1 (Phase 1.5, shortcuts) • Added test-javascript job to CI and CD GitHub Actions workflows • Removed unused TocDebug overlay feature from toc-scroll-spy.js • Updated documentation: testing-strategy, javascript, running-and-testing, repository-structure
There was a problem hiding this comment.
Pull request overview
This PR introduces a JavaScript unit-testing setup (Vitest + jsdom) for the TechHub Web client-side JS modules, wires it into CI/CD and the local Run workflow, and removes an unused TOC debug feature.
Changes:
- Add Vitest/jsdom configuration and 9 new JS test suites covering the existing
wwwroot/js/modules. - Integrate JavaScript tests into GitHub Actions (CI + CD) quality gates and the local PowerShell runner (
Run -TestProject javascript). - Remove the TOC scroll spy debug overlay/toggle functionality and update docs/AGENTS guidance accordingly.
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.js | Adds Vitest configuration targeting jsdom + tests/javascript/**/*.test.js. |
| package.json | Adds vitest and jsdom dev dependencies and npm test scripts. |
| package-lock.json | Locks the newly added Vitest/jsdom dependency graph. |
| scripts/TechHubRunner.psm1 | Adds JavaScript test execution to Run and a JS-only mode. |
| src/TechHub.Web/wwwroot/js/toc-scroll-spy.js | Removes the TocDebug overlay/toggle functionality. |
| tests/javascript/infinite-scroll.test.js | Adds unit tests for infinite-scroll module behavior and lifecycle. |
| tests/javascript/toc-scroll-spy.test.js | Adds unit tests for TOC scroll spy behavior (active heading, collapse state, cleanup, etc.). |
| tests/javascript/sidebar-toggle.test.js | Adds unit tests for sidebar collapse toggle + cookie behavior. |
| tests/javascript/hero-banner.test.js | Adds unit tests for hero banner cookie persistence helpers. |
| tests/javascript/mobile-nav.test.js | Adds unit tests for scroll lock/unlock + Escape handler. |
| tests/javascript/nav-helpers.test.js | Adds unit tests for nav helper UI creation and behavior. |
| tests/javascript/date-range-slider.test.js | Adds unit tests for dual-range clamping + fill positioning. |
| tests/javascript/custom-pages.test.js | Adds unit tests for custom page DOM behaviors (collapsibles, filters, badges). |
| tests/javascript/page-scripts.test.js | Adds unit tests for page script orchestrator globals and early-return behavior. |
| tests/javascript/AGENTS.md | Introduces conventions/guidance for the new JS test suite. |
| tests/AGENTS.md | Documents JavaScript testing as a first-class test type. |
| docs/testing-strategy.md | Updates strategy docs to include JavaScript tests and guidance on mocking. |
| docs/running-and-testing.md | Documents Run -TestProject javascript and test execution order. |
| docs/repository-structure.md | Documents tests/javascript/ in repository layout. |
| docs/javascript.md | Documents JS module list and how to run JavaScript tests. |
| .github/workflows/ci.yml | Adds test-javascript job and gates it via quality-gate. |
| .github/workflows/cd.yml | Adds test-javascript job and gates it via quality-gate. |
| .github/copilot-instructions.md | Adds tests/javascript/ to the AGENTS discovery list. |
🚀 PR Preview EnvironmentA preview environment has been deployed for this pull request.
Note The environment uses an isolated PostgreSQL database (cloned from production via PITR) and runs in the staging Azure Container Apps Environment. |
|
@copilot both in main and on this branch there are failing e2e tests: failed�[m TechHub.E2E.Tests.Web.ContentDetailTests.ContentDetailPage_OldDatePrefixedURL_Returns404 (851ms)�[m
Please investigate and fix. Add tests where possible |
- Rename ContentDetailPage_OldDatePrefixedURL_Returns404 to RedirectsToCleanUrl and switch to HttpClient to verify 301 redirect without following it. Page.GotoAsync was throwing PlaywrightException for redirect-then-404 scenarios. - Fix BackNavigation_AfterInfiniteScroll_DoesNotTriggerCascade by moving scroll-up to immediately after ScrollToLoadMoreAsync (before CountAsync). OnAfterRenderAsync's immediate handleScroll check now sees the safe position before it can trigger cascade batch loads that inflate GridStateCache. Agent-Logs-Url: https://github.com/techhubms/techhub/sessions/a3345826-0ea2-416a-9904-ce3787af7b6d Co-authored-by: rvanmaanen <4835258+rvanmaanen@users.noreply.github.com>
Investigated and fixed both failures in commit c95eac4.
|
Summary: Fix issues flagged by Copilot review on the JavaScript testing framework PR: correct event dispatch in slider tests, harden npm prerequisite handling, fix stale-dependency risk, align docs with actual test execution order, and resolve a CodeQL null dereference. Implementation: • tests/javascript/date-range-slider.test.js: dispatch events from slider elements directly instead of patching event.target on the container, making tests reliable in jsdom • scripts/TechHubRunner.psm1: add explicit npm availability check before running JS tests; run npm ci unconditionally to prevent stale node_modules • docs/running-and-testing.md: correct test execution order to PowerShell first, then JavaScript/Vitest (matching actual runner phases) • tests/TechHub.E2E.Tests/Web/ContentDetailTests.cs: add null guard after NotBeNullOrEmpty assertion to satisfy CodeQL and eliminate potential null dereference • .github/prompts/address-pr-reviews.prompt.md: update Step 7 run command from Run -SkipE2E to Run -Clean
| beforeEach(() => { | ||
| document.body.innerHTML = ''; | ||
| document.documentElement.className = ''; | ||
|
|
||
| delete window.TechHub; | ||
| delete window.__scrollRestoredAt; | ||
|
|
||
| Object.defineProperty(window, 'scrollY', { | ||
| value: 0, | ||
| writable: true, | ||
| configurable: true, | ||
| }); | ||
|
|
||
| Object.defineProperty(window, 'pageYOffset', { | ||
| value: 0, | ||
| writable: true, | ||
| configurable: true, | ||
| }); | ||
|
|
||
| window.scrollTo = vi.fn(); | ||
|
|
||
| // Mock history | ||
| window.history.replaceState = vi.fn(); | ||
| window.history.back = vi.fn(); | ||
| Object.defineProperty(window.history, 'length', { | ||
| value: 5, | ||
| writable: true, | ||
| configurable: true, | ||
| }); | ||
|
|
||
| // Mock location | ||
| Object.defineProperty(window, 'location', { | ||
| value: { | ||
| pathname: '/all', | ||
| search: '', | ||
| hash: '', | ||
| href: 'https://localhost/all', | ||
| }, | ||
| writable: true, | ||
| configurable: true, | ||
| }); | ||
|
|
||
| // Ensure rAF executes synchronously for tests | ||
| originalRAF = window.requestAnimationFrame; | ||
| window.requestAnimationFrame = (cb) => { cb(); return 1; }; | ||
| window.cancelAnimationFrame = vi.fn(); | ||
|
|
||
| vi.resetModules(); | ||
| }); |
There was a problem hiding this comment.
nav-helpers.js starts a 200ms setInterval (with a 10s timeout) when Blazor is undefined. In this test file, Blazor is never stubbed before import(MODULE_PATH), so each import will register a long-lived interval/timeout that can keep the Vitest process alive and make the suite slow/flaky. Stub globalThis.Blazor with an addEventListener function (or otherwise disable the retry loop) before importing, and clean it up in afterEach/afterAll to avoid leaking globals between tests.
There was a problem hiding this comment.
Fixed: Added \globalThis.Blazor = { addEventListener: vi.fn() }\ in \�eforeEach\ and \delete globalThis.Blazor\ in \�fterEach. With Blazor stubbed, \ rySetupBlazorListeners\ takes the happy path immediately (calls \Blazor.addEventListener) and never enters the 200ms setInterval/10s timeout loop. Tests remain isolated.
| # Verify npm is available | ||
| if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { | ||
| Write-Host " npm not found on PATH — skipping JavaScript tests" -ForegroundColor Yellow | ||
| Write-Host " Please install Node.js: https://nodejs.org" -ForegroundColor Yellow | ||
| return $true | ||
| } |
There was a problem hiding this comment.
Invoke-JavaScriptTests returns $true when npm is not available, even when the user explicitly requested Run -TestProject javascript/js/vitest. That makes the command report success while silently skipping the requested test suite. Consider returning $false (and a clear prerequisite error) when JavaScript tests are explicitly selected, while optionally keeping the “skip with warning” behavior only for the default full Run if you want JS tests to be optional locally.
There was a problem hiding this comment.
Fixed: Added a -Required\ switch parameter to \Invoke-JavaScriptTests. When JavaScript tests are explicitly selected (-TestProject javascript), the function is called with -Required\ and returns \False\ on missing npm (clear error message). In the default full-\Run\ path it is called without -Required\ and still skips gracefully with a yellow warning.
Summary
Introduces comprehensive JavaScript unit testing for all client-side JS modules using Vitest and jsdom. Previously, the 9 JavaScript files in the web project had no automated test coverage — bugs could slip through undetected. This PR adds 114 tests covering all modules and integrates them into both CI/CD pipelines and the local development workflow.
Changes
Testing Framework
pm test and
pm run test:watch scripts
Test Coverage (114 tests across 9 files)
av-helpers.test.js — active link highlighting, section matching
CI/CD Integration
Local Development Integration
Code Cleanup
Documentation
Copilot Review Fixes