shoc-frontend-new/src/test/domain/uplifts/api/uplifts-api.test.ts
Codex Review Integration 3c84d851c0 feat(uplifts): align uplift detail modal with SH-209
Two sections, Work order and Uplift request, divided by a single rule.
Work order shows Service, Vendor / Technician, Assigned Dispatcher and
Scheduled from the queue item, so it no longer fetches the work order
and no longer degrades to Unavailable for account-scoped staff. Uplift
request shows Requested By, Requested At, the justification in a
bordered block, the approved-on-WO breakdown and a horizontal
attachment row whose chips open the evidence in a new tab. Every field
renders data or an explicit placeholder. The footer shows Reject and
Approve for pending uplifts, Revoke for approved ones and nothing for
read-only records; closing is the header X.
2026-09-18 12:53:55 -03:00

94 lines
3 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const apiGet = vi.fn();
const apiPost = vi.fn();
const apiRequestRaw = vi.fn();
vi.mock("@/api/api", () => ({
apiGet: (...args: unknown[]) => apiGet(...args),
apiPost: (...args: unknown[]) => apiPost(...args),
apiRequestRaw: (...args: unknown[]) => apiRequestRaw(...args),
}));
import { upliftsApi } from "@/domain/uplifts/api/uplifts-api";
describe("upliftsApi", () => {
beforeEach(() => {
apiGet.mockReset();
apiPost.mockReset();
apiRequestRaw.mockReset();
});
it("posts admin revoke decisions to the uplift decision endpoint", async () => {
apiPost.mockResolvedValueOnce(undefined);
await upliftsApi.revoke(42, "Scope was already covered");
expect(apiPost).toHaveBeenCalledWith("uplifts/42/revoke", {
note: "Scope was already covered",
});
});
it("reads the backend tier decision permission", async () => {
apiGet.mockResolvedValueOnce({ status: "Success", data: { canApprove: true } });
await expect(upliftsApi.canApprove(1)).resolves.toBe(true);
expect(apiGet).toHaveBeenCalledWith("uplifts/can-approve", { searchParams: { tier: 1 } });
});
it("treats a missing tier permission as false", async () => {
apiGet.mockResolvedValueOnce({ status: "Success", data: {} });
await expect(upliftsApi.canApprove(2)).resolves.toBe(false);
});
describe("openEvidence", () => {
function evidenceResponse(body: string, contentType: string): Response {
return new Response(body, {
headers: {
"Content-Type": contentType,
"Content-Disposition": 'attachment; filename="quote.pdf"',
},
});
}
function fakeTab() {
return { location: { href: "about:blank" }, close: vi.fn() };
}
beforeEach(() => {
URL.createObjectURL = vi.fn(() => "blob:evidence");
URL.revokeObjectURL = vi.fn();
});
it("renders an inert evidence type in the tab opened by the click", async () => {
apiRequestRaw.mockResolvedValueOnce(evidenceResponse("%PDF", "application/pdf"));
const tab = fakeTab();
await upliftsApi.openEvidence(7, tab as unknown as Window);
expect(apiRequestRaw).toHaveBeenCalledWith(
"get",
"uplifts/7/evidence",
undefined,
"upliftsApi.openEvidence",
);
expect(tab.location.href).toBe("blob:evidence");
expect(tab.close).not.toHaveBeenCalled();
});
it("downloads a type the browser could execute instead of rendering it on the app origin", async () => {
apiRequestRaw.mockResolvedValueOnce(evidenceResponse("<svg/>", "image/svg+xml"));
const tab = fakeTab();
const click = vi.spyOn(HTMLAnchorElement.prototype, "click").mockImplementation(() => {});
await upliftsApi.openEvidence(8, tab as unknown as Window);
expect(tab.location.href).toBe("about:blank");
expect(tab.close).toHaveBeenCalled();
expect(click).toHaveBeenCalled();
click.mockRestore();
});
});
});