diff --git a/memory-bank/change-log.md b/memory-bank/change-log.md index 4ccccdb5..9808613a 100644 --- a/memory-bank/change-log.md +++ b/memory-bank/change-log.md @@ -2602,3 +2602,40 @@ Validation: Follow-ups: - Optional next widened slice: add a focused phase22 behavioral suite for `caseDirectService` and normalize any remaining specialized encoding usage behind explicit helper options where appropriate. + +--- + +### CL-073: TASK22260 essential condensed slice — case phase22 behavioural coverage + encoding contract lock + +date: 2026-03-25 +author: Cline +scope: `tests/phase22/{case-service-behaviour,index}.test.cjs` +type: change +rationale: Condense remaining core work into one essential slice by adding explicit phase22 behavioural coverage for `caseDirectService` route composition and encoding-sensitive contracts. +impact: Improves regression confidence for case service route-building behavior (BASE_URL composition, case-reference encoding/escaping, error-return contracts) without runtime behavior changes. +status: completed + +Summary: + +- Added new suite `tests/phase22/case-service-behaviour.test.cjs` with focused behavioural assertions for: + - `getPortalModuleDetails` BASE_URL + encoded case reference composition + - `getPortalModuleDetailsProxy` apostrophe escape behavior in case reference + - `getAppealID` query composition and non-underscore value extraction + - `getAppealPDFDocument` failure-path logging + `error.response` passthrough +- Updated `tests/phase22/index.test.cjs` aggregate runner to include `case-service-behaviour` suite. + +Validation: + +- `node tests/phase22/index.test.cjs` -> pass + - core-token: 2/2 + - client-utils: 6/6 + - file-client: 4/4 + - case-service: 4/4 + - phase22 combined: pass +- `node tests/phase6/service-behaviour.test.cjs` -> pass (9/9) +- `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) +- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) + +Follow-ups: + +- Optional closure slice: add a dedicated phase22 portal-service behavioural suite and finish harmonization of remaining direct query string composition in `portalDirectService` write helpers. diff --git a/tests/phase22/case-service-behaviour.test.cjs b/tests/phase22/case-service-behaviour.test.cjs new file mode 100644 index 00000000..5c37e232 --- /dev/null +++ b/tests/phase22/case-service-behaviour.test.cjs @@ -0,0 +1,130 @@ +const assert = require("assert"); +const { + createAxiosMock, + createLoggerMock, + createAxiosError, + loadServiceModule, + normalize +} = require("../serviceHarness.cjs"); + +const tests = []; +const test = (name, fn) => tests.push({ name, fn }); + +test("case/getPortalModuleDetails uses BASE_URL route and encoded case reference", async () => { + const axios = createAxiosMock(); + const logger = createLoggerMock(); + + axios.getHandler = async () => ({ data: { value: [] } }); + + const caseService = loadServiceModule("caseDirectService.js", { + axios, + BASE_URL: "http://example.local", + consoleLogger: logger.consoleLogger + }); + + const result = await caseService.getPortalModuleDetails( + "appeal", + "REF A/B" + ); + + assert.deepStrictEqual(normalize(result), { value: [] }); + assert.strictEqual( + axios.calls[0].url, + "http://example.local/api/endpoint/getportalmoduledetails_api?appealType=appeal&caseReference=REF%20A/B" + ); +}); + +test("case/getPortalModuleDetailsProxy escapes apostrophes in case reference", async () => { + const axios = createAxiosMock(); + const logger = createLoggerMock(); + + axios.getHandler = async () => ({ data: { value: [] } }); + + const caseService = loadServiceModule("caseDirectService.js", { + axios, + BASE_URL: "", + consoleLogger: logger.consoleLogger + }); + + const result = await caseService.getPortalModuleDetailsProxy( + "appeal", + "REF'O" + ); + + assert.deepStrictEqual(normalize(result), { value: [] }); + assert.strictEqual( + axios.calls[0].url, + "/api/endpoint/getportalmoduledetailsproxy_api?appealType=appeal&caseReference=REF''O" + ); +}); + +test("case/getAppealID composes lookup route and extracts first non-underscore value", async () => { + const axios = createAxiosMock(); + const logger = createLoggerMock(); + + axios.getHandler = async () => ({ + data: { + value: [ + { + _internal: "ignore", + pinswg_appeal: "appeal-123" + } + ] + } + }); + + const caseService = loadServiceModule("caseDirectService.js", { + axios, + BASE_URL: "", + consoleLogger: logger.consoleLogger + }); + + const result = await caseService.getAppealID("REF-1", "pinswg_cases", "id"); + + assert.strictEqual(result, "appeal-123"); + assert.strictEqual( + axios.calls[0].url, + "/api/endpoint/getappealid_api?updateFormCollection=pinswg_cases&primaryAttribute=id&caseReference=REF-1" + ); +}); + +test("case/getAppealPDFDocument logs and returns error.response on failure", async () => { + const axios = createAxiosMock(); + const logger = createLoggerMock(); + const error = createAxiosError(404, "Not Found"); + + axios.getHandler = async () => Promise.reject(error); + + const caseService = loadServiceModule("caseDirectService.js", { + axios, + BASE_URL: "http://example.local", + consoleLogger: logger.consoleLogger + }); + + const result = await caseService.getAppealPDFDocument("inc-123"); + + assert.strictEqual(result, error.response); + assert.strictEqual(logger.calls.length, 1); +}); + +const run = async () => { + let passed = 0; + + for (const currentTest of tests) { + await currentTest.fn(); + passed += 1; + } + + console.log( + `Phase 22 case-service tests passed (${passed}/${tests.length}).` + ); +}; + +module.exports = run; + +if (require.main === module) { + run().catch((error) => { + console.error(error); + process.exit(1); + }); +} diff --git a/tests/phase22/index.test.cjs b/tests/phase22/index.test.cjs index 976bf9ee..bacc8e98 100644 --- a/tests/phase22/index.test.cjs +++ b/tests/phase22/index.test.cjs @@ -1,11 +1,13 @@ const runCoreTokenTests = require("./core-token-behaviour.test.cjs"); const runClientUtilsTests = require("./client-utils-behaviour.test.cjs"); const runFileClientTests = require("./file-client-behaviour.test.cjs"); +const runCaseServiceTests = require("./case-service-behaviour.test.cjs"); const run = async () => { await runCoreTokenTests(); await runClientUtilsTests(); await runFileClientTests(); + await runCaseServiceTests(); console.log("Phase 22 combined suite passed."); };