22541 compose mapped breadcrumb groups in factory and add null fallback guard
This commit is contained in:
+19
-56
@@ -17,13 +17,7 @@ import {
|
|||||||
buildBreadcrumbRendererMaps,
|
buildBreadcrumbRendererMaps,
|
||||||
resolveMappedRouteRenderer as resolveMappedRouteRendererByMaps
|
resolveMappedRouteRenderer as resolveMappedRouteRendererByMaps
|
||||||
} from "../lib/routing/breadcrumbRouteMaps";
|
} from "../lib/routing/breadcrumbRouteMaps";
|
||||||
import {
|
import { createMappedRouteRendererGroups } from "../lib/routing/breadcrumbRendererFactories";
|
||||||
createSimpleRouteRenderers,
|
|
||||||
createSimpleLinkTextPairRenderers,
|
|
||||||
createSimpleMyPortalRouteRenderers,
|
|
||||||
createCaseDetailRouteRenderers,
|
|
||||||
createDetailAndAccountRouteRenderers
|
|
||||||
} from "../lib/routing/breadcrumbRendererFactories";
|
|
||||||
|
|
||||||
const Breadcrumbs = (props) => {
|
const Breadcrumbs = (props) => {
|
||||||
const {
|
const {
|
||||||
@@ -196,37 +190,6 @@ const Breadcrumbs = (props) => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const simpleRouteRenderersByPath = createSimpleRouteRenderers({
|
|
||||||
t,
|
|
||||||
renderTextCrumb,
|
|
||||||
renderMyPortalSectionCrumbs
|
|
||||||
});
|
|
||||||
|
|
||||||
const simpleLinkTextPairRenderersByPath = createSimpleLinkTextPairRenderers(
|
|
||||||
{
|
|
||||||
t,
|
|
||||||
router,
|
|
||||||
isWelsh,
|
|
||||||
renderLinkCrumb,
|
|
||||||
renderTextCrumb
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const simpleMyPortalRouteRenderersByPath =
|
|
||||||
createSimpleMyPortalRouteRenderers({
|
|
||||||
t,
|
|
||||||
router,
|
|
||||||
isWelsh,
|
|
||||||
myPortalHref,
|
|
||||||
currentViewState,
|
|
||||||
getViewAllLabel,
|
|
||||||
renderAnchorCrumb,
|
|
||||||
renderLinkCrumb,
|
|
||||||
renderTextCrumb,
|
|
||||||
renderMyPortalCrumb,
|
|
||||||
renderMyPortalSectionCrumbs
|
|
||||||
});
|
|
||||||
|
|
||||||
const resolveMappedRouteRenderer = (path) => {
|
const resolveMappedRouteRenderer = (path) => {
|
||||||
return resolveMappedRouteRendererByMaps(path, mappedRouteRendererMaps);
|
return resolveMappedRouteRendererByMaps(path, mappedRouteRendererMaps);
|
||||||
};
|
};
|
||||||
@@ -241,36 +204,36 @@ const Breadcrumbs = (props) => {
|
|||||||
query: router.query,
|
query: router.query,
|
||||||
hasSession: Boolean(session),
|
hasSession: Boolean(session),
|
||||||
getViewAllLabel,
|
getViewAllLabel,
|
||||||
advancedLabel: () => t("common:breadcrumb-advanced-search-results"),
|
advancedLabel: t("common:breadcrumb-advanced-search-results"),
|
||||||
addressLabel: () => t("common:breadcrumb-address-search-results"),
|
addressLabel: t("common:breadcrumb-address-search-results"),
|
||||||
defaultLabel: () => t("common:breadcrumb-search-results")
|
defaultLabel: t("common:breadcrumb-search-results")
|
||||||
});
|
});
|
||||||
|
|
||||||
const caseDetailRouteRenderersByPath = createCaseDetailRouteRenderers({
|
const {
|
||||||
|
simpleRouteRenderersByPath,
|
||||||
|
simpleLinkTextPairRenderersByPath,
|
||||||
|
simpleMyPortalRouteRenderersByPath,
|
||||||
|
caseDetailRouteRenderersByPath,
|
||||||
|
detailAndAccountRouteRenderersByPath
|
||||||
|
} = createMappedRouteRendererGroups({
|
||||||
t,
|
t,
|
||||||
router,
|
router,
|
||||||
isWelsh,
|
isWelsh,
|
||||||
|
myPortalHref,
|
||||||
|
cyMyPortalHref,
|
||||||
|
currentViewState,
|
||||||
|
getViewAllLabel,
|
||||||
caseResultsHref,
|
caseResultsHref,
|
||||||
breadcrumbLabel,
|
breadcrumbLabel,
|
||||||
fallbackSearchTitle,
|
fallbackSearchTitle,
|
||||||
caseReferenceDisplay,
|
|
||||||
getViewAllLabel,
|
|
||||||
renderLinkCrumb,
|
|
||||||
renderCaseReferenceCrumb,
|
|
||||||
renderMyPortalCrumb
|
|
||||||
});
|
|
||||||
|
|
||||||
const detailAndAccountRouteRenderersByPath =
|
|
||||||
createDetailAndAccountRouteRenderers({
|
|
||||||
t,
|
|
||||||
router,
|
|
||||||
isWelsh,
|
|
||||||
cyMyPortalHref,
|
|
||||||
currentReference,
|
currentReference,
|
||||||
caseReferenceDisplay,
|
caseReferenceDisplay,
|
||||||
renderMyPortalCrumb,
|
renderAnchorCrumb,
|
||||||
renderLinkCrumb,
|
renderLinkCrumb,
|
||||||
|
renderTextCrumb,
|
||||||
renderCaseReferenceCrumb,
|
renderCaseReferenceCrumb,
|
||||||
|
renderMyPortalCrumb,
|
||||||
|
renderMyPortalSectionCrumbs,
|
||||||
renderDnsCaseReferenceCrumbs
|
renderDnsCaseReferenceCrumbs
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -312,3 +312,92 @@ export const createDetailAndAccountRouteRenderers = ({
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const createMappedRouteRendererGroups = ({
|
||||||
|
t,
|
||||||
|
router,
|
||||||
|
isWelsh,
|
||||||
|
myPortalHref,
|
||||||
|
cyMyPortalHref,
|
||||||
|
currentViewState,
|
||||||
|
getViewAllLabel,
|
||||||
|
caseResultsHref,
|
||||||
|
breadcrumbLabel,
|
||||||
|
fallbackSearchTitle,
|
||||||
|
currentReference,
|
||||||
|
caseReferenceDisplay,
|
||||||
|
renderAnchorCrumb,
|
||||||
|
renderLinkCrumb,
|
||||||
|
renderTextCrumb,
|
||||||
|
renderCaseReferenceCrumb,
|
||||||
|
renderMyPortalCrumb,
|
||||||
|
renderMyPortalSectionCrumbs,
|
||||||
|
renderDnsCaseReferenceCrumbs
|
||||||
|
}) => {
|
||||||
|
const simpleRouteRenderersByPath = createSimpleRouteRenderers({
|
||||||
|
t,
|
||||||
|
renderTextCrumb,
|
||||||
|
renderMyPortalSectionCrumbs
|
||||||
|
});
|
||||||
|
|
||||||
|
const simpleLinkTextPairRenderersByPath = createSimpleLinkTextPairRenderers(
|
||||||
|
{
|
||||||
|
t,
|
||||||
|
router,
|
||||||
|
isWelsh,
|
||||||
|
renderLinkCrumb,
|
||||||
|
renderTextCrumb
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const simpleMyPortalRouteRenderersByPath =
|
||||||
|
createSimpleMyPortalRouteRenderers({
|
||||||
|
t,
|
||||||
|
router,
|
||||||
|
isWelsh,
|
||||||
|
myPortalHref,
|
||||||
|
currentViewState,
|
||||||
|
getViewAllLabel,
|
||||||
|
renderAnchorCrumb,
|
||||||
|
renderLinkCrumb,
|
||||||
|
renderTextCrumb,
|
||||||
|
renderMyPortalCrumb,
|
||||||
|
renderMyPortalSectionCrumbs
|
||||||
|
});
|
||||||
|
|
||||||
|
const caseDetailRouteRenderersByPath = createCaseDetailRouteRenderers({
|
||||||
|
t,
|
||||||
|
router,
|
||||||
|
isWelsh,
|
||||||
|
caseResultsHref,
|
||||||
|
breadcrumbLabel,
|
||||||
|
fallbackSearchTitle,
|
||||||
|
caseReferenceDisplay,
|
||||||
|
getViewAllLabel,
|
||||||
|
renderLinkCrumb,
|
||||||
|
renderCaseReferenceCrumb,
|
||||||
|
renderMyPortalCrumb
|
||||||
|
});
|
||||||
|
|
||||||
|
const detailAndAccountRouteRenderersByPath =
|
||||||
|
createDetailAndAccountRouteRenderers({
|
||||||
|
t,
|
||||||
|
router,
|
||||||
|
isWelsh,
|
||||||
|
cyMyPortalHref,
|
||||||
|
currentReference,
|
||||||
|
caseReferenceDisplay,
|
||||||
|
renderMyPortalCrumb,
|
||||||
|
renderLinkCrumb,
|
||||||
|
renderCaseReferenceCrumb,
|
||||||
|
renderDnsCaseReferenceCrumbs
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
simpleRouteRenderersByPath,
|
||||||
|
simpleLinkTextPairRenderersByPath,
|
||||||
|
simpleMyPortalRouteRenderersByPath,
|
||||||
|
caseDetailRouteRenderersByPath,
|
||||||
|
detailAndAccountRouteRenderersByPath
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -532,6 +532,39 @@ Follow-ups:
|
|||||||
- Next slice option A (larger): move per-path map object declarations out of `components/breadcrumbs.js` into module-level pure factories (still injected with `t/router/currentView`) to further shrink component body.
|
- Next slice option A (larger): move per-path map object declarations out of `components/breadcrumbs.js` into module-level pure factories (still injected with `t/router/currentView`) to further shrink component body.
|
||||||
- Next slice option B (smaller): add one focused parity test asserting mapped resolver fallback returns `null` in component rendering path for non-mapped routes (ensures no accidental render noise).
|
- Next slice option B (smaller): add one focused parity test asserting mapped resolver fallback returns `null` in component rendering path for non-mapped routes (ensures no accidental render noise).
|
||||||
|
|
||||||
|
### CL-22541-R: breadcrumbs mapped-group factory composition + unmapped-route null parity guard
|
||||||
|
|
||||||
|
date: 2026-04-09
|
||||||
|
author: Cline
|
||||||
|
scope: `lib/routing/breadcrumbRendererFactories.js`, `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs`
|
||||||
|
type: change
|
||||||
|
rationale: Execute both approved next slices in one commit by centralizing deterministic mapped route-group composition into a factory-level helper and adding explicit structure guard coverage for null fallback behavior on unmapped routes.
|
||||||
|
impact: Refactor-only structural consolidation and test hardening; no intended route/auth/session/API/EN-CY/a11y behavior change.
|
||||||
|
status: completed
|
||||||
|
|
||||||
|
Summary:
|
||||||
|
|
||||||
|
- Added `createMappedRouteRendererGroups(...)` in `lib/routing/breadcrumbRendererFactories.js` to compose and return all deterministic mapped renderer groups in one place:
|
||||||
|
- `simpleRouteRenderersByPath`
|
||||||
|
- `simpleLinkTextPairRenderersByPath`
|
||||||
|
- `simpleMyPortalRouteRenderersByPath`
|
||||||
|
- `caseDetailRouteRenderersByPath`
|
||||||
|
- `detailAndAccountRouteRenderersByPath`
|
||||||
|
- Updated `components/breadcrumbs.js` to consume `createMappedRouteRendererGroups(...)` and remove local per-group factory composition boilerplate while preserving existing map precedence and resolver flow.
|
||||||
|
- Expanded `tests/phase22/breadcrumbs-route-map-structure.test.cjs` to assert:
|
||||||
|
- grouped renderer maps are composed via `createMappedRouteRendererGroups(...)`
|
||||||
|
- mapped rendering path explicitly preserves null fallback (`routeRenderer ? routeRenderer() : null`)
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
|
||||||
|
- `npx eslint lib/routing/breadcrumbRendererFactories.js components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/index.test.cjs` -> pass.
|
||||||
|
- `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumbs-route-map 4/4).
|
||||||
|
|
||||||
|
Follow-ups:
|
||||||
|
|
||||||
|
- Next slice option A (larger): extract remaining deterministic inline branches (`/myportal/case`, `/case/id/[incident]` if kept deterministic after constraints review) only if they remain callback/state free.
|
||||||
|
- Next slice option B (smaller): add one focused assertion in helper-level tests that empty grouped map entries are tolerated without affecting precedence resolution.
|
||||||
|
|
||||||
### CL-00X: 22500 `components/elements/index.js` Phase 1 helper extraction
|
### CL-00X: 22500 `components/elements/index.js` Phase 1 helper extraction
|
||||||
|
|
||||||
date: 2026-04-07
|
date: 2026-04-07
|
||||||
|
|||||||
@@ -155,73 +155,17 @@ test("breadcrumbs/component composes mapped routes via imported factories and sh
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
/createSimpleRouteRenderers/.test(source),
|
/createMappedRouteRendererGroups/.test(source),
|
||||||
true,
|
true,
|
||||||
"Expected breadcrumbs to reference createSimpleRouteRenderers"
|
"Expected breadcrumbs to reference createMappedRouteRendererGroups"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
/createSimpleLinkTextPairRenderers/.test(source),
|
/const\s+\{[\s\S]*simpleRouteRenderersByPath[\s\S]*detailAndAccountRouteRenderersByPath[\s\S]*\}\s*=\s*createMappedRouteRendererGroups\s*\(/.test(
|
||||||
true,
|
|
||||||
"Expected breadcrumbs to reference createSimpleLinkTextPairRenderers"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
/createSimpleMyPortalRouteRenderers/.test(source),
|
|
||||||
true,
|
|
||||||
"Expected breadcrumbs to reference createSimpleMyPortalRouteRenderers"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
/createCaseDetailRouteRenderers/.test(source),
|
|
||||||
true,
|
|
||||||
"Expected breadcrumbs to reference createCaseDetailRouteRenderers"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
/createDetailAndAccountRouteRenderers/.test(source),
|
|
||||||
true,
|
|
||||||
"Expected breadcrumbs to reference createDetailAndAccountRouteRenderers"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
/const\s+simpleRouteRenderersByPath\s*=\s*createSimpleRouteRenderers\s*\(/.test(
|
|
||||||
source
|
source
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
"Expected breadcrumbs to build simple route renderers from factory"
|
"Expected breadcrumbs to compose grouped renderer maps via createMappedRouteRendererGroups"
|
||||||
);
|
|
||||||
|
|
||||||
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+caseDetailRouteRenderersByPath\s*=\s*createCaseDetailRouteRenderers\s*\(/.test(
|
|
||||||
source
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
"Expected breadcrumbs to build case detail route renderers from factory"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
/const\s+detailAndAccountRouteRenderersByPath\s*=\s*createDetailAndAccountRouteRenderers\s*\(/.test(
|
|
||||||
source
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
"Expected breadcrumbs to build detail and account route renderers from factory"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@@ -256,6 +200,12 @@ test("breadcrumbs/component composes mapped routes via imported factories and sh
|
|||||||
"Expected reusable renderMappedRoute helper to exist"
|
"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(
|
assert.strictEqual(
|
||||||
source.includes("{renderMappedRoute(pathname)}"),
|
source.includes("{renderMappedRoute(pathname)}"),
|
||||||
true,
|
true,
|
||||||
|
|||||||
Reference in New Issue
Block a user