diff --git a/frontend/app/(auth)/recover-password/__tests__/page.test.tsx b/frontend/app/(auth)/recover-password/__tests__/page.test.tsx
new file mode 100644
index 000000000..d4daab2f3
--- /dev/null
+++ b/frontend/app/(auth)/recover-password/__tests__/page.test.tsx
@@ -0,0 +1,131 @@
+/* eslint-disable max-lines */
+import { fireEvent, render } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+
+import RecoverPassword from "../page";
+
+const mockUsePathname = vi.fn(() => "/previous-page");
+const mockRedirect = vi.fn((url: string) => ({ url }));
+
+vi.mock("next/navigation", () => ({
+ redirect: (url: string) => mockRedirect(url),
+ usePathname: () => mockUsePathname(),
+}));
+
+const mockUseSupabase = vi.fn(() => ({
+ supabase: {
+ auth: {
+ updateUser: vi.fn(),
+ },
+ },
+ session: {
+ user: {},
+ },
+}));
+
+vi.mock("@/lib/context/SupabaseProvider", () => ({
+ useSupabase: () => mockUseSupabase(),
+}));
+
+const mockPublish = vi.fn();
+
+vi.mock("@/lib/hooks/useToast", () => ({
+ useToast: () => ({
+ publish: mockPublish,
+ }),
+}));
+
+const mockTrack = vi.fn();
+
+vi.mock("@/services/analytics/useEventTracking", () => ({
+ useEventTracking: () => ({
+ track: mockTrack,
+ }),
+}));
+
+describe("RecoverPassword component", () => {
+ it("should render the password update form", () => {
+ mockUseSupabase.mockReturnValue({
+ //@ts-expect-error doing this for testing purposes
+ session: { user: undefined },
+ });
+ const { getByTestId } = render();
+ const passwordField = getByTestId("password-field");
+ const updateButton = getByTestId("update-button");
+
+ expect(passwordField).toBeDefined();
+ expect(updateButton).toBeDefined();
+ });
+
+ it("should update the password and shows success toast", async () => {
+ const updateUserMock = vi.fn(() => ({
+ data: {},
+ }));
+ mockUseSupabase.mockReturnValue({
+ supabase: {
+ auth: {
+ updateUser: updateUserMock,
+ },
+ },
+ session: { user: {} },
+ });
+ const { getByTestId } = render();
+ const passwordField = getByTestId("password-field");
+ const updateButton = getByTestId("update-button");
+
+ const newPassword = "new-password";
+ fireEvent.change(passwordField, { target: { value: newPassword } });
+ fireEvent.click(updateButton);
+
+ expect(mockTrack).toHaveBeenCalledTimes(1);
+ expect(mockTrack).toHaveBeenCalledWith("UPDATE_PASSWORD");
+
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ expect(mockPublish).toHaveBeenCalledTimes(1);
+ expect(mockPublish).toHaveBeenCalledWith({
+ variant: "success",
+ text: "Password updated successfully!",
+ });
+ expect(updateUserMock).toHaveBeenCalledTimes(1);
+ expect(updateUserMock).toHaveBeenCalledWith({
+ password: newPassword,
+ });
+ resolve();
+ }, 0);
+ });
+ });
+
+ it("should show error toast when password update fails", async () => {
+ const errorMessage = "Password update failed";
+ const updateUserMock = vi.fn(() => ({
+ error: { message: errorMessage },
+ }));
+ mockUseSupabase.mockReturnValue({
+ supabase: {
+ auth: {
+ updateUser: updateUserMock,
+ },
+ },
+ session: { user: {} },
+ });
+ const { getByTestId } = render();
+ const passwordField = getByTestId("password-field");
+ const updateButton = getByTestId("update-button");
+
+ fireEvent.change(passwordField, { target: { value: "new-password" } });
+ fireEvent.click(updateButton);
+
+ expect(mockPublish).toHaveBeenCalledTimes(1);
+
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ expect(mockPublish).toHaveBeenCalledWith({
+ variant: "danger",
+ text: `Error: ${errorMessage}`,
+ });
+ resolve();
+ }, 0);
+ });
+ });
+});
diff --git a/frontend/app/(auth)/recover-password/page.tsx b/frontend/app/(auth)/recover-password/page.tsx
index 2f99d5e88..3697302aa 100644
--- a/frontend/app/(auth)/recover-password/page.tsx
+++ b/frontend/app/(auth)/recover-password/page.tsx
@@ -63,9 +63,12 @@ export default function RecoverPassword() {
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="New password"
+ data-testid="password-field"
/>
-
+