import { screen, waitFor } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import DashboardLayout from "@/app/(app)/layout"; import { renderWithQueryClient } from "./test-utils"; const replaceMock = vi.fn(); vi.mock("next/navigation", () => ({ useRouter: () => ({ push: vi.fn(), replace: replaceMock }), usePathname: () => "/dashboard", })); function meBody(mustChangePassword: boolean) { return { id: "user-1", email: "user@example.com", display_name: "Regular User", timezone: "America/New_York", is_active: true, is_admin: false, auth_mode: "jwt", must_change_password: mustChangePassword, }; } function systemStatusBody() { return { app_env: "development", auth_mode: "jwt", llm_provider: "mock", search_provider: "mock", sms_enabled: false, sms_provider: "twilio", ninjapear_configured: false, ninjapear_credit_balance: null, ninjapear_estimated_credits_per_company: null, is_localhost: false, turnstile_site_key: null, components: [], }; } function mockFetchImplementation(mustChangePassword: boolean) { return vi.fn().mockImplementation((url: string) => { const path = url.replace("http://localhost:8000", ""); if (path === "/api/v1/auth/me") { return Promise.resolve({ ok: true, status: 200, json: async () => meBody(mustChangePassword) }); } if (path === "/api/v1/system/status") { return Promise.resolve({ ok: true, status: 200, json: async () => systemStatusBody() }); } return Promise.resolve({ ok: false, status: 404, json: async () => ({ detail: "not found" }) }); }); } beforeEach(() => { replaceMock.mockClear(); }); describe("DashboardLayout - must_change_password redirect", () => { it("redirects to /change-password and withholds the page content when the flag is set", async () => { vi.stubGlobal("fetch", mockFetchImplementation(true)); renderWithQueryClient(
Protected dashboard content
, ); await waitFor(() => { expect(replaceMock).toHaveBeenCalledWith("/change-password"); }); expect(screen.queryByText(/protected dashboard content/i)).not.toBeInTheDocument(); }); it("renders normally when the flag is not set", async () => { vi.stubGlobal("fetch", mockFetchImplementation(false)); renderWithQueryClient(
Protected dashboard content
, ); expect(await screen.findByText(/protected dashboard content/i)).toBeInTheDocument(); expect(replaceMock).not.toHaveBeenCalledWith("/change-password"); }); });