Skip to content

test(scripts): re-anchor 12 assertions that could not fail - #449

Merged
PathGao merged 1 commit into
masterfrom
fix/tests-that-cannot-fail-values
Aug 3, 2026
Merged

test(scripts): re-anchor 12 assertions that could not fail#449
PathGao merged 1 commit into
masterfrom
fix/tests-that-cannot-fail-values

Conversation

@PathGao

@PathGao PathGao commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Twelve assertions in twelve test files survive the defect they name. Each was reproduced first: the mutation applied to a clean worktree, npm test run, 584/584 green, source restored. None of them is the failure #440 fixed — those were anchors that were missing, so the slice degenerated to "". These are anchors that are too far apart, values compared against the constant they were read from, and assertions with no reachable subject.

These tests are recent, and they were added by the same series of changes that is now fixing them. Ten of the twelve files did not exist at v2.6.14; only editorToolbar.test.ts and windowClosePerTab.test.ts predate it. This is not inherited debt.

Based on df80968 (#447). npm test 586/586, npm run check 638 files / 0 errors, npm run build clean. No Rust touched.

The one that was live

mermaidPrintTheme.test.ts exists so that PDF export renders diagrams light — Mermaid bakes theme colours into the SVG as attributes, so a dark preview exports dark boxes with dark text onto white paper. The file asserted assert.deepEqual(mermaid.themes, [MERMAID_PRINT_THEME]), and MERMAID_PRINT_THEME is the constant renderDiagramsForPrint reads.

-export const MERMAID_PRINT_THEME = 'neutral';
+export const MERMAID_PRINT_THEME = 'dark';

584 tests, 584 passing. Every PDF export re-themes every diagram dark, and the file whose whole purpose is the print theme has nothing to say about it.

Making the implementation stop using the constant is caught, so the call sequencing was real — only the value was unpinned. The assertion now spells 'neutral', and MERMAID_PRINT_THEME was exported for nothing else, so the export goes with it.

Shape 1 — value pins that pin nothing

site what it said what it holds now
mermaidPrintTheme.test.ts:103,108,114 deepEqual(mermaid.themes, [MERMAID_PRINT_THEME]) ['neutral'] — the literal is the claim
editorToolbar.test.ts:14-26,41 every expected value derived from DEFAULT_EDITOR_TOOLBAR_ORDER, which is EDITOR_TOOLBAR_TOOLS.map(t => t.id) the id list as literals, plus each tool's label / name / shortcut

Deleting the Underline tool from the editor toolbar catalogue outright left the whole file green: expectations written in terms of a derived constant shrink with it. titlebarToolbar.test.ts has the same derived shape but also asserts literal id lists, so the same deletion there reddens three tests; editorToolbar.test.ts now does too. The added test also covers name, label, group and shortcut, which nothing tested — a tool that silently loses its accelerator still renders.

Shape 2 — discriminators neutralised

exportRichContent.test.ts:299 — "a document with no math carries no KaTeX fonts at all" called inlineKatexFontFaces(css, new Set(), new Map()). The empty byte map deletes every face through the "bytes could not be read" branch, so the empty family set decides nothing. Deleting the family filter from exportFonts.ts:171 was green across the whole suite, integration assertions included. The test now supplies every face's bytes, so the family filter is the only thing left that can drop them.

previewAnchorRestore.test.ts:327/import \{[\s\S]*findAnchorElement[\s\S]*\} from '\.\/utils\/previewAnchor\.js'/. Both gaps are unbounded, so the match starts at the first import in the file and runs past every brace between there and line 46. Forking findAnchorElement / getAnchorScrollTop into another module, leaving the rest of the import in place, was green. Now read out of the one import statement ([^}]*) and checked as a specifier list.

editorPdfExport.test.ts:379-380 — the test is named "a failed refresh does not pass off a stale export as a fresh one" and asserted /catch \(error\)/ and /addToast\(/.

-addToast('Exported PDF may not include the latest edits', 'warning');
+addToast('Export refreshed', 'success');

Green, both regexes still matching, with the claim in the test's name inverted. The export deliberately still goes ahead on a failed refresh — printing the stale DOM beats not printing — so the entire contract lives in the severity. That is what is asserted now: exactly one toast in the catch, severity warning.

Shape 3 — over-fitted spellings

Two doesNotMatch guards pinned the exact one-line spelling a fixed defect happened to be written in. Both defects were reintroduced in ordinary brace / for…of spelling; both green.

liveModeWatchedPath.test.ts:26/isLiveMode\(\)\) invoke\('watch_file'/ against documentSession.svelte.ts, where neither token occurs any more. #296 removed the isLiveMode option from that module entirely, so the guard has been reading a file that cannot contain its pattern. Re-anchored to who may own the watcher: filesMatching(readSourceFiles('src'), /invoke\(\s*'watch_file'/) must be ['src/lib/MarkdownViewer.svelte'], and callbackBodies(viewer, '$effect') must contain exactly one effect that watches — which is also where the matching unwatch_file has to live.

windowClosePerTab.test.ts:25/tabManager\.tabs\.forEach\(\(t\) => \(t\.isDirty = false\)\)/. Now /\.isDirty\s*=\s*false/ over the close handler: the assignment, not the loop it is written in. (This is one of the two files that predate v2.6.14.)

Deleted rather than repaired

Five sites have no reachable subject. Each is dominated by an assertion that already covers the ground, named in a comment where the dead one was.

site why it cannot fail what covers it
exportSanitize.test.ts:56 assert.match(POC, /onerror=/)POC is a template literal three lines above the config assertions below it; uriIsAllowed('x') runs the real regexp and stays
i18nCoverage.test.ts:453 assert.ok(total >= 0) on a sum of array lengths :249 every key the source asks for exists in English, :267 no language defines a key English does not have
settingsPersistence.test.ts:195 new SettingsStore() instanceof SettingsStore — a constructor that throws fails the line above, one that returns fails nothing the effect-count assertions two lines down, which are the point of the test
renderProtocol.test.ts:252-256 underscore counts of two strings :242 already asserted strictly equal :242-246
scrollSync.test.ts:52 (200/1000)*600 === 120 over the file's own two fixture constants :54-55, on numbers the mapping returned

The renderProtocol case was checked rather than argued: making processDisplayMathBlocks strip underscores from data-math-source fails at line 242, so line 252 never runs.

scrollSync.test.ts:52's 120 is genuinely useful documentation — it is the number the whole two-section design exists to avoid — so it stays, in the comment that already stated it.

Reported as unreachable, and is not

exportSanitize.test.ts:68assert.equal(MARKDOWN_SANITIZE_CONFIG.ALLOWED_URI_REGEXP, ALLOWED_MARKDOWN_URI_REGEXP) compares the field against the constant it is assigned from one line earlier in sanitize.ts, and the two are the same object reference. But the assignment is reachable:

-	ALLOWED_URI_REGEXP: ALLOWED_MARKDOWN_URI_REGEXP,
+	ALLOWED_URI_REGEXP: /^[\s\S]*$/,

fails it, and previewSanitize.test.ts with it. Left as it stands.

Mutation check

Each mutation applied to df80968, the suite run, the source restored; then re-applied against this branch. "before" is the full suite (584 tests at df80968), "after" is the file under test.

# site mutation before after
1 mermaidPrintTheme:103,108,114 MERMAID_PRINT_THEME 'neutral''dark' 584/584 green RED — exporting re-renders with the print theme…: actual: [ 'dark' ], expected: [ 'neutral' ]
2 mermaidPrintTheme:187-189 divert only MarkdownViewer.svelte:1072 (preview) to mermaidTheme: 'dark', leaving the HTML export at 1886 584/584 green RED — the PDF export wraps the print render…: actual: [ "'dark'" ], expected: [], every diagram render must resolve the theme the way the print restore does (currentMermaidTheme())
3a mermaidPrintTheme:152 delete if (diagrams.length === 0) return () => {}; RED — the helper is inert…: actual: [ 'neutral' ], expected: [], nothing to re-render must not re-theme mermaid
3b mermaidPrintTheme:152 delete if (!root || !mermaid) return () => {}; RED — the helper is inert…: TypeError: Cannot read properties of null (reading 'initialize')
4 editorToolbar:14-26,41 delete the Underline tool from EDITOR_TOOLBAR_TOOLS 584/584 green RED (3) — the default order is the whole tool catalogue…, each tool carries the label, name and shortcut…, getVisibleEditorToolbarTools applies saved order and hidden ids
5 exportRichContent:299 delete if (!usedFamilies.has(face.family)) continue; from exportFonts.ts:171 584/584 green RED — a document with no math carries no KaTeX fonts at all: input matched /@font-face/
6 previewAnchorRestore:327 fork findAnchorElement / getAnchorScrollTop into a second module, leave the other two specifiers 584/584 green RED — the viewer restores through the measured resolver: actual: [ 'findAnchorElement', 'getAnchorScrollTop' ], expected: []
7 editorPdfExport:379-380 warning toast → addToast('Export refreshed', 'success') 584/584 green RED — a failed refresh does not pass off a stale export…: actual: [ 'success' ], expected: [ 'warning' ]
8 liveModeWatchedPath:26 documentSession.loadMarkdown re-issues invoke('watch_file', …) in an ordinary if (…) { … } 584/584 green RED — Live Mode follows the active file…: actual: [ 'src/lib/MarkdownViewer.svelte', 'src/lib/sessions/documentSession.svelte.ts' ], expected: [ 'src/lib/MarkdownViewer.svelte' ]
9 windowClosePerTab:25 for (const t of tabManager.tabs) t.isDirty = false; at the top of the dirty branch 584/584 green RED — the aggregate unsaved-files modal is gone from the close handler
10 renderProtocol:252-256 data-math-source written with underscores stripped RED at :242, never reaching :252 — which is why :252-256 is deleted
11 exportSanitize:68 ALLOWED_URI_REGEXP: /^[\s\S]*$/ RED (2) — does not reproduce unchanged

One honest gap. The survey's mutation for site 3 was make the early-return closure write a global; that is still green here, and the rewritten test does not claim otherwise. Writing an unrelated global is not a defect shape this helper has. What the test now claims — and what 3a and 3b prove — is that the handle the export's finally calls re-themes nothing and touches no DOM.

Not covered

truncatedBufferGuard, viewModeWithoutSaving, previewSanitize, windowOrganization, recentFilesMultiWindow and editorContextMenuI18n are untouched here — six sites where an unprotected guard, rather than a dead assertion, is the finding.

🤖 Generated with Claude Code

Twelve assertion sites across twelve test files were verified to survive the
defect they name. Each was reproduced by applying the mutation to a clean
worktree and running the whole suite green before it was touched.

Three shapes:

  * value pins written in terms of the constant the implementation reads, so
    changing the constant satisfies them ('neutral' -> 'dark' for every PDF
    export re-themes diagrams dark, undetected);
  * discriminators neutralised by the arguments the test supplies, or by an
    unbounded gap in a source regex that lets the match land on a different
    site than the one under test;
  * assertions with no reachable subject at all - a fixture restated back to
    itself, a sum of array lengths asserted non-negative, `new X() instanceof
    X`, and an underscore count between two strings the line above already
    asserted equal.

Six of these were deleted rather than repaired, each dominated by a stronger
executable assertion that is named in a comment where it was removed.

`MERMAID_PRINT_THEME` was exported only so a test could compare the print
theme against itself; the assertion now spells 'neutral' and the export is
gone. No other behaviour in `src/` or `src-tauri/` changes.

`exportSanitize.test.ts:68` was reported as unreachable and is not: replacing
`MARKDOWN_SANITIZE_CONFIG.ALLOWED_URI_REGEXP` with a permissive pattern fails
it. Left as it stands.

Ten of the twelve files did not exist at v2.6.14. This is debt from the recent
PR series, not inherited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@PathGao
PathGao force-pushed the fix/tests-that-cannot-fail-values branch from a62a6eb to 77211ab Compare August 3, 2026 13:36
@PathGao
PathGao merged commit 086f6fd into master Aug 3, 2026
4 checks passed
@PathGao
PathGao deleted the fix/tests-that-cannot-fail-values branch August 5, 2026 06:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant