// frontend/tests/connectors/AddAccountMenu.test.tsx — phase-16 계정 추가(OAuth) 메뉴 import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { AddAccountMenu } from "@/components/connectors/AddAccountMenu"; import { connectorsApi } from "@/lib/connectors/api"; vi.mock("@/lib/connectors/api", () => ({ connectorsApi: { providers: vi.fn(), oauthStart: vi.fn() }, })); const providersMock = vi.mocked(connectorsApi.providers); const oauthStartMock = vi.mocked(connectorsApi.oauthStart); const assignMock = vi.fn(); const originalLocation = window.location; beforeEach(() => { providersMock.mockReset(); oauthStartMock.mockReset(); assignMock.mockReset(); // jsdom location.assign 은 non-configurable → location 객체 자체를 교체 Object.defineProperty(window, "location", { configurable: true, writable: true, value: { ...originalLocation, assign: assignMock }, }); }); afterEach(() => { Object.defineProperty(window, "location", { configurable: true, writable: true, value: originalLocation, }); vi.restoreAllMocks(); }); const PROVIDERS = [ { domain: "mail", provider: "gmail", label: "Gmail", configured: true }, { domain: "mail", provider: "outlook", label: "Outlook", configured: false }, ]; describe("AddAccountMenu", () => { it("provider 가 없으면 아무것도 렌더하지 않는다", async () => { providersMock.mockResolvedValue([]); const { container } = render(); await waitFor(() => expect(providersMock).toHaveBeenCalledWith("mail")); expect(container.textContent).toBe(""); }); it("열면 configured/미구성 provider 를 보여준다", async () => { providersMock.mockResolvedValue(PROVIDERS); render(); const btn = await screen.findByText("계정 추가"); fireEvent.click(btn); expect(screen.getByRole("menuitem", { name: /Gmail/ })).not.toBeDisabled(); expect(screen.getByRole("menuitem", { name: /Outlook/ })).toBeDisabled(); // 미구성 expect(screen.getByText("설정 필요")).toBeInTheDocument(); }); it("configured provider 클릭 시 oauthStart 후 authorize_url 로 이동", async () => { providersMock.mockResolvedValue(PROVIDERS); oauthStartMock.mockResolvedValue({ authorize_url: "https://accounts.google.com/o/oauth2/x" }); render(); fireEvent.click(await screen.findByText("계정 추가")); fireEvent.click(screen.getByRole("menuitem", { name: /Gmail/ })); await waitFor(() => expect(oauthStartMock).toHaveBeenCalledWith("mail", "gmail", "/settings?tab=mail"), ); await waitFor(() => expect(assignMock).toHaveBeenCalledWith("https://accounts.google.com/o/oauth2/x"), ); }); it("oauthStart 실패 시 onError 토스트 호출", async () => { providersMock.mockResolvedValue(PROVIDERS); oauthStartMock.mockRejectedValue(new Error("400")); const onError = vi.fn(); render(); fireEvent.click(await screen.findByText("계정 추가")); fireEvent.click(screen.getByRole("menuitem", { name: /Gmail/ })); await waitFor(() => expect(onError).toHaveBeenCalledWith("Gmail 연결을 시작하지 못했어요")); }); });