// @vitest-environment jsdom import { beforeAll, afterEach, describe, expect, test, vitest, vi } from "vitest"; import "vitest-dom/extend-expect"; import { render, waitFor, screen, cleanup } from "@testing-library/react"; import { createRoutesStub } from "react-router"; import Root, { Layout } from "../root"; import * as auth from "~/lib/auth"; // Mock isAuthEnabled to control test behavior vi.mock("~/lib/auth", async () => { const actual = await vi.importActual("~/lib/auth"); return { ...actual, isAuthEnabled: vi.fn().mockReturnValue(true) }; }); describe("Root", () => { beforeAll(() => { // not sure what calls scrollTo, but it does get // called in this test - and if we don't mock it this // will throw an exception/warning window.scrollTo = vitest.fn(() => {}); }); afterEach(() => { cleanup(); vitest.clearAllMocks(); }); test("renders without crashing", async () => { function loader() { return { version: { name: "ABC123", url: "http://example.com/commit/ABC123", }, origin: "http://example.com", url: "http://example.com/path", }; } const RemixStub = createRoutesStub([ { path: "/", Component: Root, loader, }, ]); render(); // wait until the rows render in the document await waitFor(() => screen.findByText("Version")); expect(screen.getByText("ABC123")).toBeInTheDocument(); }); test("renders logout button when user is authenticated", async () => { // Mock isAuthEnabled to return true for this test vi.mocked(auth.isAuthEnabled).mockReturnValue(true); function loader() { return { version: { name: "ABC123", url: "http://example.com/commit/ABC123", }, origin: "http://example.com", url: "http://example.com/path", user: { authenticated: true }, isAuthEnabled: true }; } const RemixStub = createRoutesStub([ { path: "/", Component: Root, loader, }, ]); render(); await waitFor(() => screen.getByText("ABC123")); const logoutLink = screen.getByText("Logout"); expect(logoutLink).toBeInTheDocument(); expect(logoutLink.closest("a")).toHaveAttribute("href", "/logout"); expect(logoutLink.closest("a")).toHaveClass("ml-2"); }); }); describe("Layout", () => { beforeAll(() => { window.scrollTo = vitest.fn(() => {}); }); afterEach(() => { cleanup(); vitest.clearAllMocks(); }); test("renders with default data when no route data is available", async () => { const RemixStub = createRoutesStub([ { path: "/", // @ts-expect-error TODO: Figure out how t Component: Layout, // loader intentionally omitted }, ]); // note: this will render an element into a
, // which will trigger a warning in the console // // "Warning: validateDOMNesting(...): cannot appear as a child of
." await waitFor(() => render()); // Check for important meta tags const viewport = document.querySelector('meta[name="viewport"]'); expect(viewport).toHaveAttribute( "content", "width=device-width, initial-scale=1", ); }); test("renders with provided route data", async () => { function loader() { return { version: "v1.2.3", origin: "test.counterscale.dev", url: "https://test.counterscale.dev/", }; } const RemixStub = createRoutesStub([ { path: "/", // @ts-expect-error TODO: Figure out how to type this Component: Layout, loader, }, ]); render(); await waitFor(() => expect( document.querySelector('meta[property="og:url"]'), ).toBeInTheDocument(), ); const meta = document.querySelector('meta[property="og:url"]'); expect(meta).toHaveAttribute( "content", "https://test.counterscale.dev/", ); }); });