shoc-frontend-new/src/test/domain/work-orders/utils/wo-closability.test.ts

131 lines
3.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { WoClosabilityInput } from "@/domain/work-orders/utils/wo-closability";
import {
PENDING_UPLIFT_GAP,
UPLIFT_PENDING_COMPLETED_TITLE,
canGenerateCompDoc,
formatClosabilityMissingTitle,
getClosabilityGaps,
hasPendingUplift,
isRealWoNumber,
} from "@/domain/work-orders/utils/wo-closability";
function makeInput(overrides: Partial<WoClosabilityInput> = {}): WoClosabilityInput {
return {
dispatcherId: "u1",
dispatcherName: "Alex",
tech: "Sam",
completedDate: "2026-07-01",
woNumber: "1001",
pm: "HVAC",
docStatus: "Yes",
mediaCount: 1,
type: "PM",
upliftSummary: undefined,
hasPendingUplift: undefined,
...overrides,
};
}
describe("isRealWoNumber", () => {
it("rejects empty and SH-prefixed provisional numbers", () => {
expect(isRealWoNumber("")).toBe(false);
expect(isRealWoNumber("SH-9")).toBe(false);
expect(isRealWoNumber("sh123")).toBe(false);
expect(isRealWoNumber("98765")).toBe(true);
});
});
describe("hasPendingUplift", () => {
it("is true when hasPendingUplift flag is set", () => {
expect(hasPendingUplift(makeInput({ hasPendingUplift: true }))).toBe(true);
});
it("is true when upliftSummary.pendingCount is positive", () => {
expect(
hasPendingUplift(makeInput({ upliftSummary: { hasUplift: true, pendingCount: 2 } })),
).toBe(true);
});
it("is false when no uplift signals are present", () => {
expect(hasPendingUplift(makeInput())).toBe(false);
expect(
hasPendingUplift(makeInput({ upliftSummary: { hasUplift: false, pendingCount: 0 } })),
).toBe(false);
});
});
describe("getClosabilityGaps", () => {
it("returns empty when all gates are satisfied", () => {
expect(getClosabilityGaps(makeInput())).toEqual([]);
});
it("lists field gaps before uplift and document gaps", () => {
expect(
getClosabilityGaps(
makeInput({
dispatcherId: "",
dispatcherName: "",
tech: " ",
completedDate: "",
woNumber: "SH-1",
pm: "",
hasPendingUplift: true,
docStatus: "No",
type: "PM",
}),
),
).toEqual([
"Dispatcher",
"Technician",
"Completed Date",
"WO number",
"Service",
PENDING_UPLIFT_GAP,
"Completion document",
]);
});
it("blocks Completed when uplift is pending via summary", () => {
expect(
getClosabilityGaps(makeInput({ upliftSummary: { hasUplift: true, pendingCount: 1 } })),
).toEqual([PENDING_UPLIFT_GAP]);
});
it("blocks Completed when hasPendingUplift is true", () => {
expect(getClosabilityGaps(makeInput({ hasPendingUplift: true }))).toEqual([PENDING_UPLIFT_GAP]);
});
it("requires a photo for Emergency / Reactive", () => {
expect(
getClosabilityGaps(makeInput({ type: "Emergency", mediaCount: 0, docStatus: "No" })),
).toEqual(["At least 1 photo"]);
});
});
describe("formatClosabilityMissingTitle", () => {
it("uses design Completed title when only uplift is missing", () => {
expect(formatClosabilityMissingTitle([PENDING_UPLIFT_GAP])).toBe(
UPLIFT_PENDING_COMPLETED_TITLE,
);
});
it("joins multiple gaps with Missing prefix", () => {
expect(formatClosabilityMissingTitle(["Dispatcher", PENDING_UPLIFT_GAP])).toBe(
`Missing: Dispatcher, ${PENDING_UPLIFT_GAP}`,
);
});
});
describe("canGenerateCompDoc", () => {
it("allows generation when no closability gaps", () => {
expect(canGenerateCompDoc(makeInput())).toEqual({ allowed: true });
});
it("blocks generation with design reason when only pending uplift exists", () => {
expect(canGenerateCompDoc(makeInput({ hasPendingUplift: true }))).toEqual({
allowed: false,
reason: UPLIFT_PENDING_COMPLETED_TITLE,
});
});
});