shoc-frontend-new/src/test/app/(protected)/uplifts/uplift-queue-decision-flow.test.tsx
Alexandre Brandizzi 28e30f8edb fix(uplifts): show the requested increase as the one uplift amount
The queue Amount column, the detail modal and the reject/revoke dialogs
showed requestedNTE (the resulting NTE total) while the decision toasts
showed delta (the increase), so a work order with an existing NTE named
two different figures for one request. Route every surface through one
upliftAmount helper that returns the increase, matching the prototype's
single uplift amount, and show it on both Approve buttons.
2026-09-25 01:49:24 -03:00

166 lines
5.9 KiB
TypeScript

import { fireEvent, screen } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { UpliftQueueItem, UpliftsQueueResult } from "@/domain/uplifts/types/uplift";
import { renderWithProviders } from "@/test/test-utils";
const rejectMutate = vi.fn();
const approveMutate = vi.fn();
const revokeMutate = vi.fn();
const refetch = vi.fn();
const queueState = vi.hoisted(() => ({
data: null as UpliftsQueueResult | null,
}));
const canApproveState = vi.hoisted(() => ({ data: true as boolean | undefined }));
const pendingItem: UpliftQueueItem = {
id: 41,
status: "Pending",
currentNTE: 100,
requestedNTE: 250,
delta: 150,
vendorReason: "Extra parts",
requestedAt: "2026-01-15T10:00:00Z",
requestedByVendorName: "Gateway",
decidedAt: "",
decidedByName: "",
decisionNote: "",
requiredTier: 1,
canDecide: true,
expiresAt: "",
notificationStatus: "",
notificationError: "",
evidenceDocumentId: null,
evidenceFileName: "",
evidenceContentType: "",
evidenceSizeBytes: null,
dispatchNumber: "DSP-41",
poNumber: "PO-41",
vendorCompanyName: "Gateway Plumbing",
workOrderId: 99,
dispatchId: 7,
woNumber: "WO-99",
site: "Site A",
serviceName: "Plumbing repair",
technicianName: "",
workOrderDispatcherName: "",
workOrderScheduledDate: "",
attachmentCount: null,
approvedOnWoAuto: null,
approvedOnWoAdmin: null,
approvedOnWoTotal: 100,
workOrderClosed: false,
};
vi.mock("@/domain/uplifts/use-cases/use-uplifts-queue", () => ({
useUpliftsQueue: () => ({
data: queueState.data,
isLoading: false,
isFetching: false,
error: null,
refetch,
}),
}));
vi.mock("@/domain/uplifts/use-cases/use-uplift-actions", () => ({
useApproveUplift: () => ({ isPending: false, mutate: approveMutate }),
useRejectUplift: () => ({ isPending: false, mutate: rejectMutate }),
useRevokeUplift: () => ({ isPending: false, mutate: revokeMutate }),
}));
vi.mock("@/providers/auth-context", async (importOriginal) => ({
...(await importOriginal<object>()),
useAuthContext: () => ({ user: { userRoles: "Admin" } }),
}));
vi.mock("@/domain/uplifts/use-cases/use-uplifts-can-approve", () => ({
useUpliftsCanApprove: () => ({ data: canApproveState.data }),
}));
describe("Uplift Approvals decision flow", () => {
beforeEach(() => {
rejectMutate.mockReset();
approveMutate.mockReset();
revokeMutate.mockReset();
refetch.mockReset();
canApproveState.data = true;
queueState.data = {
items: [pendingItem],
totalCount: 1,
page: 1,
pageSize: 25,
pendingExposureTotal: 250,
};
});
it("shows the Uplift Approvals heading, count pill and exposure total", async () => {
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
renderWithProviders(<UpliftQueuePage />);
expect(screen.getByRole("heading", { name: "Uplift Approvals" })).toBeInTheDocument();
expect(screen.getByLabelText("1 pending uplifts")).toBeInTheDocument();
expect(screen.getByText("Pending exposure: $250.00")).toBeInTheDocument();
});
it("approves in one click without a confirmation dialog", async () => {
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
renderWithProviders(<UpliftQueuePage />);
fireEvent.click(screen.getByRole("button", { name: "Approve $150.00" }));
expect(approveMutate).toHaveBeenCalledWith({ id: 41, amount: 150, woNumber: "WO-99" });
expect(screen.queryByRole("button", { name: "Confirm" })).not.toBeInTheDocument();
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
});
it("opens RejectDialog with the dispatcher copy and does not reject on Cancel", async () => {
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
renderWithProviders(<UpliftQueuePage />);
fireEvent.click(screen.getByRole("button", { name: "Reject" }));
expect(screen.getByRole("heading", { name: "Reject uplift of $150.00?" })).toBeInTheDocument();
expect(screen.getByText("The dispatcher sees this reason on WO #WO-99.")).toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "Cancel" }));
expect(rejectMutate).not.toHaveBeenCalled();
});
it("shows the pending empty copy when nothing is waiting", async () => {
queueState.data = {
items: [],
totalCount: 0,
page: 1,
pageSize: 25,
pendingExposureTotal: null,
};
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
renderWithProviders(<UpliftQueuePage />);
expect(screen.getByText("No uplifts waiting for approval.")).toBeInTheDocument();
});
it("disables Approve and Reject for a Dispatcher the backend refuses, without dialogs or toasts", async () => {
canApproveState.data = false;
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
renderWithProviders(<UpliftQueuePage />);
const approve = screen.getByRole("button", { name: "Approve $150.00" });
const reject = screen.getByRole("button", { name: "Reject" });
expect(approve).toBeDisabled();
expect(reject).toBeDisabled();
fireEvent.mouseOver(approve);
expect(await screen.findByText("Requires Tier 1 role")).toBeInTheDocument();
fireEvent.click(approve);
fireEvent.click(reject);
expect(approveMutate).not.toHaveBeenCalled();
expect(rejectMutate).not.toHaveBeenCalled();
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
expect(screen.queryByRole("heading", { name: /reject uplift of/i })).not.toBeInTheDocument();
});
it("keeps Approve and Reject enabled when the backend allows the tier", async () => {
const { default: UpliftQueuePage } = await import("@/app/(protected)/uplifts/index");
renderWithProviders(<UpliftQueuePage />);
expect(screen.getByRole("button", { name: "Approve $150.00" })).toBeEnabled();
expect(screen.getByRole("button", { name: "Reject" })).toBeEnabled();
});
});