import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, expect, it, vi } from "vitest"; import { MemoryRouter } from "react-router"; import { SwitchProfileContextMenu } from "#/components/features/chat/switch-profile-context-menu"; import type { LlmProfileSummary } from "#/api/settings-service/profiles-service.api"; // `useTranslation` is mocked globally in vitest.setup.ts to return keys as // labels, so assertions below check for the raw I18n key strings. const PROFILES: LlmProfileSummary[] = [ { name: "default", model: "anthropic/claude-sonnet-4-6", base_url: null, api_key_set: true, }, { name: "gpt-5", model: "openai/gpt-5", base_url: null, api_key_set: true, }, ]; const renderMenu = ( overrides: Partial< React.ComponentProps > = {}, ) => { const profiles = overrides.profiles ?? PROFILES; const activeProfileName = overrides.activeProfileName !== undefined ? overrides.activeProfileName : "default"; const onSelect = overrides.onSelect ?? vi.fn(); const onClose = overrides.onClose ?? vi.fn(); render( , ); return { profiles, activeProfileName, onSelect, onClose }; }; describe("SwitchProfileContextMenu", () => { it("renders the i18n header and one row per profile", () => { renderMenu(); expect( screen.getByText("SETTINGS$AVAILABLE_PROFILES"), ).toBeInTheDocument(); expect( screen.getByTestId("switch-profile-option-default"), ).toBeInTheDocument(); expect( screen.getByTestId("switch-profile-option-gpt-5"), ).toBeInTheDocument(); }); it("shows each profile's provider/model under its name", () => { renderMenu(); expect(screen.getByText("anthropic/claude-sonnet-4-6")).toBeInTheDocument(); expect(screen.getByText("openai/gpt-5")).toBeInTheDocument(); }); it("marks the active profile with aria-current=true and others without", () => { renderMenu({ activeProfileName: "gpt-5" }); expect(screen.getByTestId("switch-profile-option-gpt-5")).toHaveAttribute( "aria-current", "true", ); expect( screen.getByTestId("switch-profile-option-default"), ).not.toHaveAttribute("aria-current"); }); it("calls onSelect with the profile name and then onClose when a row is clicked", async () => { const user = userEvent.setup(); const props = renderMenu(); await user.click(screen.getByTestId("switch-profile-option-gpt-5")); expect(props.onSelect).toHaveBeenCalledWith("gpt-5"); expect(props.onClose).toHaveBeenCalled(); }); it("renders the Settings entry as a Link to /settings (cmd-click friendly)", () => { renderMenu(); const settings = screen.getByTestId("switch-profile-open-settings"); expect(settings.tagName).toBe("A"); expect(settings).toHaveAttribute("href", "/settings"); expect(settings).toHaveTextContent("MODEL$OPEN_SETTINGS"); }); it("calls onClose when clicking the Settings link", async () => { const user = userEvent.setup(); const props = renderMenu(); await user.click(screen.getByTestId("switch-profile-open-settings")); expect(props.onClose).toHaveBeenCalled(); }); it("closes the menu when Escape is pressed", async () => { const user = userEvent.setup(); const props = renderMenu(); await user.keyboard("{Escape}"); expect(props.onClose).toHaveBeenCalled(); }); });