import { beforeEach, expect, it, vi } from "vitest"; import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import App from "./App"; import { getModelInfo, getModels } from "./api"; // Every tab's data dependency is mocked: hidden tabs are pre-rendered by // , so their fetches fire even before the user visits them. vi.mock("./api", () => ({ analyze: vi.fn(), explainText: vi.fn(), analyzeCsv: vi.fn(), getModelInfo: vi.fn(), getModels: vi.fn(), compareModels: vi.fn(), compareAiDetectors: vi.fn(), })); beforeEach(() => { vi.mocked(getModels).mockResolvedValue({ models: [ { id: "twitter-roberta", name: "cardiffnlp/twitter-roberta-base-sentiment-latest", task: "sentiment", labels: ["negative", "neutral", "positive"], domain: "social / short English text", note: "", default: true, loaded: true, }, ], }); vi.mocked(getModelInfo).mockResolvedValue({ name: "cardiffnlp/twitter-roberta-base-sentiment-latest", labels: ["negative", "neutral", "positive"], max_tokens: 512, device: "mps", description: "RoBERTa-base fine-tuned on tweets.", }); }); // Hidden tabs suspend while their promises settle, so React 19 requires the // initial render inside an awaited act(). const renderApp = () => act(async () => render()); it("shows the wordmark and five tabs with Analyze active by default", async () => { await renderApp(); expect(screen.getByText("SentimentScope")).toBeInTheDocument(); const tabs = screen.getAllByRole("tab"); expect(tabs.map((t) => t.textContent)).toEqual([ "Analyze", "Batch", "Compare Sentiment", "AI Detector", "How it works", ]); expect(screen.getByRole("tab", { name: "Analyze" })).toHaveAttribute("aria-selected", "true"); expect(screen.getByPlaceholderText(/type or paste text/i)).toBeVisible(); }); it("switches the visible panel when a tab is clicked", async () => { const user = userEvent.setup(); await renderApp(); await user.click(screen.getByRole("tab", { name: "Compare Sentiment" })); expect(await screen.findByRole("button", { name: "Compare models" })).toBeVisible(); expect(screen.getByPlaceholderText(/type or paste text/i)).not.toBeVisible(); await user.click(screen.getByRole("tab", { name: "How it works" })); expect(await screen.findByRole("heading", { name: /tokenization/i })).toBeVisible(); }); it("preserves in-progress tab state when switching away and back", async () => { const user = userEvent.setup(); await renderApp(); await user.type(screen.getByPlaceholderText(/type or paste text/i), "battery life is incredible"); await user.click(screen.getByRole("tab", { name: "How it works" })); await user.click(screen.getByRole("tab", { name: "Analyze" })); expect(screen.getByPlaceholderText(/type or paste text/i)).toHaveValue("battery life is incredible"); });