Skip to content

Commit

Permalink
Merge pull request #658 from hngprojects/feat/auth-forgot-password-test
Browse files Browse the repository at this point in the history
  • Loading branch information
Prudent Bird authored Jul 24, 2024
2 parents 12e5f9c + 56b2f08 commit 11a227b
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 9 deletions.
116 changes: 116 additions & 0 deletions src/app/(auth-routes)/forgot-password/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";

import ForgotPassword from "./page";

vi.mock("next/link", () => ({
default: ({ children }: { children: React.ReactNode }) => children,
}));

describe("forgot password page", () => {
it("renders the initial email input form", () => {
expect.hasAssertions();
render(<ForgotPassword />);

expect(screen.getByText(/forgot password/i)).toBeInTheDocument();

expect(screen.getByText(/enter the email address/i)).toBeInTheDocument();

expect(
screen.getByPlaceholderText(/enter your email/i),
).toBeInTheDocument();

expect(screen.getByText(/send/i)).toBeInTheDocument();
});

it("shows email error for unregistered email", async () => {
expect.hasAssertions();

render(<ForgotPassword />);

const emailInput = screen.getByPlaceholderText(/enter your email/i);
const sendButton = screen.getByText(/send/i);

fireEvent.change(emailInput, {
target: { value: "[email protected]" },
});
fireEvent.click(sendButton);

await waitFor(() => {
expect(
screen.getByText(/this email doesn't match our records/i),
).toBeInTheDocument();
});
});

it("proceeds to verification code stage on valid email", async () => {
expect.hasAssertions();

render(<ForgotPassword />);

const emailInput = screen.getByPlaceholderText(/enter your email/i);
const sendButton = screen.getByText(/send/i);

fireEvent.change(emailInput, {
target: { value: "[email protected]" },
});
fireEvent.click(sendButton);

await waitFor(() => {
expect(screen.getByText("Verification Code")).toBeInTheDocument();
});
});

it("shows error for incorrect OTP", async () => {
expect.hasAssertions();

render(<ForgotPassword />);

const emailInput = screen.getByPlaceholderText(/enter your email/i);
const sendButton = screen.getByText(/send/i);

fireEvent.change(emailInput, {
target: { value: "[email protected]" },
});
fireEvent.click(sendButton);

await waitFor(() => {
expect(screen.getByText("Verification Code")).toBeInTheDocument();
});

const otpInput = screen.getByTestId("forgot-password-otp-input");
fireEvent.change(otpInput, { target: { value: "000000" } });

await waitFor(() => {
expect(
screen.getByText(/the otp entered is not correct/i),
).toBeInTheDocument();
});
});

it("proceeds to reset password stage on correct OTP", async () => {
expect.hasAssertions();

render(<ForgotPassword />);

const emailInput = screen.getByPlaceholderText(/enter your email/i);
const sendButton = screen.getByText(/send/i);

fireEvent.change(emailInput, {
target: { value: "[email protected]" },
});
fireEvent.click(sendButton);

await waitFor(() => {
expect(screen.getByText("Verification Code")).toBeInTheDocument();
});

const otpInput = screen.getByTestId("forgot-password-otp-input");
fireEvent.change(otpInput, { target: { value: "123456" } });
const verifyButton = screen.getByText(/verify/i);
fireEvent.click(verifyButton);

await waitFor(() => {
expect(screen.getByText(/verification successful/i)).toBeInTheDocument();
});
});
});
5 changes: 4 additions & 1 deletion src/app/(auth-routes)/forgot-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ const ForgotPassword = () => {
<InputOtp
slotClassName={`size-10 sm:size-[60px] !rounded-lg border duration-300 font-bold text-xs sm:text-lg ${isCodeComplete && isCodeCorrect ? "border-primary ring-none" : !isCodeCorrect && isCodeComplete ? "border-error" : "border-stroke-colors-stroke ring-primary"}`}
className="justify-center"
data-testid="forgot-password-otp-input"
onChange={(value) => {
setCode(value);
setIsCodeComplete(value.length === 6);
Expand Down Expand Up @@ -282,7 +283,9 @@ const ForgotPassword = () => {
{
element: Default,
stage: 0,
onSubmit: () => setCurrentStage(1),
onSubmit: () => {
if (!emailError) setCurrentStage(1);
},
},
{
element: VerificationCode,
Expand Down
23 changes: 15 additions & 8 deletions src/components/common/input-otp/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,22 @@ interface Properties {
onComplete?: (value: string) => void;
}

export function InputOtp({
maxLength = 6,
slotClassName,
className,
onChange,
onComplete,
}: Properties) {
export function InputOtp(properties: Properties) {
const {
maxLength = 6,
slotClassName,
className,
onChange,
onComplete,
...rest
} = properties;
return (
<InputOTP maxLength={maxLength} onChange={onChange} onComplete={onComplete}>
<InputOTP
maxLength={maxLength}
onChange={onChange}
onComplete={onComplete}
{...rest}
>
<InputOTPGroup className={cn("flex gap-[10px] md:gap-4", className)}>
{/* eslint-disable unicorn/no-useless-spread */}
{/* eslint-disable unicorn/no-new-array */}
Expand Down

0 comments on commit 11a227b

Please sign in to comment.