From 46a0e0b185efc78a6915c3bcb33ec8560070c439 Mon Sep 17 00:00:00 2001 From: Robert Bond Date: Tue, 5 May 2026 10:16:27 +0000 Subject: [PATCH] Merged PR 2291: reps array refactor and update and tests reps array refactor and update and tests Related work items: #22873 --- components/case/representation/index.js | 158 +----- .../representation/utils/buildRepsArrRules.js | 216 +++++++++ tests/phase22/index.test.cjs | 2 + ...presentation-build-reps-arr-rules.test.cjs | 454 ++++++++++++++++++ 4 files changed, 689 insertions(+), 141 deletions(-) create mode 100644 components/case/representation/utils/buildRepsArrRules.js create mode 100644 tests/phase22/representation-build-reps-arr-rules.test.cjs diff --git a/components/case/representation/index.js b/components/case/representation/index.js index f9debdf9..0b12e97b 100644 --- a/components/case/representation/index.js +++ b/components/case/representation/index.js @@ -52,6 +52,10 @@ import { buildSubmitEnrichedValues, runFinalisationSequence } from "./utils/finalisationBoundary"; +import { + buildRepresentationContext, + buildRepsArrFromContext +} from "./utils/buildRepsArrRules"; let MakeRepresentation = (props) => { let { t } = useTranslation(); @@ -313,152 +317,24 @@ let MakeRepresentation = (props) => { const safeResultsObj = resultsObj || {}; const buildRepsArr = (detailsObj) => { - const buildArr = []; - const todaysDate = new Date(); - - const isDNS = appealType === 846040011; - const isSIPS = appealType === 846040002; - const specialistProcess = currentView.caseReference.specialistProcess; - - const isSpecialistNonHearing = specialistProcess !== 846040001; - - const involvementType = - props.props?.accountDetails?.accountDetails - ?.pinswg_typeofinvolvement; - - //const isAppellant = involvementType === 846040001; - - const isAppellant = + const isCaseOwner = props.props.accountDetails.accountDetails.emailaddress1 == props.searchResultsObj?.searchResultsObj?.value[0] .customerid_contact.emailaddress1; - const isAgent = involvementType === 846040000; - const isIP = involvementType === 846040061; - const isLPA = involvementType === 846040012; + const ctx = buildRepresentationContext({ + detailsObj, + appealType, + specialistProcess: currentView.caseReference.specialistProcess, + involvementType: + props.props?.accountDetails?.accountDetails + ?.pinswg_typeofinvolvement, + selectedCapacity: repCapacityType(), + isCaseOwner, + isNRW + }); - const startDate = new Date( - isDNS - ? detailsObj.pinswg_applicationacceptedasvalid - : detailsObj.pinswg_startdate || detailsObj.pinswg_startdates - ); - - const finalCommentsDate = new Date( - isDNS - ? detailsObj.pinswg_endofrepresentationperiod - : detailsObj.pinswg_finalcommentsduedate - ); - finalCommentsDate.setHours(23, 59, 59, 999); - - const statementDueDate = new Date( - isDNS - ? detailsObj.pinswg_endofrepresentationperiod - : detailsObj.pinswg_statementduedate || - detailsObj.pinswg_statementsduedate - ); - statementDueDate.setHours(23, 59, 59, 999); - - const isWithin = (start, end) => - todaysDate >= start && todaysDate <= end; - - const addRep = (value) => { - if (!buildArr.includes(value)) { - buildArr.push(value); - } - }; - - const canAddQuestionnaire = - isLPA && - ![846040019, 846040011, 846040015, 846040016].includes( - appealType - ) && - isWithin(startDate, finalCommentsDate); - - if (canAddQuestionnaire) { - addRep("Questionnaire"); - } - - const isLpaAdvertPart3NoStatement = - isLPA && - appealType === 846040018 && - specialistProcess === 846040000; - - const canAddDnsLpaDocs = - isLPA && - isDNS && - appealType !== 846040019 && - !isAppellant && - isWithin(startDate, finalCommentsDate); - - if (canAddDnsLpaDocs) { - addRep("Local Impact Report"); - addRep("Statement"); - } - - const canAddStatementForNonDns = - !isDNS && - appealType !== 846040004 && - !isLpaAdvertPart3NoStatement && - !isAppellant && - isWithin(startDate, statementDueDate); - - if (canAddStatementForNonDns) { - addRep("Statement"); - } - - const canAddStatementForDnsNonLpa = - isDNS && - !isLPA && - !isAppellant && - isWithin(startDate, statementDueDate); - - if (canAddStatementForDnsNonLpa) { - addRep("Statement"); - } - - const canSubmitFinalComments = isAppellant || isAgent || isIP || isLPA; - - const canAddFinalComments = - canSubmitFinalComments && - isWithin(statementDueDate, finalCommentsDate) && - (appealType !== 846040004 || isSpecialistNonHearing); - - // IP and Agents and LPA can do final comments. - - if (canAddFinalComments) { - addRep("Final comments"); - } - - if (isSIPS) { - const capacity = repCapacityType(); - - addRep("Consultation Response"); - - if (capacity !== "appellant") { - addRep("Local Impact Report"); - } - - if (isNRW) { - addRep("Marine Impact Report"); - } - } - - console.log( - "======================================\n\n", - "isAgent: " + isAgent, - "\n", - "isIP: " + isIP, - "\n", - "isLPA: " + isLPA, - "\n", - "isAppellant: " + isAppellant, - "\n\n======================================\n\n", - "options: ", - buildArr, - "\n\n======================================\n\n" - ); - - return buildArr; + return buildRepsArrFromContext(ctx); }; const repCapacityType = () => { diff --git a/components/case/representation/utils/buildRepsArrRules.js b/components/case/representation/utils/buildRepsArrRules.js new file mode 100644 index 00000000..b9439c8f --- /dev/null +++ b/components/case/representation/utils/buildRepsArrRules.js @@ -0,0 +1,216 @@ +export const APPEAL_TYPES = { + SIPS: 846040002, + DNS: 846040011, + HOUSEHOLDER: 846040004, + ADVERT: 846040018, + EXCLUDE_QUESTIONNAIRE_1: 846040019, + EXCLUDE_QUESTIONNAIRE_2: 846040015, + EXCLUDE_QUESTIONNAIRE_3: 846040016 +}; + +export const SPECIALIST_PROCESS = { + WRITTEN_REPS: 846040000, + HEARING: 846040001 +}; + +export const INVOLVEMENT_TYPES = { + LPA: 846040012 +}; + +export const REPRESENTATION_OPTIONS = { + QUESTIONNAIRE: "Questionnaire", + STATEMENT: "Statement", + FINAL_COMMENTS: "Final comments", + CONSULTATION_RESPONSE: "Consultation Response", + LOCAL_IMPACT_REPORT: "Local Impact Report", + MARINE_IMPACT_REPORT: "Marine Impact Report" +}; + +const isValidDate = (date) => + date instanceof Date && !Number.isNaN(date.getTime()); + +const toDateOrNull = (value) => { + const date = new Date(value); + return isValidDate(date) ? date : null; +}; + +const endOfDay = (date) => { + if (!isValidDate(date)) return null; + const next = new Date(date); + next.setHours(23, 59, 59, 999); + return next; +}; + +const isWithinWindow = (now, start, end) => { + if (!isValidDate(now) || !isValidDate(start) || !isValidDate(end)) { + return false; + } + return now >= start && now <= end; +}; + +const normalizeCapacity = (value) => + (value || "") + .toString() + .toLowerCase() + .replace(/(\band|[\s\-\+\(\)\,\&])/g, ""); + +export const buildRepresentationContext = ({ + detailsObj = {}, + appealType, + specialistProcess, + involvementType, + selectedCapacity, + isCaseOwner, + isNRW, + now = new Date() +}) => { + const isDNS = appealType === APPEAL_TYPES.DNS; + + const startDate = toDateOrNull( + isDNS + ? detailsObj.pinswg_applicationacceptedasvalid + : detailsObj.pinswg_startdate || detailsObj.pinswg_startdates + ); + + const statementDueDate = endOfDay( + toDateOrNull( + isDNS + ? detailsObj.pinswg_endofrepresentationperiod + : detailsObj.pinswg_statementduedate || + detailsObj.pinswg_statementsduedate + ) + ); + + const finalCommentsDueDate = endOfDay( + toDateOrNull( + isDNS + ? detailsObj.pinswg_endofrepresentationperiod + : detailsObj.pinswg_finalcommentsduedate + ) + ); + + const capacity = normalizeCapacity(selectedCapacity); + const isLPA = involvementType === INVOLVEMENT_TYPES.LPA; + + return { + appealType, + specialistProcess, + isDNS, + isSIPS: appealType === APPEAL_TYPES.SIPS, + isLPA, + isNRW: !!isNRW, + isCaseOwner: !!isCaseOwner, + isSelectedAppellant: capacity === "appellant", + isSelectedAgent: capacity === "agent", + isSelectedInterestedParty: capacity === "interestedparty", + now, + startDate, + statementDueDate, + finalCommentsDueDate + }; +}; + +export const addQuestionnaire = (options, ctx) => { + const excludedTypes = [ + APPEAL_TYPES.EXCLUDE_QUESTIONNAIRE_1, + APPEAL_TYPES.DNS, + APPEAL_TYPES.EXCLUDE_QUESTIONNAIRE_2, + APPEAL_TYPES.EXCLUDE_QUESTIONNAIRE_3 + ]; + + const canAdd = + ctx.isLPA && + !excludedTypes.includes(ctx.appealType) && + isWithinWindow(ctx.now, ctx.startDate, ctx.finalCommentsDueDate); + + if (canAdd) { + options.add(REPRESENTATION_OPTIONS.QUESTIONNAIRE); + } +}; + +export const addStatements = (options, ctx) => { + const isLpaAdvertPart3NoStatement = + ctx.isLPA && + ctx.appealType === APPEAL_TYPES.ADVERT && + ctx.specialistProcess === SPECIALIST_PROCESS.WRITTEN_REPS; + + const canAddDnsLpaDocs = + ctx.isLPA && + ctx.isDNS && + ctx.appealType !== APPEAL_TYPES.EXCLUDE_QUESTIONNAIRE_1 && + !ctx.isCaseOwner && + isWithinWindow(ctx.now, ctx.startDate, ctx.finalCommentsDueDate); + + if (canAddDnsLpaDocs) { + options.add(REPRESENTATION_OPTIONS.LOCAL_IMPACT_REPORT); + options.add(REPRESENTATION_OPTIONS.STATEMENT); + } + + const canAddStatementForNonDns = + !ctx.isDNS && + ctx.appealType !== APPEAL_TYPES.HOUSEHOLDER && + !isLpaAdvertPart3NoStatement && + !ctx.isCaseOwner && + isWithinWindow(ctx.now, ctx.startDate, ctx.statementDueDate); + + if (canAddStatementForNonDns) { + options.add(REPRESENTATION_OPTIONS.STATEMENT); + } + + const canAddStatementForDnsNonLpa = + ctx.isDNS && + !ctx.isLPA && + !ctx.isCaseOwner && + isWithinWindow(ctx.now, ctx.startDate, ctx.statementDueDate); + + if (canAddStatementForDnsNonLpa) { + options.add(REPRESENTATION_OPTIONS.STATEMENT); + } +}; + +export const addFinalComments = (options, ctx) => { + const canSubmitFinalComments = + ctx.isSelectedAppellant || + ctx.isSelectedAgent || + ctx.isSelectedInterestedParty || + ctx.isLPA; + + const isSpecialistNonHearing = + ctx.specialistProcess !== SPECIALIST_PROCESS.HEARING; + + const canAdd = + canSubmitFinalComments && + isWithinWindow( + ctx.now, + ctx.statementDueDate, + ctx.finalCommentsDueDate + ) && + (ctx.appealType !== APPEAL_TYPES.HOUSEHOLDER || isSpecialistNonHearing); + + if (canAdd) { + options.add(REPRESENTATION_OPTIONS.FINAL_COMMENTS); + } +}; + +export const addConsultation = (options, ctx) => { + if (!ctx.isSIPS) return; + + options.add(REPRESENTATION_OPTIONS.CONSULTATION_RESPONSE); + + if (!ctx.isSelectedAppellant) { + options.add(REPRESENTATION_OPTIONS.LOCAL_IMPACT_REPORT); + } + + if (ctx.isNRW) { + options.add(REPRESENTATION_OPTIONS.MARINE_IMPACT_REPORT); + } +}; + +export const buildRepsArrFromContext = (ctx) => { + const options = new Set(); + addQuestionnaire(options, ctx); + addStatements(options, ctx); + addFinalComments(options, ctx); + addConsultation(options, ctx); + return [...options]; +}; diff --git a/tests/phase22/index.test.cjs b/tests/phase22/index.test.cjs index 7bfabdc5..76f99725 100644 --- a/tests/phase22/index.test.cjs +++ b/tests/phase22/index.test.cjs @@ -9,6 +9,7 @@ const runAzurestorageHelperTests = require("./azurestorage-helper-behaviour.test const runRouteStateHelperTests = require("./route-state-helper.test.cjs"); const runBreadcrumbRouteMapsHelperTests = require("./breadcrumb-route-maps-helper.test.cjs"); const runBreadcrumbsRouteMapStructureTests = require("./breadcrumbs-route-map-structure.test.cjs"); +const runRepresentationBuildRepsArrRulesTests = require("./representation-build-reps-arr-rules.test.cjs"); const run = async () => { await runCoreTokenTests(); @@ -22,6 +23,7 @@ const run = async () => { await runRouteStateHelperTests(); await runBreadcrumbRouteMapsHelperTests(); await runBreadcrumbsRouteMapStructureTests(); + await runRepresentationBuildRepsArrRulesTests(); console.log("Phase 22 combined suite passed."); }; diff --git a/tests/phase22/representation-build-reps-arr-rules.test.cjs b/tests/phase22/representation-build-reps-arr-rules.test.cjs new file mode 100644 index 00000000..fa19daf6 --- /dev/null +++ b/tests/phase22/representation-build-reps-arr-rules.test.cjs @@ -0,0 +1,454 @@ +const fs = require("fs"); +const path = require("path"); +const vm = require("vm"); +const assert = require("assert"); + +const rootDir = path.resolve(__dirname, "..", ".."); + +const loadBuildRepsArrRulesModule = () => { + const filePath = path.join( + rootDir, + "components", + "case", + "representation", + "utils", + "buildRepsArrRules.js" + ); + + let source = fs.readFileSync(filePath, "utf8"); + source = source.replace(/export const\s+/g, "const "); + source += ` +module.exports = { + APPEAL_TYPES, + SPECIALIST_PROCESS, + INVOLVEMENT_TYPES, + buildRepresentationContext, + buildRepsArrFromContext +}; +`; + + 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 }); + +const mod = loadBuildRepsArrRulesModule(); +const { + APPEAL_TYPES, + SPECIALIST_PROCESS, + INVOLVEMENT_TYPES, + buildRepresentationContext, + buildRepsArrFromContext +} = mod; + +const BASE_DETAILS = { + pinswg_startdate: "2026-04-01T00:00:00.000Z", + pinswg_statementduedate: "2026-04-30T00:00:00.000Z", + pinswg_finalcommentsduedate: "2026-05-25T00:00:00.000Z" +}; + +const baseInput = (overrides = {}) => ({ + detailsObj: BASE_DETAILS, + appealType: 846040000, + specialistProcess: SPECIALIST_PROCESS.WRITTEN_REPS, + involvementType: 999, + selectedCapacity: "appellant", + isCaseOwner: false, + isNRW: false, + now: new Date("2026-04-10T10:00:00.000Z"), + ...overrides +}); + +const buildOptions = (overrides = {}) => + buildRepsArrFromContext(buildRepresentationContext(baseInput(overrides))); + +test("baseline truth-table: non-DNS non-SIPS across windows/capacities/ownership", () => { + const capacities = [ + { value: "appellant", hasFinalComments: true }, + { value: "agent", hasFinalComments: true }, + { value: "interestedparty", hasFinalComments: true }, + { value: false, hasFinalComments: false }, + { value: "", hasFinalComments: false }, + { value: "unknown", hasFinalComments: false } + ]; + + const cases = [ + { + label: "before start", + now: "2026-03-31T10:00:00.000Z", + expected: (c, isCaseOwner) => [] + }, + { + label: "statement period", + now: "2026-04-15T10:00:00.000Z", + expected: (c, isCaseOwner) => (isCaseOwner ? [] : ["Statement"]) + }, + { + label: "final comments period", + now: "2026-05-10T10:00:00.000Z", + expected: (c) => (c.hasFinalComments ? ["Final comments"] : []) + }, + { + label: "after final comments due", + now: "2026-05-26T10:00:00.000Z", + expected: () => [] + } + ]; + + for (const capacity of capacities) { + for (const scenario of cases) { + for (const isCaseOwner of [true, false]) { + const result = buildOptions({ + selectedCapacity: capacity.value, + isCaseOwner, + now: new Date(scenario.now) + }); + assert.deepStrictEqual( + result, + scenario.expected(capacity, isCaseOwner), + `Failed for ${scenario.label}, capacity=${capacity.value}, isCaseOwner=${isCaseOwner}` + ); + } + } + } +}); + +test("LPA involvement: questionnaire and final comments windows", () => { + assert.deepStrictEqual( + buildOptions({ + involvementType: INVOLVEMENT_TYPES.LPA, + selectedCapacity: "unknown", + now: new Date("2026-04-10T10:00:00.000Z") + }), + ["Questionnaire", "Statement"] + ); + + assert.deepStrictEqual( + buildOptions({ + involvementType: INVOLVEMENT_TYPES.LPA, + selectedCapacity: "unknown", + now: new Date("2026-05-10T10:00:00.000Z") + }), + ["Questionnaire", "Final comments"] + ); + + assert.deepStrictEqual( + buildOptions({ + involvementType: INVOLVEMENT_TYPES.LPA, + selectedCapacity: "unknown", + now: new Date("2026-05-26T10:00:00.000Z") + }), + [] + ); +}); + +test("questionnaire excluded appeal types for LPA", () => { + const excluded = [846040019, 846040011, 846040015, 846040016]; + for (const appealType of excluded) { + const result = buildOptions({ + appealType, + involvementType: INVOLVEMENT_TYPES.LPA, + now: new Date("2026-04-10T10:00:00.000Z") + }); + assert.strictEqual( + result.includes("Questionnaire"), + false, + `Questionnaire should be excluded for ${appealType}` + ); + } +}); + +test("householder: statements blocked; final comments depend on specialist process", () => { + assert.deepStrictEqual( + buildOptions({ + appealType: APPEAL_TYPES.HOUSEHOLDER, + selectedCapacity: "appellant", + specialistProcess: SPECIALIST_PROCESS.HEARING, + now: new Date("2026-04-15T10:00:00.000Z") + }), + [] + ); + + assert.deepStrictEqual( + buildOptions({ + appealType: APPEAL_TYPES.HOUSEHOLDER, + selectedCapacity: "appellant", + specialistProcess: SPECIALIST_PROCESS.HEARING, + now: new Date("2026-05-10T10:00:00.000Z") + }), + [] + ); + + assert.deepStrictEqual( + buildOptions({ + appealType: APPEAL_TYPES.HOUSEHOLDER, + selectedCapacity: "appellant", + specialistProcess: SPECIALIST_PROCESS.WRITTEN_REPS, + now: new Date("2026-05-10T10:00:00.000Z") + }), + ["Final comments"] + ); +}); + +test("advert appeal type: LPA written reps blocks statement, non-LPA non-owner can still submit statement", () => { + assert.deepStrictEqual( + buildOptions({ + appealType: APPEAL_TYPES.ADVERT, + involvementType: INVOLVEMENT_TYPES.LPA, + specialistProcess: SPECIALIST_PROCESS.WRITTEN_REPS, + now: new Date("2026-04-15T10:00:00.000Z") + }), + ["Questionnaire"] + ); + + assert.deepStrictEqual( + buildOptions({ + appealType: APPEAL_TYPES.ADVERT, + involvementType: 999, + isCaseOwner: false, + now: new Date("2026-04-15T10:00:00.000Z") + }), + ["Statement"] + ); +}); + +test("DNS rules: statement/LIR ownership behaviour and questionnaire exclusion", () => { + const dnsDetails = { + pinswg_applicationacceptedasvalid: "2026-04-01T00:00:00.000Z", + pinswg_endofrepresentationperiod: "2026-05-25T00:00:00.000Z" + }; + + const dnsOptions = (overrides = {}) => + buildRepsArrFromContext( + buildRepresentationContext( + baseInput({ + appealType: APPEAL_TYPES.DNS, + detailsObj: dnsDetails, + ...overrides + }) + ) + ); + + assert.deepStrictEqual( + dnsOptions({ + involvementType: 999, + isCaseOwner: false, + now: new Date("2026-05-01T10:00:00.000Z") + }), + ["Statement"] + ); + + assert.deepStrictEqual( + dnsOptions({ + involvementType: 999, + isCaseOwner: true, + now: new Date("2026-05-01T10:00:00.000Z") + }), + [] + ); + + assert.deepStrictEqual( + dnsOptions({ + involvementType: INVOLVEMENT_TYPES.LPA, + isCaseOwner: false, + now: new Date("2026-05-01T10:00:00.000Z") + }), + ["Local Impact Report", "Statement", "Final comments"] + ); + + assert.deepStrictEqual( + dnsOptions({ + involvementType: INVOLVEMENT_TYPES.LPA, + isCaseOwner: true, + now: new Date("2026-05-01T10:00:00.000Z") + }), + ["Final comments"] + ); + + assert.strictEqual( + dnsOptions({ + involvementType: INVOLVEMENT_TYPES.LPA, + isCaseOwner: false, + now: new Date("2026-05-01T10:00:00.000Z") + }).includes("Questionnaire"), + false + ); +}); + +test("SIPS consultation behaviour is not date-gated", () => { + const sips = (overrides = {}) => + buildOptions({ appealType: APPEAL_TYPES.SIPS, ...overrides }); + + assert.deepStrictEqual( + sips({ selectedCapacity: "appellant", isNRW: false }), + ["Statement", "Consultation Response"] + ); + + assert.deepStrictEqual(sips({ selectedCapacity: "agent", isNRW: false }), [ + "Statement", + "Consultation Response", + "Local Impact Report" + ]); + + assert.deepStrictEqual( + sips({ selectedCapacity: "interestedparty", isNRW: true }), + [ + "Statement", + "Consultation Response", + "Local Impact Report", + "Marine Impact Report" + ] + ); + + assert.deepStrictEqual( + sips({ + selectedCapacity: "appellant", + now: new Date("2026-06-01T10:00:00.000Z") + }), + ["Consultation Response"] + ); +}); + +test("deduplication and ordering are stable", () => { + const result = buildOptions({ + appealType: APPEAL_TYPES.SIPS, + involvementType: INVOLVEMENT_TYPES.LPA, + selectedCapacity: "agent", + isNRW: true, + isCaseOwner: false, + now: new Date("2026-05-10T10:00:00.000Z") + }); + + assert.deepStrictEqual(result, [ + "Questionnaire", + "Final comments", + "Consultation Response", + "Local Impact Report", + "Marine Impact Report" + ]); + assert.strictEqual(new Set(result).size, result.length); +}); + +test("invalid or missing dates suppress date-gated options but SIPS consultation persists", () => { + assert.deepStrictEqual( + buildRepsArrFromContext( + buildRepresentationContext( + baseInput({ + detailsObj: { + pinswg_statementduedate: "2026-04-30T00:00:00.000Z", + pinswg_finalcommentsduedate: "2026-05-25T00:00:00.000Z" + } + }) + ) + ), + [] + ); + + assert.deepStrictEqual( + buildRepsArrFromContext( + buildRepresentationContext( + baseInput({ + detailsObj: { + pinswg_startdate: "2026-04-01T00:00:00.000Z", + pinswg_finalcommentsduedate: "2026-05-25T00:00:00.000Z" + } + }) + ) + ), + [] + ); + + assert.deepStrictEqual( + buildRepsArrFromContext( + buildRepresentationContext( + baseInput({ + detailsObj: { + pinswg_startdate: "2026-04-01T00:00:00.000Z", + pinswg_statementduedate: "2026-04-30T00:00:00.000Z" + }, + involvementType: INVOLVEMENT_TYPES.LPA, + now: new Date("2026-05-10T10:00:00.000Z") + }) + ) + ), + [] + ); + + assert.deepStrictEqual( + buildRepsArrFromContext( + buildRepresentationContext( + baseInput({ + appealType: APPEAL_TYPES.SIPS, + detailsObj: {}, + selectedCapacity: "agent", + isNRW: true, + now: new Date("2026-06-20T10:00:00.000Z") + }) + ) + ), + ["Consultation Response", "Local Impact Report", "Marine Impact Report"] + ); +}); + +test("capacity normalization coverage", () => { + const inFinalWindow = { now: new Date("2026-05-10T10:00:00.000Z") }; + + assert.deepStrictEqual( + buildOptions({ selectedCapacity: "appellant", ...inFinalWindow }), + ["Final comments"] + ); + + assert.deepStrictEqual( + buildOptions({ selectedCapacity: "Appellant", ...inFinalWindow }), + ["Final comments"] + ); + + assert.deepStrictEqual( + buildOptions({ + selectedCapacity: "Interested Party", + ...inFinalWindow + }), + ["Final comments"] + ); + + assert.deepStrictEqual( + buildOptions({ + selectedCapacity: "interested-party", + ...inFinalWindow + }), + ["Final comments"] + ); + + assert.deepStrictEqual( + buildOptions({ selectedCapacity: "agent", ...inFinalWindow }), + ["Final comments"] + ); +}); + +const run = async () => { + let passed = 0; + for (const currentTest of tests) { + await currentTest.fn(); + passed += 1; + } + console.log( + `Phase 22 representation buildRepsArr rules tests passed (${passed}/${tests.length}).` + ); +}; + +module.exports = run; + +if (require.main === module) { + run().catch((error) => { + console.error(error); + process.exit(1); + }); +}