shoc-frontend-new/src/test/app/(protected)/workorders/slide-over-completion-service-gate.test.tsx
2026-09-23 04:31:53 -03:00

117 lines
3.9 KiB
TypeScript

import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { toast } from "react-toastify";
import { SlideOverCompletionTab } from "@/app/(protected)/workorders/_components/detail/tabs/slide-over-completion-tab";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
vi.mock("react-toastify", () => ({
toast: { error: vi.fn(), success: vi.fn() },
}));
function renderTab(pm: string, onOpenCompletionDoc = vi.fn()) {
const row = { id: "1", type: "PM", pm, docStatus: "No", rowVersion: "1" } as WorkOrderTableRow;
render(
<SlideOverCompletionTab
row={row}
isReadOnly={false}
media={[]}
onOpenCompletionDoc={onOpenCompletionDoc}
/>,
);
return onOpenCompletionDoc;
}
describe("SlideOverCompletionTab service gate", () => {
it("disables the completion document button until a service is selected", () => {
const onOpen = renderTab(" ");
const button = screen.getByRole("button", { name: /select service/i });
expect(button).toBeDisabled();
expect(
screen.getByText("Select a service before opening the completion document."),
).toBeInTheDocument();
expect(
screen.queryByRole("button", { name: /open completion document/i }),
).not.toBeInTheDocument();
fireEvent.click(button);
expect(onOpen).not.toHaveBeenCalled();
});
it("opens the completion document when a service is selected", () => {
const onOpen = renderTab("HVAC Inspection");
const button = screen.getByRole("button", { name: /open completion document/i });
expect(button).toBeEnabled();
expect(screen.queryByText(/select service/i)).not.toBeInTheDocument();
fireEvent.click(button);
expect(onOpen).toHaveBeenCalledTimes(1);
});
it("renders disabled Emergency media upload with the policy failure message", () => {
const onUpload = vi.fn();
const row = {
id: "1",
type: "Emergency",
docStatus: "No",
rowVersion: "1",
} as WorkOrderTableRow;
render(
<SlideOverCompletionTab
row={row}
isReadOnly={false}
media={[]}
uploadDisabled
uploadUnavailableMessage="Upload permissions could not be loaded. Refresh and try again."
onUploadMedia={onUpload}
onOpenCompletionDoc={vi.fn()}
/>,
);
expect(screen.getByRole("status")).toHaveTextContent(
"Upload permissions could not be loaded. Refresh and try again.",
);
expect(document.querySelector('input[type="file"]')).toBeDisabled();
expect(
screen.getByRole("button", { name: /drag files here or click to browse/i }),
).toBeDisabled();
expect(onUpload).not.toHaveBeenCalled();
});
it("shows per-kind Emergency limits before starting an oversized photo upload", () => {
const onUpload = vi.fn();
const row = {
id: "1",
type: "Emergency",
docStatus: "No",
rowVersion: "1",
} as WorkOrderTableRow;
render(
<SlideOverCompletionTab
row={row}
isReadOnly={false}
media={[]}
typeAllowed={() => true}
fileSizeError={(file) =>
file.size > 10_000_000 ? `"${file.name}" exceeds the photo limit (10 MB).` : undefined
}
uploadHint="Photos up to 10 MB · Videos up to 100 MB and 90 seconds"
onUploadMedia={onUpload}
onOpenCompletionDoc={vi.fn()}
/>,
);
expect(
screen.getByText("Photos up to 10 MB · Videos up to 100 MB and 90 seconds"),
).toBeInTheDocument();
fireEvent.change(document.querySelector('input[type="file"]') as HTMLInputElement, {
target: {
files: [new File([new Uint8Array(10_000_001)], "photo.jpg", { type: "image/jpeg" })],
},
});
expect(toast.error).toHaveBeenCalledWith('"photo.jpg" exceeds the photo limit (10 MB).');
expect(onUpload).not.toHaveBeenCalled();
});
});