feat: spellcheck menu, typewriter mode, file associations, updater hardening
English spellcheck suggestions with Add-to-dictionary in the native context menu plus a Settings toggle. Typewriter caret-centering mode. OS file associations for .md/.txt and Open File wording. Updater: release URL surfaced, single progress listener, two-byte tarball check, installer wait guard. Search/installer test suites registered; chapter-list layout polish; ignore KDE .directory files.
This commit is contained in:
parent
1413e73015
commit
542a545c0d
17 changed files with 445 additions and 73 deletions
41
tests/run-search-test.mjs
Normal file
41
tests/run-search-test.mjs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Standalone test for the whole-book search helpers (src/renderer/book/ui.ts).
|
||||
// These pure functions power the Search modal: Markdown flattening, literal
|
||||
// matching (phrases included), and result snippets.
|
||||
// Run with: node tests/run-search-test.mjs
|
||||
import { bundleForTest } from "./helpers/bundle.mjs";
|
||||
|
||||
const { mod: ui, cleanupBundle } = await bundleForTest({
|
||||
name: "folio-search-ui",
|
||||
entryPoints: ["src/renderer/book/ui.ts"],
|
||||
});
|
||||
const { findMatches, markdownToPlain, makeSnippet, moveInList, escapeHtml } = ui;
|
||||
|
||||
let failures = 0;
|
||||
function ok(cond, msg) {
|
||||
if (cond) console.log(" ok -", msg);
|
||||
else { failures++; console.error("FAIL -", msg); }
|
||||
}
|
||||
|
||||
// markdown -> searchable plain text
|
||||
ok(markdownToPlain("# Title\nSome **bold** text") === "Title\nSome bold text", "headings/emphasis flattened");
|
||||
ok(markdownToPlain("[link](http://x)") === "link", "links flattened to text");
|
||||
ok(markdownToPlain("`code`") === "code", "inline code flattened");
|
||||
|
||||
// literal matching incl. phrases, case handling
|
||||
ok(JSON.stringify(findMatches("hello world hello", "hello", true)) === "[0,12]", "finds all occurrences");
|
||||
ok(findMatches("Hello", "hello", true).length === 0, "match-case respected");
|
||||
ok(findMatches("Hello", "hello", false).length === 1, "case-insensitive match");
|
||||
ok(JSON.stringify(findMatches("the quick brown fox", "quick brown", false)) === "[4]", "phrase search works");
|
||||
ok(findMatches("a.b", "a.b", false).length === 1, "regex chars treated literally");
|
||||
|
||||
// snippets highlight the match and escape HTML
|
||||
const snip = makeSnippet("say <hi> & bye", 4, 4);
|
||||
ok(snip.includes("<mark>") && snip.includes("<hi>"), "snippet highlights + escapes");
|
||||
|
||||
// shared reorder math used by drag + keyboard reorder
|
||||
ok(JSON.stringify(moveInList([1, 2, 3], 0, 2)) === "[2,3,1]", "moveInList moves item");
|
||||
ok(escapeHtml("<a>&") === "<a>&", "escapeHtml works");
|
||||
|
||||
cleanupBundle();
|
||||
if (failures) { console.error(`${failures} search check(s) FAILED`); process.exit(1); }
|
||||
console.log("All search checks passed.");
|
||||
Loading…
Add table
Add a link
Reference in a new issue