shoc-frontend-new/src/test/app/(protected)/workorders/use-slide-over-media-state.test.tsx
Arthur Bassi 0a2544fae4 fix(work-orders): persist Extra Docs Aveta category round-trip
Keep Extra uploads uncategorized until the dispatcher picks Aveta.
Drive the shield from hasAvetaDocument after reopen.
2026-08-25 15:11:25 -03:00

180 lines
4.8 KiB
TypeScript

import { renderHook } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { useSlideOverMediaState } from "@/app/(protected)/workorders/_components/detail/use-slide-over-media-state";
import type { WorkOrderBoardDetail } from "@/domain/work-orders/types/work-order-board-detail";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
function baseInfo(overrides: Partial<WorkOrderTableRow> = {}): WorkOrderTableRow {
return {
id: 100,
woNumber: "100",
site: "SITE",
type: "Emergency",
severity: null,
dispatcherId: "d1",
dispatcherName: "Alex",
scheduledOn: "2026-07-16",
completedDate: "",
targetWeek: "",
dayGroup: "2026-07-16",
dayLabel: "Thu",
location: "Main",
locationId: 5,
pm: "",
serviceNotes: "",
extraServices: [],
vendorId: "v1",
company: "Acme",
tech: "Sam",
techPhone: "",
apptStart: "",
apptEnd: "",
apptTime: "",
status: "Incomplete",
docStatus: "",
pocName: "",
pocPhone: "",
pocNotes: "",
additionalContacts: [],
dueDate: "",
rescheduleCount: 0,
carriedOver: 0,
originalWeek: "",
originalDate: "",
isPastDue: false,
scheduleWeekOnly: false,
mediaCount: 0,
title: "",
priority: "",
primaryDispatchId: null,
rowVersion: "1",
dispatchRowVersion: "",
flagColor: null,
isAddOn: false,
upliftSummary: { hasUplift: false, pendingCount: 0 },
...overrides,
};
}
function detailWithMedia(
media: WorkOrderBoardDetail["media"],
infoOverrides: Partial<WorkOrderTableRow> = {},
): WorkOrderBoardDetail {
return {
info: baseInfo(infoOverrides),
completion: {
docStatus: "",
template: null,
signOffName: "",
signOffAttachment: "",
signOffSignature: "",
dispatchSignoffs: [],
},
comments: [],
audit: [],
media,
};
}
function idleMutation() {
return {
mutate: vi.fn(),
mutateAsync: vi.fn().mockResolvedValue({}),
isPending: false,
} as never;
}
describe("useSlideOverMediaState completion filter", () => {
it("keeps Before/After/Completion after refetch mapped purpose (not file category)", () => {
const detail = detailWithMedia([
{
id: "1",
category: "Before",
url: "https://cdn.example.com/before.jpg",
fileName: "before.jpg",
uploadedAt: "2026-07-15T18:00:00.0000000Z",
isLegacy: false,
},
{
id: "2",
category: "After",
url: "https://cdn.example.com/after.jpg",
fileName: "after.jpg",
uploadedAt: "2026-07-15T18:00:00.0000000Z",
isLegacy: false,
},
{
id: "3",
category: "Completion",
url: "https://cdn.example.com/completion.pdf",
fileName: "completion.pdf",
uploadedAt: "2026-07-15T18:00:00.0000000Z",
isLegacy: false,
},
{
id: "4",
category: "Extra",
url: "https://cdn.example.com/extra.pdf",
fileName: "extra.pdf",
uploadedAt: "2026-07-15T18:00:00.0000000Z",
isLegacy: false,
},
]);
const { result } = renderHook(() =>
useSlideOverMediaState({
detailForRow: detail,
uploadMediaMutation: idleMutation(),
deleteMediaMutation: idleMutation(),
categorizeMediaMutation: idleMutation(),
}),
);
expect(result.current.completionMedia.map((item) => item.purpose)).toEqual([
"Before",
"After",
"Completion",
]);
expect(
result.current.completionMedia.every((item) =>
["Photo", "Video", "Report", "Other"].includes(item.category),
),
).toBe(true);
expect(result.current.extrasUploads).toHaveLength(1);
expect(result.current.extrasUploads[0]?.purpose).toBe("Extra");
});
it("includes Aveta-categorized extra documents in extrasUploads", () => {
const detail = detailWithMedia([
{
id: "4",
category: "Extra",
url: "https://cdn.example.com/extra.pdf",
fileName: "extra.pdf",
uploadedAt: "2026-07-15T18:00:00.0000000Z",
isLegacy: false,
},
{
id: "5",
category: "Aveta",
url: "https://cdn.example.com/aveta.pdf",
fileName: "aveta.pdf",
uploadedAt: "2026-07-15T18:00:00.0000000Z",
isLegacy: false,
},
]);
const { result } = renderHook(() =>
useSlideOverMediaState({
detailForRow: detail,
uploadMediaMutation: idleMutation(),
deleteMediaMutation: idleMutation(),
categorizeMediaMutation: idleMutation(),
}),
);
expect(result.current.extrasUploads).toHaveLength(2);
expect(result.current.extrasUploads.map((item) => item.purpose)).toEqual(["Extra", "Aveta"]);
expect(result.current.extrasUploads[1]?.category).toBe("Aveta");
});
});