import { describe, it, expect, vi, beforeEach } from "vitest"; import { useEffect } from "react"; import userEvent from "@testing-library/user-event"; import { renderWithProviders as render, screen } from "../utils/test-utils"; import "@testing-library/jest-dom/vitest"; import { ConfirmStakeholdersScreen } from "../../app/(app)/create/screens/select/ConfirmStakeholdersScreen"; import { useCreateFlow } from "../../app/(app)/create/context/CreateFlowContext"; import type { CreateFlowState } from "../../app/(app)/create/types"; vi.mock("../../lib/create/api", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, fetchAuthSession: vi.fn(async () => ({ user: { id: "u1", email: "maya@example.org" }, })), }; }); function SeedCreateFlow({ patch }: { patch: Partial }) { const { updateState } = useCreateFlow(); useEffect(() => { updateState(patch); }, [patch, updateState]); return null; } describe("ConfirmStakeholdersScreen", () => { beforeEach(() => { vi.clearAllMocks(); }); it("renders the invite heading and email field", () => { render(); expect( screen.getByRole("heading", { name: "Invite people to read your Rule", }), ).toBeInTheDocument(); expect( screen.getByText("Everyone you add gets a private link to read the Rule."), ).toBeInTheDocument(); expect( screen.getByRole("button", { name: "Add" }), ).toBeInTheDocument(); expect( screen.getByText( /Every Rule starts private\. Only the people you invite can read it/, ), ).toBeInTheDocument(); }); it("does not show the old draft toast", () => { render(); expect( screen.queryByText(/Congratulations! You've drafted your CommunityRule!/i), ).not.toBeInTheDocument(); }); it("adds an email and shows the owner as You", async () => { const user = userEvent.setup(); render(); expect(await screen.findByText("maya@example.org")).toBeInTheDocument(); expect(screen.getByText("You")).toBeInTheDocument(); await user.type( screen.getByRole("textbox", { name: /Add someone by email/i }), "rosa@example.org", ); await user.click(screen.getByRole("button", { name: "Add" })); expect(screen.getByText("rosa@example.org")).toBeInTheDocument(); expect( screen.getByText("2 people get a private link to read the Rule."), ).toBeInTheDocument(); expect( screen.queryByRole("button", { name: /Remove maya@example.org/i }), ).not.toBeInTheDocument(); expect( screen.getByRole("button", { name: /Remove rosa@example.org/i }), ).toBeInTheDocument(); }); it("keeps a pasted invalid address in the field and reports what was added", async () => { const user = userEvent.setup(); render(); const field = await screen.findByRole("textbox", { name: /Add someone by email/i, }); field.focus(); await user.paste("rosa@example.org, jo@example, sam@example.org"); expect(await screen.findByText("rosa@example.org")).toBeInTheDocument(); expect(screen.getByText("sam@example.org")).toBeInTheDocument(); expect(field).toHaveValue("jo@example"); expect( screen.getByText( /Added two people from your list\. One is not an email address\./, ), ).toBeInTheDocument(); expect( screen.getByText("Not an email address. Fix it and select Add, or clear it."), ).toBeInTheDocument(); }); it("shows the membership card from the selected method", async () => { render( <> , ); expect(await screen.findByText("Open admission")).toBeInTheDocument(); expect(screen.getByText("Who belongs, in your Rule’s words")).toBeInTheDocument(); expect( screen.getByText(/Anyone who shares the work belongs/), ).toBeInTheDocument(); }); });