import { act, fireEvent, render, screen } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import AboutModal from "../../components/AboutModal"; // Mock App module for constants vi.mock("../../App", () => ({ FRONTEND_VERSION: "1.0.0", GITHUB_URL: "https://github.com/test/repo", })); describe("AboutModal", () => { const defaultProps = { isOpen: true, onClose: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); }); it("returns null when not open", () => { const { container } = render(); expect(container.firstChild).toBeNull(); }); it("renders when open", () => { render(); expect(screen.getByText(/about\.appName/i)).toBeInTheDocument(); }); it("displays version number", () => { render(); expect(screen.getByText(/1\.0\.0/)).toBeInTheDocument(); }); it("calls onClose when close button is clicked", () => { render(); fireEvent.click(screen.getByText("×")); expect(defaultProps.onClose).toHaveBeenCalled(); }); it("calls onClose when overlay is clicked", () => { const { container } = render(); const overlay = container.querySelector(".modal-overlay"); fireEvent.click(overlay!); expect(defaultProps.onClose).toHaveBeenCalled(); }); it("does not call onClose when modal content is clicked", () => { const { container } = render(); const content = container.querySelector(".about-modal"); if (content) { fireEvent.click(content); expect(defaultProps.onClose).not.toHaveBeenCalled(); } }); it("renders GitHub link", () => { render(); const links = screen.getAllByRole("link"); expect(links.length).toBeGreaterThan(0); }); it("renders version as link to GitHub release", () => { render(); const versionLink = screen.getByText("1.0.0").closest("a"); expect(versionLink).toHaveAttribute("href", "https://github.com/test/repo/releases/tag/v1.0.0"); expect(versionLink).toHaveAttribute("target", "_blank"); }); it("shows up-to-date result after successful version check", async () => { vi.useFakeTimers(); (global.fetch as ReturnType).mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ tag_name: "v1.0.0" }), }); render(); await act(async () => { fireEvent.click(screen.getByRole("button", { name: /about\.checkForUpdates/i })); await vi.advanceTimersByTimeAsync(1000); }); expect(screen.getByText(/about\.upToDate/i)).toBeInTheDocument(); vi.useRealTimers(); }); it("shows update available result with download link", async () => { vi.useFakeTimers(); (global.fetch as ReturnType).mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ tag_name: "v1.2.0" }), }); render(); await act(async () => { fireEvent.click(screen.getByRole("button", { name: /about\.checkForUpdates/i })); await vi.advanceTimersByTimeAsync(1000); }); expect(screen.getByText(/about\.updateAvailable/i)).toBeInTheDocument(); const downloadLink = screen.getByRole("link", { name: /about\.downloadUpdate/i }); expect(downloadLink).toHaveAttribute("href", "https://github.com/test/repo/releases/latest"); vi.useRealTimers(); }); it("shows error result when update check fails", async () => { vi.useFakeTimers(); (global.fetch as ReturnType).mockResolvedValueOnce({ ok: false, json: () => Promise.resolve({}), }); render(); await act(async () => { fireEvent.click(screen.getByRole("button", { name: /about\.checkForUpdates/i })); await vi.advanceTimersByTimeAsync(1000); }); expect(screen.getByText(/about\.checkFailed/i)).toBeInTheDocument(); vi.useRealTimers(); }); });