shoc-frontend-new/src/test/app/(protected)/workorders/slide-over-extras-aveta.test.tsx
Codex Review Integration 8774b2e0a6 fix(work-orders): render PM extra media in the gallery (SH-371)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:23:24 -03:00

200 lines
6.2 KiB
TypeScript

import { fireEvent, screen } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import { toast } from "react-toastify";
import { SlideOverExtrasTab } from "@/app/(protected)/workorders/_components/detail/tabs/slide-over-extras-tab";
import { workOrdersApi } from "@/domain/work-orders/api/work-orders-api";
import type { MediaFile } from "@/domain/work-orders/types/work-order-media";
import { renderWithProviders } from "@/test/test-utils";
const photo: MediaFile = {
id: "m1",
name: "safety-form.pdf",
fileType: "pdf",
url: "blob:1",
category: "Report",
};
const avetaDoc: MediaFile = {
id: "m2",
name: "aveta-clearance.pdf",
fileType: "pdf",
url: "blob:2",
category: "Aveta",
};
describe("SlideOverExtrasTab Aveta", () => {
afterEach(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
});
it("does not label the first extra document as Aveta when none is explicitly Aveta", () => {
renderWithProviders(
<SlideOverExtrasTab
uploads={[photo]}
avetaRequired
isReadOnly
onUpload={vi.fn()}
onRemove={vi.fn()}
/>,
);
expect(screen.getByText("safety-form.pdf")).toBeInTheDocument();
expect(screen.getAllByText("Aveta")).toHaveLength(1);
});
it("labels only an explicitly Aveta-categorized extra document", () => {
renderWithProviders(
<SlideOverExtrasTab
uploads={[photo, avetaDoc]}
avetaRequired
isReadOnly
onUpload={vi.fn()}
onRemove={vi.fn()}
/>,
);
expect(screen.getByText("safety-form.pdf")).toBeInTheDocument();
expect(screen.getByText("aveta-clearance.pdf")).toBeInTheDocument();
expect(screen.getAllByText("Aveta").length).toBeGreaterThanOrEqual(2);
});
it("categorizes an Extra file as Aveta without auto-labeling the first upload", () => {
const onCategorize = vi.fn();
renderWithProviders(
<SlideOverExtrasTab
uploads={[photo]}
avetaRequired
isReadOnly={false}
onUpload={vi.fn()}
onRemove={vi.fn()}
onCategorize={onCategorize}
/>,
);
fireEvent.change(screen.getByLabelText("Category for safety-form.pdf"), {
target: { value: "Aveta" },
});
expect(onCategorize).toHaveBeenCalledWith("m1", "Aveta");
expect(screen.queryByText("safety-form.pdf")).toBeInTheDocument();
});
it("opens Extra Docs through authenticated content instead of a static href", async () => {
const blob = new Blob(["pdf"], { type: "application/pdf" });
const getMediaContent = vi.spyOn(workOrdersApi, "getMediaContent").mockResolvedValue(blob);
const createObjectURL = vi.fn(() => "blob:authorized");
vi.stubGlobal("URL", { ...URL, createObjectURL, revokeObjectURL: vi.fn() });
const tab = {
opener: window,
location: { href: "about:blank" },
close: vi.fn(),
};
const open = vi.fn(() => tab);
vi.stubGlobal("open", open);
renderWithProviders(
<SlideOverExtrasTab
uploads={[{ ...photo, url: "https://cdn.example.com/Assets/Documents/secret.pdf" }]}
workOrderId={10}
avetaRequired
isReadOnly
onUpload={vi.fn()}
onRemove={vi.fn()}
/>,
);
expect(screen.queryByRole("link")).not.toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "safety-form.pdf" }));
await vi.waitFor(() => {
expect(getMediaContent).toHaveBeenCalledWith(10, "m1");
});
expect(createObjectURL).toHaveBeenCalledWith(blob);
expect(open).toHaveBeenCalledWith("about:blank", "_blank");
expect(tab.opener).toBeNull();
expect(tab.location.href).toBe("blob:authorized");
});
it("shows an error when the browser blocks the document tab", async () => {
const getMediaContent = vi.spyOn(workOrdersApi, "getMediaContent");
const toastError = vi.spyOn(toast, "error").mockImplementation(vi.fn());
vi.stubGlobal(
"open",
vi.fn(() => null),
);
renderWithProviders(
<SlideOverExtrasTab
uploads={[photo]}
workOrderId={10}
isReadOnly
onUpload={vi.fn()}
onRemove={vi.fn()}
/>,
);
fireEvent.click(screen.getByRole("button", { name: "safety-form.pdf" }));
expect(toastError).toHaveBeenCalledWith(
"Unable to open this document. Please allow pop-ups and try again.",
);
expect(getMediaContent).not.toHaveBeenCalled();
});
it("shows Extra Docs accept copy with PDF DOC and 50MB", () => {
renderWithProviders(
<SlideOverExtrasTab uploads={[]} isReadOnly={false} onUpload={vi.fn()} onRemove={vi.fn()} />,
);
expect(
screen.getByText("Accepted: JPG, PNG, MP4, MOV, PDF, DOC · Max 50MB per file"),
).toBeInTheDocument();
const input = document.querySelector('input[type="file"]');
expect(input?.getAttribute("accept")).toContain(".pdf");
expect(input?.getAttribute("accept")).toContain(".doc");
expect(input?.getAttribute("accept")).toContain(".docx");
});
it("disables document opening until the work order id is available", () => {
renderWithProviders(
<SlideOverExtrasTab uploads={[photo]} isReadOnly onUpload={vi.fn()} onRemove={vi.fn()} />,
);
expect(screen.getByRole("button", { name: "safety-form.pdf" })).toBeDisabled();
});
it("labels each extra item with its type and category", () => {
const sitePhoto: MediaFile = {
id: "m3",
name: "site.jpg",
fileType: "image",
url: "blob:3",
category: "Photo",
purpose: "Extra",
};
const walkthrough: MediaFile = {
id: "m4",
name: "walkthrough.mp4",
fileType: "video",
url: "blob:4",
category: "Video",
purpose: "Extra",
};
renderWithProviders(
<SlideOverExtrasTab
uploads={[sitePhoto, walkthrough, avetaDoc]}
isReadOnly
onUpload={vi.fn()}
onRemove={vi.fn()}
/>,
);
expect(screen.getByRole("group", { name: "Photo, Extra: site.jpg" })).toBeInTheDocument();
expect(
screen.getByRole("group", { name: "Video, Extra: walkthrough.mp4" }),
).toBeInTheDocument();
expect(
screen.getByRole("group", { name: "PDF, Aveta: aveta-clearance.pdf" }),
).toBeInTheDocument();
});
});