// @vitest-environment jsdom import { act } from "react"; import { createRoot } from "react-dom/client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { SidebarCompanyMenu } from "./SidebarCompanyMenu"; const mockAuthApi = vi.hoisted(() => ({ getSession: vi.fn(), signInEmail: vi.fn(), signUpEmail: vi.fn(), getProfile: vi.fn(), updateProfile: vi.fn(), signOut: vi.fn(), })); const mockSetSidebarOpen = vi.hoisted(() => vi.fn()); vi.mock("@/api/auth", () => ({ authApi: mockAuthApi, })); vi.mock("@/lib/router", () => ({ Link: ({ children, to, ...props }: { children: React.ReactNode; to: string }) => ( {children} ), })); vi.mock("@/context/CompanyContext", () => ({ useCompany: () => ({ selectedCompany: { id: "company-1", name: "Acme Labs", brandColor: "#3366ff", }, }), })); vi.mock("../context/SidebarContext", () => ({ useSidebar: () => ({ isMobile: false, setSidebarOpen: mockSetSidebarOpen, }), })); // eslint-disable-next-line @typescript-eslint/no-explicit-any (globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; async function flushReact() { await act(async () => { await Promise.resolve(); await new Promise((resolve) => window.setTimeout(resolve, 0)); }); } describe("SidebarCompanyMenu", () => { let container: HTMLDivElement; beforeEach(() => { container = document.createElement("div"); document.body.appendChild(container); mockAuthApi.getSession.mockResolvedValue({ session: { id: "session-1", userId: "user-1" }, user: { id: "user-1", name: "Jane Example", email: "jane@example.com", }, }); mockAuthApi.signOut.mockResolvedValue(undefined); }); afterEach(() => { container.remove(); document.body.innerHTML = ""; vi.clearAllMocks(); }); it("shows the requested company actions and signs out through the dropdown", async () => { const root = createRoot(container); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }); await act(async () => { root.render( , ); }); await flushReact(); await flushReact(); expect(container.textContent).toContain("Acme Labs"); const trigger = container.querySelector('button[aria-label="Open Acme Labs menu"]'); expect(trigger).not.toBeNull(); await act(async () => { trigger?.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, button: 0 })); trigger?.dispatchEvent(new MouseEvent("click", { bubbles: true })); }); await flushReact(); expect(document.body.textContent).toContain("Invite people to Acme Labs"); expect(document.body.textContent).toContain("Company settings"); expect(document.body.textContent).toContain("Sign out"); const signOutButton = Array.from(document.body.querySelectorAll('[data-slot="dropdown-menu-item"]')) .find((element) => element.textContent?.includes("Sign out")); expect(signOutButton).toBeTruthy(); await act(async () => { signOutButton?.dispatchEvent(new MouseEvent("click", { bubbles: true })); }); await flushReact(); expect(mockAuthApi.signOut).toHaveBeenCalledTimes(1); await act(async () => { root.unmount(); }); }); });