const assert = require("assert"); const fs = require("fs"); const path = require("path"); const tests = []; const test = (name, fn) => tests.push({ name, fn }); const loadSource = (...parts) => { const filePath = path.join(__dirname, "..", "..", ...parts); return fs.readFileSync(filePath, "utf8"); }; const loadBreadcrumbSource = () => loadSource("components", "breadcrumbs.js"); const loadFactorySource = () => loadSource("lib", "routing", "breadcrumbRendererFactories.js"); test("breadcrumbs/factory module includes expected mapped route definitions", async () => { const source = loadFactorySource(); assert.strictEqual( source.includes("export const createSimpleRouteRenderers ="), true, "Expected simple route renderer factory export" ); assert.strictEqual( source.includes("export const createSimpleLinkTextPairRenderers ="), true, "Expected link-text pair renderer factory export" ); assert.strictEqual( source.includes("export const createSimpleMyPortalRouteRenderers ="), true, "Expected my-portal route renderer factory export" ); assert.strictEqual( source.includes("export const createNewAppealRouteRenderers ="), true, "Expected new-appeal route renderer factory export" ); assert.strictEqual( source.includes("export const createCallbackRouteRenderers ="), true, "Expected callback route renderer factory export" ); assert.strictEqual( source.includes("export const createStepBackRouteRenderers ="), true, "Expected step-back route renderer factory export" ); assert.strictEqual( source.includes("export const createRepresentationRouteRenderers ="), true, "Expected representation route renderer factory export" ); assert.strictEqual( source.includes("export const createCaseDetailRouteRenderers ="), true, "Expected case detail route renderer factory export" ); assert.strictEqual( source.includes("export const createDetailAndAccountRouteRenderers ="), true, "Expected detail and account route renderer factory export" ); assert.strictEqual( source.includes('"/addresssearchresults": () => ('), true, "Expected /addresssearchresults to be mapped in createSimpleLinkTextPairRenderers" ); assert.strictEqual( source.includes('"/advancedsearchresults": () => ('), true, "Expected /advancedsearchresults to be mapped in createSimpleLinkTextPairRenderers" ); assert.strictEqual( source.includes('"/myportal/searchresults": () => ('), true, "Expected /myportal/searchresults to be mapped in createSimpleMyPortalRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/viewall": () =>'), true, "Expected /myportal/viewall to be mapped in createSimpleMyPortalRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/advancedsearchresults": () => ('), true, "Expected /myportal/advancedsearchresults to be mapped in createSimpleMyPortalRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/addresssearchresults": () => ('), true, "Expected /myportal/addresssearchresults to be mapped in createSimpleMyPortalRouteRenderers" ); assert.strictEqual( source.includes('"/newappeal/selectappeal": () => ('), true, "Expected /newappeal/selectappeal to be mapped in createNewAppealRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/case/id/[incident]": () => ('), true, "Expected /myportal/case/id/[incident] to be mapped in createCallbackRouteRenderers" ); assert.strictEqual( source.includes('"/case": () => ('), true, "Expected /case to be mapped in createCallbackRouteRenderers" ); assert.strictEqual( source.includes('"/newappeal/[appealtypes]": () => {'), true, "Expected /newappeal/[appealtypes] to be mapped in createStepBackRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/[appealtypes]": () => {'), true, "Expected /myportal/[appealtypes] to be mapped in createStepBackRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/representation": () => ('), true, "Expected /myportal/representation to be mapped in createRepresentationRouteRenderers" ); assert.strictEqual( source.includes('"/case/[ticketnumber]": () =>'), true, "Expected /case/[ticketnumber] to be mapped in createCaseDetailRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/case": () =>'), true, "Expected /myportal/case to be mapped in createCaseDetailRouteRenderers" ); assert.strictEqual( source.includes('"/case/id/[incident]": () =>'), true, "Expected /case/id/[incident] to be mapped in createCaseDetailRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/case/[ticketnumber]": () =>'), true, "Expected /myportal/case/[ticketnumber] to be mapped in createCaseDetailRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/dnsdetails": () =>'), true, "Expected /myportal/dnsdetails to be mapped in createDetailAndAccountRouteRenderers" ); assert.strictEqual( source.includes('"/myportal/dns/[developmentName]": () =>'), true, "Expected /myportal/dns/[developmentName] to be mapped in createDetailAndAccountRouteRenderers" ); assert.strictEqual( source.includes('"/dnsdetails": () =>'), true, "Expected /dnsdetails to be mapped in createDetailAndAccountRouteRenderers" ); assert.strictEqual( source.includes('"/dns/[developmentName]": () =>'), true, "Expected /dns/[developmentName] to be mapped in createDetailAndAccountRouteRenderers" ); assert.strictEqual( source.includes('"/dns/application-view": () =>'), true, "Expected /dns/application-view to be mapped in createDetailAndAccountRouteRenderers" ); assert.strictEqual( source.includes('"/account/personaldetails": () =>'), true, "Expected /account/personaldetails to be mapped in createDetailAndAccountRouteRenderers" ); assert.strictEqual( source.includes('"/account/changepassword": () =>'), true, "Expected /account/changepassword to be mapped in createDetailAndAccountRouteRenderers" ); }); test("breadcrumbs/component composes mapped routes via imported factories and shared resolver", async () => { const source = loadBreadcrumbSource(); assert.strictEqual( source.includes('from "../lib/routing/breadcrumbRouteMaps"'), true, "Expected breadcrumbs to import shared breadcrumb route-map helper module" ); assert.strictEqual( source.includes('from "../lib/routing/breadcrumbRendererFactories"'), true, "Expected breadcrumbs to import breadcrumb renderer factories" ); assert.strictEqual( /createMappedRouteRendererGroups/.test(source), true, "Expected breadcrumbs to reference createMappedRouteRendererGroups" ); assert.strictEqual( /const\s+\{[\s\S]*simpleRouteRenderersByPath[\s\S]*newAppealRouteRenderersByPath[\s\S]*callbackRouteRenderersByPath[\s\S]*stepBackRouteRenderersByPath[\s\S]*representationRouteRenderersByPath[\s\S]*detailAndAccountRouteRenderersByPath[\s\S]*\}\s*=\s*createMappedRouteRendererGroups\s*\(/.test( source ), true, "Expected breadcrumbs to compose grouped renderer maps via createMappedRouteRendererGroups" ); assert.strictEqual( /const\s+mappedRouteRendererMaps\s*=\s*buildBreadcrumbRendererMaps\s*\(/.test( source ), true, "Expected grouped mapped route renderer map composition to use helper builder" ); assert.strictEqual( /return\s+resolveMappedRouteRendererByMaps\s*\(\s*path\s*,\s*mappedRouteRendererMaps\s*\)/.test( source ), true, "Expected resolver to delegate to shared route-map resolver helper" ); assert.strictEqual( /const\s+resolveMappedRouteRenderer\s*=\s*\(\s*path\s*\)\s*=>/.test( source ), true, "Expected unified mapped route resolver helper to exist" ); assert.strictEqual( /const\s+renderMappedRoute\s*=\s*\(\s*path\s*,\s*resolver\s*=\s*resolveMappedRouteRenderer\s*\)\s*=>/.test( source ), true, "Expected reusable renderMappedRoute helper to exist" ); assert.strictEqual( source.includes("return routeRenderer ? routeRenderer() : null;"), true, "Expected mapped renderer flow to return null for unmapped routes" ); assert.strictEqual( source.includes("{renderMappedRoute(pathname)}"), true, "Expected breadcrumb JSX to use single mapped route render invocation" ); assert.strictEqual( source.includes("const viewAllLabelResolver = labelsByKey[viewKey];"), true, "Expected view-all label lookup to resolve callable/non-callable map entries" ); assert.strictEqual( source.includes('return typeof viewAllLabelResolver === "function"'), true, "Expected view-all label resolver to invoke function-backed labels" ); assert.strictEqual( source.includes( "const staticTextCrumbResolver = staticTextCrumbByPath[path];" ), true, "Expected static text breadcrumb path lookup to resolve a callable label renderer" ); assert.strictEqual( source.includes( "return staticTextCrumbResolver ? staticTextCrumbResolver() : null;" ), true, "Expected static text breadcrumb resolver to invoke mapped label function" ); assert.strictEqual( source.includes('isPath("/myportal/advancedsearchresults")'), false, "Expected /myportal/advancedsearchresults explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/myportal/addresssearchresults")'), false, "Expected /myportal/addresssearchresults explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/case/[ticketnumber]")'), false, "Expected /case/[ticketnumber] explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/myportal/case")'), false, "Expected /myportal/case explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/case/id/[incident]")'), false, "Expected /case/id/[incident] explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/newappeal/selectappeal")'), false, "Expected /newappeal/selectappeal explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/newappeal")'), false, "Expected /newappeal no-op explicit branch to be removed" ); assert.strictEqual( source.includes('isPath("/newappeal/[appealtypes]")'), false, "Expected /newappeal/[appealtypes] explicit branch to be removed after step-back mapping" ); assert.strictEqual( source.includes('isPath("/myportal/[appealtypes]")'), false, "Expected /myportal/[appealtypes] explicit branch to be removed after step-back mapping" ); assert.strictEqual( source.includes('isPath("/myportal/representation")'), false, "Expected /myportal/representation explicit branch to be removed after representation mapping" ); assert.strictEqual( source.includes('isPath("/myportal/case/[ticketnumber]")'), false, "Expected /myportal/case/[ticketnumber] explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/myportal/dnsdetails")'), false, "Expected /myportal/dnsdetails explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/myportal/dns/[developmentName]")'), false, "Expected /myportal/dns/[developmentName] explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/dnsdetails")'), false, "Expected /dnsdetails explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/dns/[developmentName]")'), false, "Expected /dns/[developmentName] explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/dns/application-view")'), false, "Expected /dns/application-view explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/account/personaldetails")'), false, "Expected /account/personaldetails explicit branch to be removed after mapping" ); assert.strictEqual( source.includes('isPath("/account/changepassword")'), false, "Expected /account/changepassword explicit branch to be removed after mapping" ); }); test("breadcrumbs/map builder preserves route map ordering", async () => { const source = loadBreadcrumbSource(); const mapBuilderCallIndex = source.indexOf( "const mappedRouteRendererMaps = buildBreadcrumbRendererMaps({" ); assert.notStrictEqual( mapBuilderCallIndex, -1, "Expected grouped map builder call to exist" ); const mapBuilderSlice = source.slice( mapBuilderCallIndex, mapBuilderCallIndex + 700 ); const simpleRouteOrderIndex = mapBuilderSlice.indexOf( "simpleRouteRenderersByPath" ); const simpleLinkTextPairOrderIndex = mapBuilderSlice.indexOf( "simpleLinkTextPairRenderersByPath" ); const simpleMyPortalOrderIndex = mapBuilderSlice.indexOf( "simpleMyPortalRouteRenderersByPath" ); const newAppealOrderIndex = mapBuilderSlice.indexOf( "newAppealRouteRenderersByPath" ); const callbackOrderIndex = mapBuilderSlice.indexOf( "callbackRouteRenderersByPath" ); const stepBackOrderIndex = mapBuilderSlice.indexOf( "stepBackRouteRenderersByPath" ); const representationOrderIndex = mapBuilderSlice.indexOf( "representationRouteRenderersByPath" ); const caseDetailOrderIndex = mapBuilderSlice.indexOf( "caseDetailRouteRenderersByPath" ); const detailAndAccountOrderIndex = mapBuilderSlice.indexOf( "detailAndAccountRouteRenderersByPath" ); assert.strictEqual( simpleRouteOrderIndex >= 0 && simpleLinkTextPairOrderIndex > simpleRouteOrderIndex && simpleMyPortalOrderIndex > simpleLinkTextPairOrderIndex && newAppealOrderIndex > simpleMyPortalOrderIndex && callbackOrderIndex > newAppealOrderIndex && stepBackOrderIndex > callbackOrderIndex && representationOrderIndex > stepBackOrderIndex && caseDetailOrderIndex > representationOrderIndex && detailAndAccountOrderIndex > caseDetailOrderIndex, true, "Expected map builder call to preserve explicit route-map ordering (simple -> link-text -> myportal -> new-appeal -> callback -> step-back -> representation -> case detail -> detail/account)" ); }); test("breadcrumbs/callback-mapped branches preserve router.back behavior", async () => { const source = loadBreadcrumbSource(); assert.strictEqual( source.includes('isPath("/myportal/case/id/[incident]")'), false, "Expected /myportal/case/id/[incident] explicit branch to be removed after callback mapping" ); assert.strictEqual( source.includes('isPath("/case")'), false, "Expected /case explicit branch to be removed after callback mapping" ); assert.strictEqual( source.includes("router.back();"), true, "Expected callback-driven router.back() behavior to remain preserved" ); }); const run = async () => { let passed = 0; for (const currentTest of tests) { await currentTest.fn(); passed += 1; } console.log( `Phase 22 breadcrumbs-route-map tests passed (${passed}/${tests.length}).` ); }; module.exports = run; if (require.main === module) { run().catch((error) => { console.error(error); process.exit(1); }); }