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();
});
});