import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { createRequire } from "node:module"; import test from "node:test"; import vm from "node:vm"; const require = createRequire(import.meta.url); const { transformSync } = require("esbuild"); const React = require("react"); const { renderToStaticMarkup } = require("react-dom/server"); const { MemoryRouter } = require("react-router"); function loadSource(path, bindings = {}) { const context = vm.createContext({ module: { exports: {} }, require, ...bindings }); context.exports = context.module.exports; vm.runInContext(transformSync(readFileSync(new URL(path, import.meta.url), "utf8"), { loader: path.endsWith(".tsx") ? "tsx" : "ts", format: "cjs", jsx: "automatic" }).code, context); return { exports: context.module.exports, context }; } const { generatedTranslations } = loadSource("../src/i18n/generatedTranslations.ts").exports; const launch = loadSource("../src/platform/launchContext.ts").exports; function harness(locale = "en") { const navigation = []; const translateText = (value) => { if (typeof value === "string") return generatedTranslations[locale][value] ?? value; let text = generatedTranslations[locale][value.key] ?? value.key; for (const [key, replacement] of Object.entries(value.values)) { text = text.replaceAll(`{${key}}`, replacement); } return text; }; const loaded = loadSource("../src/layout/BreadcrumbBar.tsx", { window: { history: { state: { idx: 7 } } }, require: (name) => { if (name === "../i18n/LanguageContext") return { usePlatformLanguage: () => ({ translateText }), i18nMessage: (key, values) => ({ key, values }) }; if (name === "../components/UnsavedChangesGuard") return { useGuardedNavigate: () => (...args) => navigation.push(args) }; if (name === "../platform/launchContext") return launch; return require(name); } }); const BreadcrumbBar = loaded.exports.default; return { ...loaded, navigation, BreadcrumbBar, links(pathname, search = "") { const html = renderToStaticMarkup(React.createElement( MemoryRouter, { initialEntries: [`${pathname}${search}`] }, React.createElement(BreadcrumbBar, { pathname }) )); return [...html.matchAll(/]*)>(.*?)<\/a>/g)].map(([, attributes, label]) => ({ href: /href="([^"]*)"/.exec(attributes)?.[1], label: label.replaceAll("&", "&") })); } }; } test("module-global reports and operator queue have their own bilingual labels and exact links", () => { for (const locale of ["en", "de"]) { const h = harness(locale); const root = generatedTranslations[locale]["i18n:govoplan-core.campaigns.01a23a28"]; for (const [route, key] of [ ["reports", "i18n:govoplan-core.reports.88bc3fe3"], ["queue", "i18n:govoplan-core.operator_queue.72492fb5"] ]) { for (const trailingSlash of ["", "/"]) { assert.deepEqual(h.links(`/campaigns/${route}${trailingSlash}`, "?campaign=selected-campaign"), [ { href: "/campaigns", label: root }, { href: `/campaigns/${route}`, label: generatedTranslations[locale][key] } ]); } } assert.equal(h.links("/operator")[0].label, generatedTranslations[locale]["i18n:govoplan-core.operator_queue.72492fb5"]); } }); test("campaign editor report aliases and attachment deep links retain their singular campaign context", () => { const h = harness(); const campaignId = "8ef65230-94d1-49a5-93a9-c5ef7c87ad45"; for (const suffix of ["report", "reports", "attachments"]) { const links = h.links(`/campaigns/${campaignId}/${suffix}`); assert.deepEqual(links.map((item) => item.href), ["/campaigns", `/campaigns/${campaignId}`, `/campaigns/${campaignId}/${suffix}`]); assert.equal(links[1].label, generatedTranslations.en["i18n:govoplan-core.campaign.69390e16"]); assert.equal(links[2].label, generatedTranslations.en[suffix === "attachments" ? "i18n:govoplan-core.attachments.6771ade6" : "i18n:govoplan-core.report.ee45c303"]); } }); test("quick-access return preserves guarded history back or the exact origin deep link", () => { const origin = launch.createQuickAccessLaunchContext({ pathname: "/cases/case-fixture", search: "?tab=work", hash: "#campaigns", historyIndex: 6, auth: { user: { account_id: "account-fixture" }, tenant: { id: "tenant-fixture" } }, temporalContext: { validityMode: "current" } }); const h = harness(); for (const historyIndex of [7, 20]) { h.context.window.history.state.idx = historyIndex; const tree = h.BreadcrumbBar({ pathname: "/campaigns/reports", locationState: launch.quickAccessLaunchState(origin) }); const button = React.Children.toArray(tree.props.children).find((item) => item.type === "button"); assert.ok(button, "the launch return action remains visible"); button.props.onClick(); } assert.deepEqual(h.navigation[0], [-1]); assert.equal(h.navigation[1][0], "/cases/case-fixture?tab=work#campaigns"); assert.equal(h.navigation[1][1].replace, true); });