test(orders): review modal cascade coverage

Two new tests for the customer -> company/rep cascade:

1. Updates Company and Rep labels when the customer changes
   - renders with customer A (company 'Atlas Corp', rep 'Riya Patel')
   - clicks the customer-search mock (now picks the next non-selected
     customer from the list)
   - asserts the labels flip to B's values and A's are gone

2. Marks the modal dirty after a customer change cascades
   - asserts the Save button is disabled at baseline
   - after customer change, asserts it's enabled (proves the dirty
     check picks up the cascaded company/rep divergence)

Also updates the CustomerSearch mock to compute the next non-selected
customer id from the list (via data-next-id) so cascade tests can
drive it without hardcoding 'cust-new'.

Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
SJCoetz 2026-07-31 15:31:07 +02:00
parent f99ab7cf1a
commit 5af04e4b60

View file

@ -5,19 +5,30 @@ vi.mock("@/components/ui/customer-search", () => ({
CustomerSearch: ({
onValueChange,
value,
customers,
}: {
onValueChange: (v: string) => void;
value: string;
customers: unknown[];
}) => (
<button
type="button"
data-testid="customer-search-mock"
onClick={() => onValueChange("cust-new")}
>
{value || "(unset)"}
</button>
),
}) => {
// Surface the first non-selected customer's id as a data attribute
// so cascade tests can click it specifically. Falls back to
// "cust-new" when there's no other customer in the list.
const others = (customers as Array<{ id: string }>).filter(
(c) => c.id !== value,
);
const nextId = others[0]?.id ?? "cust-new";
return (
<button
type="button"
data-testid="customer-search-mock"
data-next-id={nextId}
onClick={() => onValueChange(nextId)}
>
{value || "(unset)"}
</button>
);
},
}));
vi.mock("sonner", () => ({
@ -688,4 +699,73 @@ describe("OrdersReviewModal", () => {
expect(rekeyedRow?.getAttribute("data-pending-removal")).toBe("false");
});
});
describe("customer cascade (company + rep)", () => {
const expandedCustomerA: Customer = {
...baseCustomer,
id: "cust-A",
customer: "Alice Anderson",
company: "comp-A",
expand: {
company: { ...baseCompany, id: "comp-A", company: "Atlas Corp" },
rep: { id: "user-1", name: "Riya Patel", email: "riya@atlas.test" },
},
};
const expandedCustomerB: Customer = {
...baseCustomer,
id: "cust-B",
customer: "Bob Brown",
company: "comp-B",
expand: {
company: { ...baseCompany, id: "comp-B", company: "Beacon Ltd" },
rep: { id: "user-2", name: "Sam Jones", email: "sam@beacon.test" },
},
};
it("updates Company and Rep labels when the customer changes", () => {
const props = {
...baseProps(),
customers: [expandedCustomerA, expandedCustomerB],
customer: expandedCustomerA,
order: { ...baseOrder, customer: "cust-A", company: "comp-A", rep: "Riya Patel" },
};
render(<OrdersReviewModal {...props} />);
// Baseline: Company and Rep show the persisted (A) values.
expect(screen.getByText("Atlas Corp")).toBeInTheDocument();
expect(screen.getByText("Riya Patel")).toBeInTheDocument();
expect(screen.queryByText("Beacon Ltd")).not.toBeInTheDocument();
// Pick customer B. The mock's data-next-id is computed from the
// customer list, so the click will pass cust-B.
fireEvent.click(screen.getByTestId("customer-search-mock"));
// Company and Rep should now reflect customer B's expands.
expect(screen.getByText("Beacon Ltd")).toBeInTheDocument();
expect(screen.getByText("Sam Jones")).toBeInTheDocument();
// The original A values are no longer in the labels.
expect(screen.queryByText("Atlas Corp")).not.toBeInTheDocument();
expect(screen.queryByText("Riya Patel")).not.toBeInTheDocument();
});
it("marks the modal dirty after a customer change cascades", () => {
const props = {
...baseProps(),
customers: [expandedCustomerA, expandedCustomerB],
customer: expandedCustomerA,
order: { ...baseOrder, customer: "cust-A", company: "comp-A", rep: "Riya Patel" },
};
render(<OrdersReviewModal {...props} />);
// Find the Save button by accessible name. The modal's primary
// save action is the only one in the footer.
const saveBefore = screen.getByRole("button", { name: /save/i });
expect(saveBefore).toBeDisabled();
fireEvent.click(screen.getByTestId("customer-search-mock"));
const saveAfter = screen.getByRole("button", { name: /save/i });
expect(saveAfter).not.toBeDisabled();
});
});
});