test(collection-confirm): add confirm-invoice-dialog tests

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

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
SJCoetz 2026-08-03 02:32:44 +02:00
parent dbf02e2511
commit c14d07ecc0

View file

@ -0,0 +1,210 @@
import { render, screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, describe, expect, it, vi } from "vitest";
import { ConfirmInvoiceDialog } from "./confirm-invoice-dialog";
const costOverrides = { "row-1": 50 };
function getDialog() {
return screen.getByRole("dialog");
}
function getDateInput(dialog = getDialog()) {
return within(dialog).getByLabelText(/Supplier invoice date/i);
}
function getNumberInput(dialog = getDialog()) {
return within(dialog).getByLabelText(/Supplier invoice number/i);
}
function getSubmitButton(dialog = getDialog()) {
return within(dialog).getByRole("button", { name: /^Confirm(?: \d+ items)?$/i });
}
afterEach(() => {
vi.restoreAllMocks();
});
describe("ConfirmInvoiceDialog", () => {
it("renders the row and cost override summary", () => {
render(
<ConfirmInvoiceDialog
open
onOpenChange={vi.fn()}
onSubmit={vi.fn()}
rowCount={2}
costOverrides={costOverrides}
/>,
);
expect(
within(getDialog()).getByText(/Confirming 2 rows/i),
).toHaveTextContent("Confirming 2 rows · 1 cost override applied");
});
it("calls onSubmit with the invoice details and cost overrides", async () => {
const user = userEvent.setup();
const onSubmit = vi.fn();
render(
<ConfirmInvoiceDialog
open
onOpenChange={vi.fn()}
onSubmit={onSubmit}
defaultValues={{ date: "", number: "" }}
costOverrides={costOverrides}
/>,
);
await user.type(getDateInput(), "2026-08-03");
await user.type(getNumberInput(), "INV-001");
await user.click(getSubmitButton());
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
invoice: { date: "2026-08-03", number: "INV-001" },
costOverrides,
});
});
it("disables submit when the date is empty", async () => {
const user = userEvent.setup();
render(
<ConfirmInvoiceDialog
open
onOpenChange={vi.fn()}
onSubmit={vi.fn()}
defaultValues={{ date: "", number: "" }}
/>,
);
await user.type(getNumberInput(), "INV-001");
expect(getSubmitButton()).toBeDisabled();
});
it("disables submit when the invoice number is empty", async () => {
const user = userEvent.setup();
render(
<ConfirmInvoiceDialog
open
onOpenChange={vi.fn()}
onSubmit={vi.fn()}
defaultValues={{ date: "", number: "" }}
/>,
);
await user.type(getDateInput(), "2026-08-03");
expect(getSubmitButton()).toBeDisabled();
});
it("disables submit when both invoice fields are empty", () => {
render(
<ConfirmInvoiceDialog
open
onOpenChange={vi.fn()}
onSubmit={vi.fn()}
defaultValues={{ date: "", number: "" }}
/>,
);
expect(getSubmitButton()).toBeDisabled();
});
it("trims the invoice number before submitting", async () => {
const user = userEvent.setup();
const onSubmit = vi.fn();
render(
<ConfirmInvoiceDialog
open
onOpenChange={vi.fn()}
onSubmit={onSubmit}
defaultValues={{ date: "2026-08-03", number: "" }}
costOverrides={costOverrides}
/>,
);
await user.type(getNumberInput(), " INV-001 ");
await user.click(getSubmitButton());
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit.mock.calls[0][0].invoice.number).toBe("INV-001");
});
it("uses singular row and plural zero-overrides labels", () => {
render(
<ConfirmInvoiceDialog
open
onOpenChange={vi.fn()}
onSubmit={vi.fn()}
rowCount={1}
costOverrides={{}}
/>,
);
expect(
within(getDialog()).getByText(/Confirming 1 row/i),
).toHaveTextContent("Confirming 1 row · 0 cost overrides applied");
});
it("re-applies updated defaults when reopened", async () => {
const onOpenChange = vi.fn();
const onSubmit = vi.fn();
const { rerender } = render(
<ConfirmInvoiceDialog
open
onOpenChange={onOpenChange}
onSubmit={onSubmit}
defaultValues={{ date: "2026-08-01", number: "INV-OLD" }}
/>,
);
expect(getDateInput()).toHaveValue("2026-08-01");
expect(getNumberInput()).toHaveValue("INV-OLD");
rerender(
<ConfirmInvoiceDialog
open={false}
onOpenChange={onOpenChange}
onSubmit={onSubmit}
defaultValues={{ date: "2026-08-01", number: "INV-OLD" }}
/>,
);
await waitFor(() =>
expect(screen.queryByRole("dialog")).not.toBeInTheDocument(),
);
rerender(
<ConfirmInvoiceDialog
open
onOpenChange={onOpenChange}
onSubmit={onSubmit}
defaultValues={{ date: "2026-08-02", number: "INV-NEW" }}
/>,
);
const reopenedDialog = await screen.findByRole("dialog");
await waitFor(() => {
expect(getDateInput(reopenedDialog)).toHaveValue("2026-08-02");
expect(getNumberInput(reopenedDialog)).toHaveValue("INV-NEW");
});
});
it("closes the dialog when Cancel is clicked", async () => {
const user = userEvent.setup();
const onOpenChange = vi.fn();
render(
<ConfirmInvoiceDialog
open
onOpenChange={onOpenChange}
onSubmit={vi.fn()}
/>,
);
await user.click(within(getDialog()).getByRole("button", { name: /Cancel/i }));
expect(onOpenChange).toHaveBeenCalledWith(false);
});
});