test(frontend): add jsdom + React Testing Library harness - #78
Merged
Conversation
Add the DOM test infrastructure the frontend suite was missing so
component- and page-level render tests are possible. Vitest now runs two
projects split by file extension: *.test.ts under node (existing src/lib
helper tests, untouched) and *.test.tsx under jsdom with React Testing
Library.
- Pin jsdom, @testing-library/{react,dom,user-event,jest-dom} as exact
dev dependencies.
- Add src/test/setup.ts (jest-dom matchers, per-test unmount, Mantine DOM
polyfills) and src/test/render.tsx (MantineProvider + router wrapper).
- Prove the harness end-to-end with a smoke test over the shipped P3-3
credential-load-failure warning (src/pages/NewScanPage.test.tsx).
- Exempt test files from react-refresh/only-export-components.
- Document the .test.ts/.test.tsx convention and renderWithProviders
pattern in CONTRIBUTING.md; log the harness in docs/ARCHIVE.md §14.
Infrastructure only — the M19/M20/M21/P3-3 page-level tests remain
follow-up work, now unblocked. See docs/reviews/STATUS.md test-debt.
tyler-rich
added a commit
that referenced
this pull request
Jul 26, 2026
…s structure, correct a false CVE claim in the CHANGELOG (#102) * docs(archive): make §14 contiguous, add a newest-first index, and add the finding-ID decoder Twelve dated §14 entries — every one from 2026-07-09 onward, including all the recent work — sat underneath `## Build performance` rather than under §14, so anyone scrolling §14 to the end stopped short of them. Moved the Build performance section to the end of the file instead of re-parenting the entries: it is self-contained and cross-referenced by heading name (from CLAUDE.md and four workflows), not by position, so nothing breaks. All 104 dated entries are now under §14. Added a newest-first index at the top of §14, one anchored line per entry. The entries themselves are deliberately NOT reordered: sixteen of them refer to each other relatively ("the entry below", "superseded by the entry above"), and a sort would silently invert every one. The three ordering regimes are documented instead, and the index is sorted by date regardless of physical position, so lookup no longer depends on the scroll order. Added §15, a finding-ID index: one row per SEC/SC/APIR/CON/P1-P3/D/R/QUA/INF/ FE/API/FEAT/DOC/SCN id with a one-line description and its resolving PR. §14 cites these ids bare and never re-explains them; this is the decoder that replaces the docs/reviews/ reports. It also records the SEC-* prefix collision between the two reviews that reused it. Corrected §0 locked decision #7: it said CVE-2025-15366 and CVE-2025-15367 are both unfixable on 3.14. That is true of released 3.14.6 but not of the 3.14 line — the imaplib backport landed on the maintenance branch and closes on 3.14.7 (issue #98). Only the poplib CVE remains 3.15-only (#52). * docs(changelog): correct the CVE-2025-15366 claim under [Unreleased] The Python 3.14 entry said all four waived CPython CVEs remain unfixable until 3.15 because upstream declined the backport to 3.10-3.14, and pointed at issue #52 for all of them. Both halves are false, and this text ships verbatim as the next release's notes. Checked against ci/grype.yaml and the two 2026-07-26 §14 entries: the imaplib backport for CVE-2025-15366 merged onto the CPython 3.14 branch on 2026-07-07 — 18 days before the entry was written — so it closes on 3.14.7, not 3.15, and it was regrouped into Group A alongside CVE-2026-15308 and CVE-2026-12003, tracked in issue #98. Only CVE-2025-15367 (poplib) is genuinely 3.15-only and still tracked in #52. What was true and is kept: released 3.14.6 carries neither guard, so the upgrade cleared nothing at the pinned version. * docs: strike completed roadmap items, surface the settings-level work, add two process rules ROADMAP: - Struck "Pin GitHub Actions to commit SHAs" (done in #57 — ci.yml has 8 SHA-pinned uses:, dev-nightly 3, publish 3, rescan 2) and "Frontend test runner" (done in #78 — vitest 3.2.7, "test": "vitest run", 20 test files). - Rewrote "Row-bound secret AAD", which was false as stated: row binding is implemented (secret_store.py row_aad(), L1/SEC-7, #64) and every write is row-bound. What remains is only the bulk re-encryption of legacy column-only ciphertext so the read fallback can be dropped, so it is folded into the existing "Admin bulk secret re-encryption" item. - Extended the public-repo governance checklist with five settings-level items that existed only in §14 prose and were therefore invisible: Actions workflow permissions -> read-only, confirm GHCR package visibility is public (the original check asked for Private and its premise inverted when the repo went public), delete the unused DOCKERHUB_* secrets, set the GitHub profile display name to tyler-rich, and confirm Dependabot security alerts are on. CLAUDE.md § Git & PR conventions gains two rules learned the hard way: a stacked child PR retargeted after its parent was squash-merged needs git rebase --onto (flipping the base in the UI re-computes the merge base and balloons the diff), and on: pull_request does not fire on 'edited', so a base change never re-runs CI and the green check you are looking at is from the old base. CONTRIBUTING § Releasing gains a "Before you tag" checklist — CHANGELOG [Unreleased] reviewed (it ships verbatim), THIRD_PARTY_LICENSES verified against the versions actually pulled, Dependabot PRs triaged, requirements.lock regenerated — plus the two after-tag steps: back-merge main into dev, and re-run rescan.yml. * docs: delete docs/reviews and docs/upgrades, sweep every inbound reference The twelve review reports and the Python 3.14 handoff doc held only closed findings, and sat at the same directory level as the two live documents. They are removed rather than moved to a docs/history/ subtree: the only real argument against deleting them was that §14 cites their finding ids bare and never re-explains them, and §15 (previous commit) answers that directly. Git is the archive for the rest. docs/ now contains exactly ARCHIVE.md, ROADMAP.md, and screenshots/. The originals stay retrievable — the pre-deletion commit is 0780b07, and the §14 entry records the git show incantation. Nothing was rewritten before deletion. Swept every inbound reference the audit enumerated, plus the ones it did not: CONTRIBUTING § Project layout (both directories dropped, screenshots/ added), CONTRIBUTING § API conventions, CHANGELOG's L13/APIR-8 citation, and both dependabot.yml D3 comments now point at ARCHIVE §15. Inside §14, 59 docs/reviews/ and 7 docs/upgrades/ path prefixes were stripped so the entries name the reports as documents rather than as paths that no longer resolve, with a note at the top of §14 sending the reader to §15. Fixed the dead claude-md-compliance-review.md link (a filename that never existed). Left one docs/upgrades/ mention deliberately: the 2026-07-25 entry's record of what CONTRIBUTING's layout listing omitted is a statement about that date, marked '(as it then was)'. Verified no workflow, test, or source file referenced either directory, and that the four '§ Build performance' cross-references are by heading name and survive that section's move. Added the dated §14 entry recording all of it, including that docs/history/ was considered and rejected, and two corrections to the audit: twelve entries were misfiled under Build performance (not fourteen — the other two are that section's own sub-headings), and there are 42 remote branches with 36 prunable (not 39/33).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the frontend DOM test infrastructure that was missing, so component- and page-level render tests are now possible. Previously Vitest ran only in the
nodeenvironment, limiting coverage to the puresrc/lib/helpers — which blocked proper tests for four already-shipped fixes (P3-3, M19, M20, M21). Seedocs/reviews/STATUS.md§ "Test debt on already-shipped fixes."This lands the harness and proves it works end-to-end. It deliberately does not backfill the M19/M20/M21/P3-3 page-level tests — that is follow-up work, now unblocked.
What changed
frontend/vite.config.ts):*.test.ts→node(the existingsrc/lib/helper tests, untouched)*.test.tsx→jsdom+ React Testing Library[email protected],@testing-library/[email protected],@testing-library/[email protected],@testing-library/[email protected],@testing-library/[email protected].src/test/setup.ts— jest-dom matchers, per-test unmount, and thematchMedia/ResizeObserver/scrollIntoViewpolyfills Mantine needs under jsdom (loaded only by the jsdom project).src/test/render.tsx— sharedrenderWithProviderswrappingMantineProvider+ a router, re-exporting the Testing Library surface.src/pages/NewScanPage.test.tsx— one smoke test proving render, query, and a Retry click against the shipped P3-3 credential-load-failure warning.eslint.config.js— override turning offreact-refresh/only-export-componentsfor test files/utilities (outside the Fast-Refresh graph).CONTRIBUTING.md— documents the.test.ts→node /.test.tsx→jsdom convention and therenderWithProviderspattern.Verification
npm test— 22 passed (both node and jsdom projects)npm run lint— clean (0 errors, 0 warnings)npm run format:check— cleannpm run build—tsc -b(type-checks the new test files) +vite buildpassnpm ci— lockfile in syncSee
docs/ARCHIVE.md§ Deviations for the dated entry added in this change.