diff --git a/src/app/(auth-routes)/forgot-password/page.test.tsx b/src/app/(auth-routes)/forgot-password/page.test.tsx
new file mode 100644
index 000000000..024edbf5d
--- /dev/null
+++ b/src/app/(auth-routes)/forgot-password/page.test.tsx
@@ -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();
+
+ 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();
+
+ const emailInput = screen.getByPlaceholderText(/enter your email/i);
+ const sendButton = screen.getByText(/send/i);
+
+ fireEvent.change(emailInput, {
+ target: { value: "unregistered@example.com" },
+ });
+ 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();
+
+ const emailInput = screen.getByPlaceholderText(/enter your email/i);
+ const sendButton = screen.getByText(/send/i);
+
+ fireEvent.change(emailInput, {
+ target: { value: "akinsanyaadeyinka4166@gmail.com" },
+ });
+ fireEvent.click(sendButton);
+
+ await waitFor(() => {
+ expect(screen.getByText("Verification Code")).toBeInTheDocument();
+ });
+ });
+
+ it("shows error for incorrect OTP", async () => {
+ expect.hasAssertions();
+
+ render();
+
+ const emailInput = screen.getByPlaceholderText(/enter your email/i);
+ const sendButton = screen.getByText(/send/i);
+
+ fireEvent.change(emailInput, {
+ target: { value: "akinsanyaadeyinka4166@gmail.com" },
+ });
+ 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();
+
+ const emailInput = screen.getByPlaceholderText(/enter your email/i);
+ const sendButton = screen.getByText(/send/i);
+
+ fireEvent.change(emailInput, {
+ target: { value: "akinsanyaadeyinka4166@gmail.com" },
+ });
+ 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();
+ });
+ });
+});
diff --git a/src/app/(auth-routes)/forgot-password/page.tsx b/src/app/(auth-routes)/forgot-password/page.tsx
index 7361f9940..b48ca531b 100644
--- a/src/app/(auth-routes)/forgot-password/page.tsx
+++ b/src/app/(auth-routes)/forgot-password/page.tsx
@@ -173,6 +173,7 @@ const ForgotPassword = () => {
{
setCode(value);
setIsCodeComplete(value.length === 6);
@@ -282,7 +283,9 @@ const ForgotPassword = () => {
{
element: Default,
stage: 0,
- onSubmit: () => setCurrentStage(1),
+ onSubmit: () => {
+ if (!emailError) setCurrentStage(1);
+ },
},
{
element: VerificationCode,
diff --git a/src/components/common/input-otp/index.tsx b/src/components/common/input-otp/index.tsx
index ea8a93fed..87717ceb7 100644
--- a/src/components/common/input-otp/index.tsx
+++ b/src/components/common/input-otp/index.tsx
@@ -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 (
-
+
{/* eslint-disable unicorn/no-useless-spread */}
{/* eslint-disable unicorn/no-new-array */}