import { screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { beforeEach, describe, expect, it, vi } from "vitest"; import ChangePasswordPage from "@/app/change-password/page"; import { renderWithQueryClient } from "./test-utils"; const replaceMock = vi.fn(); vi.mock("next/navigation", () => ({ useRouter: () => ({ push: vi.fn(), replace: replaceMock }), })); beforeEach(() => { replaceMock.mockClear(); }); describe("ChangePasswordPage", () => { it("rejects a weak new password before submitting", async () => { const user = userEvent.setup(); renderWithQueryClient(); await user.type(screen.getByLabelText(/current password/i), "correct-horse-1"); await user.type(screen.getByLabelText(/new password/i), "allletters"); await user.click(screen.getByRole("button", { name: /update password/i })); await waitFor(() => { expect( screen.getByText(/must contain at least one letter and one digit/i), ).toBeInTheDocument(); }); }); it("submits current + new password and redirects to the dashboard on success", async () => { const fetchMock = vi.fn().mockImplementation((url: string, init?: RequestInit) => { const path = url.replace("http://localhost:8000", ""); if (path === "/api/v1/auth/change-password" && init?.method === "POST") { expect(JSON.parse(init.body as string)).toEqual({ current_password: "correct-horse-1", new_password: "brand-new-horse-2", }); return Promise.resolve({ ok: true, status: 200, json: async () => ({ access_token: "new-access", refresh_token: "new-refresh", token_type: "bearer", expires_in_minutes: 15, }), }); } return Promise.resolve({ ok: false, status: 404, json: async () => ({ detail: "not found" }) }); }); vi.stubGlobal("fetch", fetchMock); const user = userEvent.setup(); renderWithQueryClient(); await user.type(screen.getByLabelText(/current password/i), "correct-horse-1"); await user.type(screen.getByLabelText(/new password/i), "brand-new-horse-2"); await user.click(screen.getByRole("button", { name: /update password/i })); await waitFor(() => { expect(replaceMock).toHaveBeenCalledWith("/dashboard"); }); }); it("surfaces an error for the wrong current password", async () => { vi.stubGlobal( "fetch", vi.fn().mockResolvedValue({ ok: false, status: 401, json: async () => ({ detail: "Incorrect current password" }), }), ); const user = userEvent.setup(); renderWithQueryClient(); await user.type(screen.getByLabelText(/current password/i), "wrong-password-1"); await user.type(screen.getByLabelText(/new password/i), "brand-new-horse-2"); await user.click(screen.getByRole("button", { name: /update password/i })); expect(await screen.findByText(/incorrect current password/i)).toBeInTheDocument(); }); });