Skip to content

Commit

Permalink
Feat/Add unit tests to RecoverPassword component (#445)
Browse files Browse the repository at this point in the history
* test(RecoverPassword): add unit tests

* Returning a promise instead of using await (lint error) + fix build issues

* Test if updateUserMock was called in case of update failure
  • Loading branch information
ziyad-elabid-nw authored Jul 2, 2023
1 parent ca0591d commit 8bb8c21
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 1 deletion.
131 changes: 131 additions & 0 deletions frontend/app/(auth)/recover-password/__tests__/page.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<RecoverPassword />);
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(<RecoverPassword />);
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<void>((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(<RecoverPassword />);
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<void>((resolve) => {
setTimeout(() => {
expect(mockPublish).toHaveBeenCalledWith({
variant: "danger",
text: `Error: ${errorMessage}`,
});
resolve();
}, 0);
});
});
});
5 changes: 4 additions & 1 deletion frontend/app/(auth)/recover-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,12 @@ export default function RecoverPassword() {
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="New password"
data-testid="password-field"
/>
<div className="flex flex-col items-center justify-center mt-2 gap-2">
<Button isLoading={isPending}>Update</Button>
<Button isLoading={isPending} data-testid="update-button">
Update
</Button>
</div>
</form>
</Card>
Expand Down

0 comments on commit 8bb8c21

Please sign in to comment.