import assert from "node:assert/strict"; import test from "node:test"; import { fileURLToPath } from "node:url"; import { build } from "esbuild"; // Bundle React together with the code under test so that both share one React instance. async function load(entry) { const result = await build({ stdin: { contents: entry, resolveDir: fileURLToPath(new URL("../src/", import.meta.url)), loader: "tsx" }, bundle: true, write: false, format: "esm", platform: "node", jsx: "automatic", logLevel: "silent", banner: { js: "import { createRequire } from \"node:module\"; const require = createRequire(process.cwd() + \"/package.json\");" }, }); const code = Buffer.from(result.outputFiles[0].text).toString("base64"); return import(`data:text/javascript;base64,${code}`); } const { renderToStaticMarkup, h, ProgressBar, highlight } = await load(` export { renderToStaticMarkup } from "react-dom/server"; export { createElement as h } from "react"; export { ProgressBar, highlight } from "./pages/TranslationParts"; `); const stats = { lines: 10, translated: 5, progress: 0.5, strings: 4, stringsTranslated: 2, states: { untranslated: 5, outdated: 1, translated: 3, fuzzy: 0, machine: 0, approved: 1 }, }; test("ProgressBar renders counts and only non-empty segments", () => { const html = renderToStaticMarkup(h(ProgressBar, { stats })); assert.match(html, /5 из 10 реплик \(50%\)/); assert.match(html, /устарело 1/); assert.match(html, /seg-approved/); assert.doesNotMatch(html, /seg-warn/); }); test("highlight wraps glossary terms case-insensitively and escapes regex characters", () => { const terms = [{ src: "Eileen", t: "Эйлин", note: "" }, { src: "a+b", t: "x", note: "" }]; const html = renderToStaticMarkup(h("p", null, highlight("eileen met a+b", terms))); assert.match(html, /eileen<\/mark>/); assert.match(html, /a\+b<\/mark>/); assert.equal(highlight("plain", []), "plain"); }); test("tags the game does not run stay plain, and a closing tag closes only its own tag", async () => { const { build } = await import("esbuild"); const { fileURLToPath } = await import("node:url"); const compiled = await build({ entryPoints: [fileURLToPath(new URL("../src/player/text.ts", import.meta.url))], bundle: true, write: false, format: "esm", platform: "node", logLevel: "silent" }); const { parseText, plainText } = await import(`data:text/javascript;base64,${Buffer.from(compiled.outputFiles[0].text).toString("base64")}`); const parsed = parseText("a{b}{bt=8}jump{/bt} still bold{/b} plain {chaos}odd{/chaos} end"); const styles = parsed.segments.filter((s) => s.kind === "text").map((s) => [s.text, !!s.style.b]); assert.deepEqual(styles, [["a", false], ["jump", true], [" still bold", true], [" plain ", false], ["odd", false], [" end", false]]); assert.equal(plainText(parsed), "ajump still bold plain odd end"); });