xtablo-source/apps/main/src/components/InstallBanner.test.tsx
Arthur Belleville 8e41b031aa
feat(pwa): add InstallBanner component with tests
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:51:38 +02:00

128 lines
3.7 KiB
TypeScript

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
// Mock the hook so we can control its return values
const mockPromptInstall = vi.fn();
const mockDismiss = vi.fn();
vi.mock("../hooks/useInstallPrompt", () => ({
useInstallPrompt: vi.fn(() => ({
canInstall: false,
isStandalone: false,
isIOS: false,
isDismissed: false,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
})),
}));
import { useInstallPrompt } from "../hooks/useInstallPrompt";
import { InstallBanner } from "./InstallBanner";
const mockUseInstallPrompt = vi.mocked(useInstallPrompt);
describe("InstallBanner", () => {
beforeEach(() => {
mockPromptInstall.mockClear();
mockDismiss.mockClear();
});
afterEach(() => {
vi.restoreAllMocks();
});
it("renders nothing when canInstall is false and not iOS", () => {
mockUseInstallPrompt.mockReturnValue({
canInstall: false,
isStandalone: false,
isIOS: false,
isDismissed: false,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
});
const { container } = render(<InstallBanner />);
expect(container.firstChild).toBeNull();
});
it("renders nothing when already in standalone mode", () => {
mockUseInstallPrompt.mockReturnValue({
canInstall: true,
isStandalone: true,
isIOS: false,
isDismissed: false,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
});
const { container } = render(<InstallBanner />);
expect(container.firstChild).toBeNull();
});
it("renders nothing when dismissed", () => {
mockUseInstallPrompt.mockReturnValue({
canInstall: true,
isStandalone: false,
isIOS: false,
isDismissed: true,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
});
const { container } = render(<InstallBanner />);
expect(container.firstChild).toBeNull();
});
it("renders install banner when canInstall is true", () => {
mockUseInstallPrompt.mockReturnValue({
canInstall: true,
isStandalone: false,
isIOS: false,
isDismissed: false,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
});
render(<InstallBanner />);
expect(screen.getByText(/install/i)).toBeInTheDocument();
});
it("calls promptInstall when install button is clicked", async () => {
mockUseInstallPrompt.mockReturnValue({
canInstall: true,
isStandalone: false,
isIOS: false,
isDismissed: false,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
});
render(<InstallBanner />);
await userEvent.click(screen.getByRole("button", { name: /install/i }));
expect(mockPromptInstall).toHaveBeenCalledOnce();
});
it("calls dismiss when close button is clicked", async () => {
mockUseInstallPrompt.mockReturnValue({
canInstall: true,
isStandalone: false,
isIOS: false,
isDismissed: false,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
});
render(<InstallBanner />);
await userEvent.click(screen.getByRole("button", { name: /dismiss|close/i }));
expect(mockDismiss).toHaveBeenCalledOnce();
});
it("renders iOS instructions when isIOS is true and not dismissed", () => {
mockUseInstallPrompt.mockReturnValue({
canInstall: false,
isStandalone: false,
isIOS: true,
isDismissed: false,
promptInstall: mockPromptInstall,
dismiss: mockDismiss,
});
render(<InstallBanner />);
expect(screen.getByText(/share/i)).toBeInTheDocument();
expect(screen.getByText(/add to home screen/i)).toBeInTheDocument();
});
});