Refactor breadcrumbs to use factory-based route renderers
This commit is contained in:
@@ -1,49 +1,156 @@
|
||||
const assert = require("assert");
|
||||
|
||||
const {
|
||||
buildBreadcrumbRendererMaps,
|
||||
getMappedRendererByPath,
|
||||
resolveMappedRouteRenderer
|
||||
} = require("../../lib/routing/breadcrumbRouteMaps");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("breadcrumbRouteMaps/buildBreadcrumbRendererMaps preserves explicit map order", async () => {
|
||||
const mapA = { "/a": () => "A" };
|
||||
const mapB = { "/b": () => "B" };
|
||||
const mapC = { "/c": () => "C" };
|
||||
const helperModulePath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"lib",
|
||||
"routing",
|
||||
"breadcrumbRouteMaps.js"
|
||||
);
|
||||
|
||||
const result = buildBreadcrumbRendererMaps({
|
||||
simpleRouteRenderersByPath: mapA,
|
||||
simpleLinkTextPairRenderersByPath: mapB,
|
||||
simpleMyPortalRouteRenderersByPath: mapC
|
||||
const loadHelpers = () => {
|
||||
const source = fs.readFileSync(helperModulePath, "utf8");
|
||||
|
||||
const transformedSource = `
|
||||
${source
|
||||
.replace(/export const /g, "const ")
|
||||
.replace(/export function /g, "function ")}
|
||||
|
||||
module.exports = {
|
||||
buildBreadcrumbRendererMaps,
|
||||
resolveMappedRouteRenderer
|
||||
};
|
||||
`;
|
||||
|
||||
const sandbox = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
__dirname: path.dirname(helperModulePath),
|
||||
__filename: helperModulePath,
|
||||
console
|
||||
};
|
||||
|
||||
vm.runInNewContext(transformedSource, sandbox, {
|
||||
filename: helperModulePath
|
||||
});
|
||||
|
||||
assert.strictEqual(result[0], mapA);
|
||||
assert.strictEqual(result[1], mapB);
|
||||
assert.strictEqual(result[2], mapC);
|
||||
return sandbox.module.exports;
|
||||
};
|
||||
|
||||
test("buildBreadcrumbRendererMaps returns grouped maps in explicit precedence order", () => {
|
||||
const { buildBreadcrumbRendererMaps } = loadHelpers();
|
||||
|
||||
const simpleRouteRenderersByPath = {
|
||||
"/alpha": () => "alpha"
|
||||
};
|
||||
const simpleLinkTextPairRenderersByPath = {
|
||||
"/beta": () => "beta"
|
||||
};
|
||||
const simpleMyPortalRouteRenderersByPath = {
|
||||
"/gamma": () => "gamma"
|
||||
};
|
||||
|
||||
const result = buildBreadcrumbRendererMaps({
|
||||
simpleRouteRenderersByPath,
|
||||
simpleLinkTextPairRenderersByPath,
|
||||
simpleMyPortalRouteRenderersByPath
|
||||
});
|
||||
|
||||
assert.ok(Array.isArray(result), "Expected grouped maps array");
|
||||
assert.strictEqual(result.length, 3, "Expected three grouped route maps");
|
||||
assert.strictEqual(
|
||||
result[0],
|
||||
simpleRouteRenderersByPath,
|
||||
"Expected simple route renderers first"
|
||||
);
|
||||
assert.strictEqual(
|
||||
result[1],
|
||||
simpleLinkTextPairRenderersByPath,
|
||||
"Expected simple link-text pair renderers second"
|
||||
);
|
||||
assert.strictEqual(
|
||||
result[2],
|
||||
simpleMyPortalRouteRenderersByPath,
|
||||
"Expected my-portal route renderers third"
|
||||
);
|
||||
});
|
||||
|
||||
test("breadcrumbRouteMaps/getMappedRendererByPath returns mapped renderer or null", async () => {
|
||||
const renderer = () => "ok";
|
||||
const map = { "/x": renderer };
|
||||
test("resolveMappedRouteRenderer returns renderer from first matching grouped map", () => {
|
||||
const { buildBreadcrumbRendererMaps, resolveMappedRouteRenderer } =
|
||||
loadHelpers();
|
||||
|
||||
assert.strictEqual(getMappedRendererByPath("/x", map), renderer);
|
||||
assert.strictEqual(getMappedRendererByPath("/missing", map), null);
|
||||
});
|
||||
|
||||
test("breadcrumbRouteMaps/resolveMappedRouteRenderer honors map precedence", async () => {
|
||||
const firstRenderer = () => "first";
|
||||
const secondRenderer = () => "second";
|
||||
|
||||
const result = resolveMappedRouteRenderer("/same", [
|
||||
{ "/same": firstRenderer },
|
||||
{ "/same": secondRenderer }
|
||||
]);
|
||||
const maps = buildBreadcrumbRendererMaps({
|
||||
simpleRouteRenderersByPath: {
|
||||
"/known": firstRenderer
|
||||
},
|
||||
simpleLinkTextPairRenderersByPath: {
|
||||
"/known": secondRenderer
|
||||
},
|
||||
simpleMyPortalRouteRenderersByPath: {}
|
||||
});
|
||||
|
||||
assert.strictEqual(result, firstRenderer);
|
||||
assert.strictEqual(resolveMappedRouteRenderer("/none", []), null);
|
||||
const result = resolveMappedRouteRenderer("/known", maps);
|
||||
|
||||
assert.strictEqual(
|
||||
result,
|
||||
firstRenderer,
|
||||
"Expected resolver to use first matching map by precedence order"
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveMappedRouteRenderer returns renderer from later grouped map when earlier maps do not match", () => {
|
||||
const { buildBreadcrumbRendererMaps, resolveMappedRouteRenderer } =
|
||||
loadHelpers();
|
||||
|
||||
const myPortalRenderer = () => "myportal";
|
||||
|
||||
const maps = buildBreadcrumbRendererMaps({
|
||||
simpleRouteRenderersByPath: {},
|
||||
simpleLinkTextPairRenderersByPath: {},
|
||||
simpleMyPortalRouteRenderersByPath: {
|
||||
"/myportal/searchresults": myPortalRenderer
|
||||
}
|
||||
});
|
||||
|
||||
const result = resolveMappedRouteRenderer("/myportal/searchresults", maps);
|
||||
|
||||
assert.strictEqual(
|
||||
result,
|
||||
myPortalRenderer,
|
||||
"Expected resolver to return matching renderer from later grouped map"
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveMappedRouteRenderer returns null for unmapped path", () => {
|
||||
const { buildBreadcrumbRendererMaps, resolveMappedRouteRenderer } =
|
||||
loadHelpers();
|
||||
|
||||
const maps = buildBreadcrumbRendererMaps({
|
||||
simpleRouteRenderersByPath: {
|
||||
"/known": () => "known"
|
||||
},
|
||||
simpleLinkTextPairRenderersByPath: {},
|
||||
simpleMyPortalRouteRenderersByPath: {}
|
||||
});
|
||||
|
||||
const result = resolveMappedRouteRenderer("/unknown", maps);
|
||||
|
||||
assert.strictEqual(
|
||||
result,
|
||||
null,
|
||||
"Expected null when no grouped map contains the path"
|
||||
);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
|
||||
@@ -5,58 +5,75 @@ const path = require("path");
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
const loadBreadcrumbSource = () => {
|
||||
const filePath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"components",
|
||||
"breadcrumbs.js"
|
||||
);
|
||||
const loadSource = (...parts) => {
|
||||
const filePath = path.join(__dirname, "..", "..", ...parts);
|
||||
return fs.readFileSync(filePath, "utf8");
|
||||
};
|
||||
|
||||
test("breadcrumbs/simple-link-text map includes address and advanced search result routes", async () => {
|
||||
const source = loadBreadcrumbSource();
|
||||
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('"/addresssearchresults": () => ('),
|
||||
true,
|
||||
"Expected /addresssearchresults to be mapped in getSimpleLinkTextPairRenderer"
|
||||
"Expected /addresssearchresults to be mapped in createSimpleLinkTextPairRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
source.includes('"/advancedsearchresults": () => ('),
|
||||
true,
|
||||
"Expected /advancedsearchresults to be mapped in getSimpleLinkTextPairRenderer"
|
||||
"Expected /advancedsearchresults to be mapped in createSimpleLinkTextPairRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
source.includes('"/myportal/searchresults": () => ('),
|
||||
true,
|
||||
"Expected /myportal/searchresults to be mapped in getSimpleMyPortalRouteRenderer"
|
||||
"Expected /myportal/searchresults to be mapped in createSimpleMyPortalRouteRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
source.includes('"/myportal/viewall": () =>'),
|
||||
true,
|
||||
"Expected /myportal/viewall to be mapped in getSimpleMyPortalRouteRenderer"
|
||||
"Expected /myportal/viewall to be mapped in createSimpleMyPortalRouteRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
source.includes('"/myportal/advancedsearchresults": () => ('),
|
||||
true,
|
||||
"Expected /myportal/advancedsearchresults to be mapped in getSimpleMyPortalRouteRenderer"
|
||||
"Expected /myportal/advancedsearchresults to be mapped in createSimpleMyPortalRouteRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
source.includes('"/myportal/addresssearchresults": () => ('),
|
||||
true,
|
||||
"Expected /myportal/addresssearchresults to be mapped in getSimpleMyPortalRouteRenderer"
|
||||
"Expected /myportal/addresssearchresults to be mapped in createSimpleMyPortalRouteRenderers"
|
||||
);
|
||||
});
|
||||
|
||||
test("breadcrumbs/merged resolver renders mapped routes through single helper invocation", async () => {
|
||||
test("breadcrumbs/component composes mapped routes via imported factories and shared resolver", async () => {
|
||||
const source = loadBreadcrumbSource();
|
||||
|
||||
assert.strictEqual(
|
||||
@@ -66,30 +83,80 @@ test("breadcrumbs/merged resolver renders mapped routes through single helper in
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
source.includes(
|
||||
"const mappedRouteRendererMaps = buildBreadcrumbRendererMaps({"
|
||||
source.includes('from "../lib/routing/breadcrumbRendererFactories"'),
|
||||
true,
|
||||
"Expected breadcrumbs to import breadcrumb renderer factories"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
/createSimpleRouteRenderers/.test(source),
|
||||
true,
|
||||
"Expected breadcrumbs to reference createSimpleRouteRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
/createSimpleLinkTextPairRenderers/.test(source),
|
||||
true,
|
||||
"Expected breadcrumbs to reference createSimpleLinkTextPairRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
/createSimpleMyPortalRouteRenderers/.test(source),
|
||||
true,
|
||||
"Expected breadcrumbs to reference createSimpleMyPortalRouteRenderers"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
/const\s+simpleRouteRenderersByPath\s*=\s*createSimpleRouteRenderers\s*\(/.test(
|
||||
source
|
||||
),
|
||||
true,
|
||||
"Expected breadcrumbs to build simple route renderers from factory"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
/const\s+simpleLinkTextPairRenderersByPath\s*=\s*createSimpleLinkTextPairRenderers\s*\(/.test(
|
||||
source
|
||||
),
|
||||
true,
|
||||
"Expected breadcrumbs to build link-text pair renderers from factory"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
/const\s+simpleMyPortalRouteRenderersByPath\s*=\s*createSimpleMyPortalRouteRenderers\s*\(/.test(
|
||||
source
|
||||
),
|
||||
true,
|
||||
"Expected breadcrumbs to build my-portal route renderers from factory"
|
||||
);
|
||||
|
||||
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(
|
||||
source.includes(
|
||||
"return resolveMappedRouteRendererByMaps(path, mappedRouteRendererMaps);"
|
||||
/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(
|
||||
source.includes("const resolveMappedRouteRenderer = (path) =>"),
|
||||
/const\s+resolveMappedRouteRenderer\s*=\s*\(\s*path\s*\)\s*=>/.test(
|
||||
source
|
||||
),
|
||||
true,
|
||||
"Expected unified mapped route resolver helper to exist"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
source.includes(
|
||||
"const renderMappedRoute = (path, resolver = resolveMappedRouteRenderer) =>"
|
||||
/const\s+renderMappedRoute\s*=\s*\(\s*path\s*,\s*resolver\s*=\s*resolveMappedRouteRenderer\s*\)\s*=>/.test(
|
||||
source
|
||||
),
|
||||
true,
|
||||
"Expected reusable renderMappedRoute helper to exist"
|
||||
@@ -112,13 +179,24 @@ test("breadcrumbs/merged resolver renders mapped routes through single helper in
|
||||
false,
|
||||
"Expected /myportal/addresssearchresults 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 + 300
|
||||
mapBuilderCallIndex + 500
|
||||
);
|
||||
|
||||
const simpleRouteOrderIndex = mapBuilderSlice.indexOf(
|
||||
|
||||
@@ -1,187 +1,372 @@
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
const assert = require("assert");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const loadRouteStateModule = () => {
|
||||
const filePath = path.join(rootDir, "lib", "routing", "routeState.js");
|
||||
let source = fs.readFileSync(filePath, "utf8");
|
||||
|
||||
source = source.replace(/export const\s+/g, "const ");
|
||||
source +=
|
||||
"\nmodule.exports = { normalizeRouteStateQuery, resolveSearchResultsHref, resolveSearchBreadcrumbLabel, isDnsRoutePath, resolveCaseBreadcrumbState };\n";
|
||||
|
||||
const context = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, context, { filename: filePath });
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
test("routing/routeState normalizes va/adv/ads flags and key", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
const helperModulePath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"lib",
|
||||
"routing",
|
||||
"routeState.js"
|
||||
);
|
||||
|
||||
const normalized = mod.normalizeRouteStateQuery({
|
||||
va: "true",
|
||||
adv: "false",
|
||||
ads: "true",
|
||||
key: "myCases"
|
||||
const toPlain = (value) => JSON.parse(JSON.stringify(value));
|
||||
|
||||
const loadHelpers = () => {
|
||||
const source = fs.readFileSync(helperModulePath, "utf8");
|
||||
|
||||
const transformedSource = `
|
||||
${source
|
||||
.replace(/export const /g, "const ")
|
||||
.replace(/export function /g, "function ")}
|
||||
|
||||
module.exports = {
|
||||
normalizeRouteStateQuery,
|
||||
resolveSearchResultsHref,
|
||||
resolveSearchBreadcrumbLabel,
|
||||
isDnsRoutePath,
|
||||
resolveCaseBreadcrumbState
|
||||
};
|
||||
`;
|
||||
|
||||
const sandbox = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
__dirname: path.dirname(helperModulePath),
|
||||
__filename: helperModulePath,
|
||||
console
|
||||
};
|
||||
|
||||
vm.runInNewContext(transformedSource, sandbox, {
|
||||
filename: helperModulePath
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(normalized)), {
|
||||
viewAll: true,
|
||||
advanced: false,
|
||||
address: true,
|
||||
key: "myCases"
|
||||
});
|
||||
return sandbox.module.exports;
|
||||
};
|
||||
|
||||
test("normalizeRouteStateQuery maps known boolean query flags", () => {
|
||||
const { normalizeRouteStateQuery } = loadHelpers();
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
normalizeRouteStateQuery({
|
||||
va: "true",
|
||||
adv: "false",
|
||||
ads: "true",
|
||||
key: "myCases"
|
||||
})
|
||||
),
|
||||
{
|
||||
viewAll: true,
|
||||
advanced: false,
|
||||
address: true,
|
||||
key: "myCases"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("routing/routeState resolves view-all href when va=true", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
test("resolveSearchResultsHref falls back to myportal when no flags and no search query exist for signed-in user", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
const href = mod.resolveSearchResultsHref({
|
||||
query: { va: "true", key: "myCases", adv: "true" },
|
||||
hasSession: true
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(href)), {
|
||||
pathname: "/myportal/viewall",
|
||||
query: { key: "myCases" }
|
||||
});
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: {},
|
||||
hasSession: true,
|
||||
fallbackToMyPortalWhenNoFlags: true
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/myportal"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("routing/routeState resolves advanced/address/default result hrefs", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
test("resolveSearchResultsHref preserves public searchresults route when search query exists and no flags are set", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
const advancedHref = mod.resolveSearchResultsHref({
|
||||
query: { adv: "true", q: "abc" },
|
||||
hasSession: false
|
||||
});
|
||||
const addressHref = mod.resolveSearchResultsHref({
|
||||
query: { ads: "true", q: "abc" },
|
||||
hasSession: true
|
||||
});
|
||||
const defaultHref = mod.resolveSearchResultsHref({
|
||||
query: { q: "abc" },
|
||||
hasSession: true
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(advancedHref)), {
|
||||
pathname: "/advancedsearchresults",
|
||||
query: { adv: "true", q: "abc" }
|
||||
});
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(addressHref)), {
|
||||
pathname: "/myportal/addresssearchresults",
|
||||
query: { ads: "true", q: "abc" }
|
||||
});
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(defaultHref)), {
|
||||
pathname: "/myportal/searchresults",
|
||||
query: { q: "abc" }
|
||||
});
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: { q: "abc" },
|
||||
hasSession: false,
|
||||
fallbackToMyPortalWhenNoFlags: true
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/searchresults",
|
||||
query: { q: "abc" }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("routing/routeState supports fallback to /myportal when no route flags", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
test("resolveSearchResultsHref preserves myportal searchresults route when search query exists and no flags are set for signed-in user", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
const href = mod.resolveSearchResultsHref({
|
||||
query: { q: "abc" },
|
||||
hasSession: false,
|
||||
fallbackToMyPortalWhenNoFlags: true
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(href)), {
|
||||
pathname: "/myportal"
|
||||
});
|
||||
});
|
||||
|
||||
test("routing/routeState supports DNS route override", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
|
||||
const href = mod.resolveSearchResultsHref({
|
||||
query: { adv: "true", q: "abc" },
|
||||
hasSession: true,
|
||||
isDnsRoute: true
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(href)), {
|
||||
pathname: "/myportal/dnsapplications"
|
||||
});
|
||||
});
|
||||
|
||||
test("routing/routeState resolves breadcrumb label using key and route flags", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
const getViewAllLabel = (key) =>
|
||||
({ myCases: "My Cases", watchedCases: "Watched Cases" })[key] || null;
|
||||
|
||||
const fromViewAll = mod.resolveSearchBreadcrumbLabel({
|
||||
query: { va: "true", key: "myCases" },
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced",
|
||||
addressLabel: "Address",
|
||||
defaultLabel: "Search"
|
||||
});
|
||||
const fromAdvanced = mod.resolveSearchBreadcrumbLabel({
|
||||
query: { adv: "true" },
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced",
|
||||
addressLabel: "Address",
|
||||
defaultLabel: "Search"
|
||||
});
|
||||
const fromDefault = mod.resolveSearchBreadcrumbLabel({
|
||||
query: {},
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced",
|
||||
addressLabel: "Address",
|
||||
defaultLabel: "Search"
|
||||
});
|
||||
|
||||
assert.strictEqual(fromViewAll, "My Cases");
|
||||
assert.strictEqual(fromAdvanced, "Advanced");
|
||||
assert.strictEqual(fromDefault, "Search");
|
||||
});
|
||||
|
||||
test("routing/routeState identifies dns and myportal dns route prefixes", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
|
||||
assert.strictEqual(mod.isDnsRoutePath("/dns"), true);
|
||||
assert.strictEqual(mod.isDnsRoutePath("/dns/development"), true);
|
||||
assert.strictEqual(mod.isDnsRoutePath("/myportal/dns"), true);
|
||||
assert.strictEqual(mod.isDnsRoutePath("/myportal/dns/applications"), true);
|
||||
assert.strictEqual(mod.isDnsRoutePath("/case/123"), false);
|
||||
});
|
||||
|
||||
test("routing/routeState resolves bundled case breadcrumb state", async () => {
|
||||
const mod = loadRouteStateModule();
|
||||
const getViewAllLabel = (key) => ({ myCases: "My Cases" })[key] || null;
|
||||
|
||||
const state = mod.resolveCaseBreadcrumbState({
|
||||
query: { va: "true", key: "myCases" },
|
||||
hasSession: true,
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced",
|
||||
addressLabel: "Address",
|
||||
defaultLabel: "Search"
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(state)), {
|
||||
breadcrumbHref: {
|
||||
pathname: "/myportal/viewall",
|
||||
query: { key: "myCases" }
|
||||
},
|
||||
caseResultsHref: {
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: { q: "abc" },
|
||||
hasSession: true,
|
||||
fallbackToMyPortalWhenNoFlags: true
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/myportal/searchresults",
|
||||
query: { va: "true", key: "myCases" }
|
||||
},
|
||||
breadcrumbLabel: "My Cases"
|
||||
});
|
||||
query: { q: "abc" }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveSearchResultsHref routes view-all requests to myportal viewall with key only", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: {
|
||||
va: "true",
|
||||
key: "mySubmittedReps",
|
||||
q: "ignored"
|
||||
},
|
||||
hasSession: true,
|
||||
includeViewAll: true
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/myportal/viewall",
|
||||
query: { key: "mySubmittedReps" }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveSearchResultsHref routes advanced requests to advancedsearchresults and preserves query", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: { q: "abc", adv: "true", page: "2" },
|
||||
hasSession: false
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/advancedsearchresults",
|
||||
query: { q: "abc", adv: "true", page: "2" }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveSearchResultsHref routes address requests to addresssearchresults and preserves query", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: { postcode: "CF10", ads: "true" },
|
||||
hasSession: true
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/myportal/addresssearchresults",
|
||||
query: { postcode: "CF10", ads: "true" }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveSearchResultsHref routes dns requests to dnsapplications", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: { anything: "x" },
|
||||
hasSession: true,
|
||||
isDnsRoute: true
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/myportal/dnsapplications"
|
||||
}
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: { anything: "x" },
|
||||
hasSession: false,
|
||||
isDnsRoute: true
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/dnsapplications"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveSearchResultsHref defaults to searchresults and preserves query when no special route applies", () => {
|
||||
const { resolveSearchResultsHref } = loadHelpers();
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveSearchResultsHref({
|
||||
query: { q: "abc", page: "3" },
|
||||
hasSession: false
|
||||
})
|
||||
),
|
||||
{
|
||||
pathname: "/searchresults",
|
||||
query: { q: "abc", page: "3" }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveSearchBreadcrumbLabel prioritizes view-all label, then keyed label, then advanced/address/default", () => {
|
||||
const { resolveSearchBreadcrumbLabel } = loadHelpers();
|
||||
|
||||
const getViewAllLabel = (key) => {
|
||||
const labels = {
|
||||
myCases: "My cases",
|
||||
watchedCases: "Watched cases"
|
||||
};
|
||||
return labels[key] || null;
|
||||
};
|
||||
|
||||
assert.strictEqual(
|
||||
resolveSearchBreadcrumbLabel({
|
||||
query: { va: "true", key: "myCases" },
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced search results",
|
||||
addressLabel: "Address search results",
|
||||
defaultLabel: "Search results"
|
||||
}),
|
||||
"My cases"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
resolveSearchBreadcrumbLabel({
|
||||
query: { key: "watchedCases" },
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced search results",
|
||||
addressLabel: "Address search results",
|
||||
defaultLabel: "Search results"
|
||||
}),
|
||||
"Watched cases"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
resolveSearchBreadcrumbLabel({
|
||||
query: { adv: "true" },
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced search results",
|
||||
addressLabel: "Address search results",
|
||||
defaultLabel: "Search results"
|
||||
}),
|
||||
"Advanced search results"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
resolveSearchBreadcrumbLabel({
|
||||
query: { ads: "true" },
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced search results",
|
||||
addressLabel: "Address search results",
|
||||
defaultLabel: "Search results"
|
||||
}),
|
||||
"Address search results"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
resolveSearchBreadcrumbLabel({
|
||||
query: {},
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced search results",
|
||||
addressLabel: "Address search results",
|
||||
defaultLabel: "Search results"
|
||||
}),
|
||||
"Search results"
|
||||
);
|
||||
});
|
||||
|
||||
test("isDnsRoutePath correctly identifies dns route families", () => {
|
||||
const { isDnsRoutePath } = loadHelpers();
|
||||
|
||||
assert.strictEqual(isDnsRoutePath("/dns"), true);
|
||||
assert.strictEqual(isDnsRoutePath("/dns/applications"), true);
|
||||
assert.strictEqual(isDnsRoutePath("/myportal/dns"), true);
|
||||
assert.strictEqual(isDnsRoutePath("/myportal/dns/example"), true);
|
||||
|
||||
assert.strictEqual(isDnsRoutePath("/searchresults"), false);
|
||||
assert.strictEqual(isDnsRoutePath("/myportal"), false);
|
||||
assert.strictEqual(isDnsRoutePath("/myportal/case/[ticketnumber]"), false);
|
||||
});
|
||||
|
||||
test("resolveCaseBreadcrumbState returns breadcrumb and case-results hrefs plus breadcrumb label", () => {
|
||||
const { resolveCaseBreadcrumbState } = loadHelpers();
|
||||
|
||||
const getViewAllLabel = (key) =>
|
||||
key === "mySubmittedReps" ? "Submitted representations" : null;
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveCaseBreadcrumbState({
|
||||
query: { q: "cas-", adv: "false" },
|
||||
hasSession: true,
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced search results",
|
||||
addressLabel: "Address search results",
|
||||
defaultLabel: "Search results"
|
||||
})
|
||||
),
|
||||
{
|
||||
breadcrumbHref: {
|
||||
pathname: "/myportal/searchresults",
|
||||
query: { q: "cas-", adv: "false" }
|
||||
},
|
||||
caseResultsHref: {
|
||||
pathname: "/myportal/searchresults",
|
||||
query: { q: "cas-", adv: "false" }
|
||||
},
|
||||
breadcrumbLabel: "Search results"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("resolveCaseBreadcrumbState distinguishes view-all breadcrumb from case-results href", () => {
|
||||
const { resolveCaseBreadcrumbState } = loadHelpers();
|
||||
|
||||
const getViewAllLabel = (key) =>
|
||||
key === "mySubmittedReps" ? "Submitted representations" : null;
|
||||
|
||||
assert.deepStrictEqual(
|
||||
toPlain(
|
||||
resolveCaseBreadcrumbState({
|
||||
query: { va: "true", key: "mySubmittedReps" },
|
||||
hasSession: true,
|
||||
getViewAllLabel,
|
||||
advancedLabel: "Advanced search results",
|
||||
addressLabel: "Address search results",
|
||||
defaultLabel: "Search results"
|
||||
})
|
||||
),
|
||||
{
|
||||
breadcrumbHref: {
|
||||
pathname: "/myportal/viewall",
|
||||
query: { key: "mySubmittedReps" }
|
||||
},
|
||||
caseResultsHref: {
|
||||
pathname: "/myportal/searchresults",
|
||||
query: { va: "true", key: "mySubmittedReps" }
|
||||
},
|
||||
breadcrumbLabel: "Submitted representations"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
@@ -193,7 +378,7 @@ const run = async () => {
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Phase 22 route-state helper tests passed (${passed}/${tests.length}).`
|
||||
`Phase 22 route-state-helper tests passed (${passed}/${tests.length}).`
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user