// @vitest-environment jsdom import { fireEvent, screen } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { renderWithProviders } from "test-utils/render-with-providers"; const { useSWR } = vi.hoisted(() => ({ useSWR: vi.fn() })); vi.mock("swr", () => ({ default: useSWR })); import Stocks from "./stocks"; describe("components/widgets/stocks", () => { beforeEach(() => { vi.clearAllMocks(); }); it("renders an error widget when the api call fails", () => { useSWR.mockReturnValue({ data: undefined, error: new Error("nope") }); renderWithProviders(, { settings: { target: "_self" } }); expect(screen.getByText("widget.api_error")).toBeInTheDocument(); }); it("renders a loading state while waiting for data", () => { useSWR.mockReturnValue({ data: undefined, error: undefined }); renderWithProviders(, { settings: { target: "_self" } }); expect(screen.getByText(/stocks\.loading/)).toBeInTheDocument(); }); it("toggles between price and percent change on click", () => { useSWR.mockReturnValue({ data: { stocks: [ { ticker: "NASDAQ:AAPL", currentPrice: 123.45, percentChange: 1.23 }, { ticker: "MSFT", currentPrice: 99.99, percentChange: -0.5 }, ], }, error: undefined, }); renderWithProviders(, { settings: { target: "_self" } }); expect(screen.getByText("AAPL")).toBeInTheDocument(); expect(screen.getByText("123.45")).toBeInTheDocument(); fireEvent.click(screen.getByRole("button")); expect(screen.getByText("1.23%")).toBeInTheDocument(); expect(screen.getByText("-0.5%")).toBeInTheDocument(); }); it("shows api_error for null prices and uses colored classes when enabled", () => { useSWR.mockReturnValue({ data: { stocks: [{ ticker: "NASDAQ:AAPL", currentPrice: null, percentChange: -1 }], }, error: undefined, }); renderWithProviders(, { settings: { target: "_self" } }); const apiError = screen.getByText("widget.api_error"); expect(apiError.className).toContain("text-rose"); fireEvent.click(screen.getByRole("button")); const percent = screen.getByText("-1%"); expect(percent.className).toContain("text-rose"); }); });