import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { SendInvitationForm } from "./send-invitation-form"; const { pushMock, sendInviteMock } = vi.hoisted(() => ({ pushMock: vi.fn(), sendInviteMock: vi.fn(), })); vi.mock("next/navigation", () => ({ useRouter: () => ({ push: pushMock }), })); vi.mock("@/actions/invitations/invitation", () => ({ sendInvite: sendInviteMock, })); // Radix Select does not open in jsdom; a native select keeps the test on the // form's behaviour rather than the dropdown's. vi.mock("@/components/shadcn/select/select", () => ({ Select: ({ value, onValueChange, disabled, children, }: { value?: string; onValueChange: (value: string) => void; disabled?: boolean; children: React.ReactNode; }) => ( ), SelectTrigger: () => null, SelectValue: () => null, SelectContent: ({ children }: { children: React.ReactNode }) => ( <>{children} ), SelectItem: ({ value, children, }: { value: string; children: React.ReactNode; }) => , })); const ROLES = [{ id: "22222222-2222-4222-8222-222222222222", name: "admin" }]; const fillAndSubmit = async (user: ReturnType) => { await user.type(screen.getByLabelText(/email/i), "teammate@company.com"); await user.selectOptions(screen.getByRole("combobox"), ROLES[0].id); await user.click(screen.getByRole("button", { name: /send invitation/i })); }; describe("SendInvitationForm", () => { beforeEach(() => { pushMock.mockReset(); // The API answers with the created record, token included. sendInviteMock.mockReset().mockResolvedValue({ data: { id: "inv-1", attributes: { email: "teammate@company.com", token: "abc123DEF45678" }, }, }); }); it("navigates to the invitation details by default", async () => { // Given const user = userEvent.setup(); render(); // When await fillAndSubmit(user); // Then await waitFor(() => expect(pushMock).toHaveBeenCalledWith( "/invitations/check-details/?id=inv-1", ), ); const formData = sendInviteMock.mock.calls[0]?.[0] as FormData; expect(formData.get("source")).toBeNull(); }); it("hands the new invitation to onSuccess and tags the source when given", async () => { // Given const user = userEvent.setup(); const onSuccess = vi.fn(); render( , ); // When await fillAndSubmit(user); // Then await waitFor(() => expect(onSuccess).toHaveBeenCalledWith("inv-1")); expect(pushMock).not.toHaveBeenCalled(); const formData = sendInviteMock.mock.calls[0]?.[0] as FormData; expect(formData.get("source")).toBe("provider_connect"); }); });