shoc-frontend-new/src/test/app/(protected)/workorders/status-cell-pending-uplift.test.tsx
Arthur Bassi d9d6334f57 fix(work-orders): lock completed status and legacy detail
Keep Flag, comments, and extra docs writable after completion, and hide the completed status menu.
2026-08-24 12:06:42 -03:00

325 lines
9.5 KiB
TypeScript

import { fireEvent, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { StatusCell } from "@/app/(protected)/workorders/_components/list/table/cells/status-cell";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
import { renderWithProviders } from "@/test/test-utils";
function makeRow(overrides: Partial<WorkOrderTableRow> = {}): WorkOrderTableRow {
return {
id: 1,
woNumber: "1001",
site: "BK5",
type: "PM",
severity: null,
dispatcherId: "u1",
dispatcherName: "Alex",
scheduledOn: "2026-07-15",
completedDate: "2026-07-20",
targetWeek: "2026-07-15",
dayGroup: "07/15",
dayLabel: "Tue",
location: "Lobby",
locationId: "loc-1",
pm: "HVAC",
serviceNotes: "",
extraServices: [],
vendorId: "7",
company: "Acme",
tech: "Sam",
techPhone: "",
apptStart: "",
apptEnd: "",
apptTime: "",
status: "In Progress",
docStatus: "Yes",
pocName: "",
pocPhone: "",
pocNotes: "",
dueDate: "",
rescheduleCount: 0,
carriedOver: 0,
originalWeek: "",
originalDate: "",
isPastDue: false,
scheduleWeekOnly: false,
isAddOn: false,
mediaCount: 1,
title: "",
priority: "",
primaryDispatchId: null,
rowVersion: "",
dispatchRowVersion: "",
flagColor: null,
additionalContacts: [],
...overrides,
};
}
describe("StatusCell pending uplift closability", () => {
it("disables Completed with tooltip when uplift is pending", () => {
const onChangeStatus = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({ hasPendingUplift: true })}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
const completed = screen.getByRole("button", { name: /completed/i });
expect(completed).toBeDisabled();
expect(completed).toHaveAttribute(
"title",
"This work order has an uplift pending approval and cannot be completed.",
);
fireEvent.click(completed);
expect(onChangeStatus).not.toHaveBeenCalled();
});
it("disables Completed with tooltip when board pendingUpliftCount maps to pending", () => {
const onChangeStatus = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({
hasPendingUplift: true,
upliftSummary: { hasUplift: true, pendingCount: 1 },
})}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
const completed = screen.getByRole("button", { name: /completed/i });
expect(completed).toBeDisabled();
expect(completed).toHaveAttribute(
"title",
"This work order has an uplift pending approval and cannot be completed.",
);
});
it("does not patch Completed when confirmation callback is omitted", () => {
const onChangeStatus = vi.fn();
renderWithProviders(
<StatusCell wo={makeRow()} onChangeStatus={onChangeStatus} onOpenSlideOver={vi.fn()} />,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
fireEvent.click(screen.getByRole("button", { name: /completed/i }));
expect(onChangeStatus).not.toHaveBeenCalled();
});
it("allows Completed when no pending uplift", () => {
const onChangeStatus = vi.fn();
const onRequestComplete = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow()}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
onRequestComplete={onRequestComplete}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
fireEvent.click(screen.getByRole("button", { name: /completed/i }));
expect(onRequestComplete).toHaveBeenCalled();
expect(onChangeStatus).not.toHaveBeenCalled();
});
it("disables Completed when company is missing", () => {
const onChangeStatus = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({ company: "", vendorId: "" })}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
const completed = screen.getByRole("button", { name: /completed/i });
expect(completed).toBeDisabled();
expect(completed).toHaveAttribute("title", "Missing: Company");
fireEvent.click(completed);
expect(onChangeStatus).not.toHaveBeenCalled();
});
it("allows Completed when vendorId is set even if company label is empty", () => {
const onChangeStatus = vi.fn();
const onRequestComplete = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({ company: "", vendorId: "7", tech: "" })}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
onRequestComplete={onRequestComplete}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
fireEvent.click(screen.getByRole("button", { name: /completed/i }));
expect(onRequestComplete).toHaveBeenCalled();
expect(onChangeStatus).not.toHaveBeenCalled();
});
it("allows Completed when vendorId has an empty company label and a live dispatch status", () => {
const onChangeStatus = vi.fn();
const onRequestComplete = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({ company: "", vendorId: "7", tech: "", primaryDispatchStatus: "Sent" })}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
onRequestComplete={onRequestComplete}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
fireEvent.click(screen.getByRole("button", { name: /completed/i }));
expect(onRequestComplete).toHaveBeenCalled();
expect(onChangeStatus).not.toHaveBeenCalled();
});
it.each(["Cancelled", "Canceled", "Refused"] as const)(
"disables Completed when vendorId is leftover from a %s dispatch",
(primaryDispatchStatus) => {
const onChangeStatus = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({
company: "",
vendorId: "45",
tech: "",
primaryDispatchStatus,
})}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
const completed = screen.getByRole("button", { name: /completed/i });
expect(completed).toBeDisabled();
expect(completed).toHaveAttribute("title", "Missing: Company");
fireEvent.click(completed);
expect(onChangeStatus).not.toHaveBeenCalled();
},
);
it("disables Completed when the board omits vendorId after a Refused primary", () => {
const onChangeStatus = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({
company: "",
vendorId: "",
tech: "",
primaryDispatchStatus: "Refused",
})}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
const completed = screen.getByRole("button", { name: /completed/i });
expect(completed).toBeDisabled();
expect(completed).toHaveAttribute("title", "Missing: Company");
});
it("allows Completed after a vendor patch clears leftover refused status", () => {
const onChangeStatus = vi.fn();
const onRequestComplete = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({
company: "New Co",
vendorId: "9",
tech: "Pat",
primaryDispatchStatus: "",
})}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
onRequestComplete={onRequestComplete}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
fireEvent.click(screen.getByRole("button", { name: /completed/i }));
expect(onRequestComplete).toHaveBeenCalled();
expect(onChangeStatus).not.toHaveBeenCalled();
});
it("does not open the status menu when readOnly", () => {
const onChangeStatus = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({ status: "Completed" })}
readOnly
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByLabelText("Status is locked because this work order is completed"));
expect(screen.queryByRole("button", { name: /scheduled/i })).not.toBeInTheDocument();
expect(onChangeStatus).not.toHaveBeenCalled();
});
it("allows Completed when technician is empty if company is set", () => {
const onChangeStatus = vi.fn();
const onRequestComplete = vi.fn();
renderWithProviders(
<StatusCell
wo={makeRow({ tech: "" })}
onChangeStatus={onChangeStatus}
onOpenSlideOver={vi.fn()}
onRequestComplete={onRequestComplete}
/>,
{ withAuth: false },
);
fireEvent.click(screen.getByRole("button", { name: /in progress/i }));
fireEvent.click(screen.getByRole("button", { name: /completed/i }));
expect(onRequestComplete).toHaveBeenCalled();
expect(onChangeStatus).not.toHaveBeenCalled();
});
});