Files
pedwfrontend/tests/phase22/case-lifecycle-specialist-process-normalization.test.cjs
T
Robert Bond 9595ad86df Merged PR 2374: addeding domain layer extrraction
# Summary

This PR introduces a **Case Lifecycle Domain Boundary** to centralize lifecycle decision logic and reduce coupling within the appeals application.

The work is **behaviour-preserving** and introduces no intentional changes to business rules, CRM integrations, translations, dashboards, API routes, or user-facing functionality.

## What was added

New lifecycle boundary:

```text
lib/domain/case-lifecycle/
```

Key responsibilities extracted:

- Specialist process normalization
- Appeal type mapping
- Specialist process stage override mapping
- Stage case-type resolution
- Stage catalogue lookup
- Closed-case status recognition
- Lifecycle stage index resolution
- Lifecycle stage status assignment

## Behaviour preserved

Characterization tests were added before each extraction to preserve:

- Appeal type mapping and aliases
- Specialist process handling
- Lifecycle stage progression
- Closed-case handling
- Status assignment (`complete`, `in-progress`, `not-started`)
- Existing ROW behaviour
- Existing `statuscode` lifecycle semantics

Closed-case recognition remains unchanged for:

```text
1000
5
6
846040013
846040059
846040060
```

## Documentation

Added:

```text
lib/domain/case-lifecycle/README.md
```

Documenting:

- Boundary ownership
- Non-goals
- Lifecycle invariants
- Known architectural constraints
- Future extraction roadmap

## Testing

Added lifecycle characterization coverage for:

- Stage wrapper behaviour
- Specialist process normalization
- Appeal type mapping
- Specialist process stage mapping
- Stage case-type resolution
- Stage catalogue lookup
- Progress behaviour
- Closed-case status handling
- Stage index resolution
- Stage status assignment

## Validation

- Lifecycle characterization tests passed
- `npm run lint` passed with no errors

## Out of Scope

No changes to:

- Stage catalogue ownership
- Representation eligibility
- Dashboard calculations
- CRM/OData queries
- API routes
- Redux state
- EN/CY translations
- Event visibility logic

## Risk

**Low risk**

The refactor was delivered through small, characterization-first slices with no functional changes intended.

Related work items: #23527
2026-06-08 09:34:30 +00:00

113 lines
2.9 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const vm = require("vm");
const assert = require("assert");
const rootDir = path.resolve(__dirname, "..", "..");
const loadNormalizationModule = () => {
const filePath = path.join(
rootDir,
"lib",
"domain",
"case-lifecycle",
"normalizeSpecialistProcess.js"
);
let source = fs.readFileSync(filePath, "utf8");
source = source.replace(
/export function\s+normalizeSpecialistProcess/,
"function normalizeSpecialistProcess"
);
source += "\nmodule.exports = { normalizeSpecialistProcess };\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 });
const { normalizeSpecialistProcess } = loadNormalizationModule();
test("returns pinswg_specialistcaseprocess when present", () => {
assert.strictEqual(
normalizeSpecialistProcess({ pinswg_specialistcaseprocess: 846040001 }),
846040001
);
});
test("returns misspelled fallback when canonical field is absent", () => {
assert.strictEqual(
normalizeSpecialistProcess({
pinswg_speacialistcaseprocess: 846040000
}),
846040000
);
});
test("canonical field wins when both fields exist", () => {
assert.strictEqual(
normalizeSpecialistProcess({
pinswg_specialistcaseprocess: 846040001,
pinswg_speacialistcaseprocess: 846040000
}),
846040001
);
});
test("returns empty string when neither field exists", () => {
assert.strictEqual(normalizeSpecialistProcess({}), "");
});
test("returns empty string for null or undefined source", () => {
assert.strictEqual(normalizeSpecialistProcess(null), "");
assert.strictEqual(normalizeSpecialistProcess(undefined), "");
});
test("preserves number values without coercing to strings", () => {
const result = normalizeSpecialistProcess({
pinswg_specialistcaseprocess: 846040001
});
assert.strictEqual(typeof result, "number");
assert.strictEqual(result, 846040001);
});
test("preserves string values without coercing to numbers", () => {
const result = normalizeSpecialistProcess({
pinswg_specialistcaseprocess: "846040001"
});
assert.strictEqual(typeof result, "string");
assert.strictEqual(result, "846040001");
});
const run = async () => {
let passed = 0;
for (const currentTest of tests) {
await currentTest.fn();
passed += 1;
}
console.log(
`Phase 22 case-lifecycle-specialist-process-normalization tests passed (${passed}/${tests.length}).`
);
};
module.exports = run;
if (require.main === module) {
run().catch((error) => {
console.error(error);
process.exit(1);
});
}