mirror of
https://github.com/StanGirard/quivr.git
synced 2024-12-24 20:03:41 +03:00
Frontend/unit tests (#485)
* test(GoogleLogin): add unit tests * test: run tests concurrently * test(<LogoutPage/>): add unit tests * chore: refactor <SigupPage/> * test(<SignUpPage />): add unit tests
This commit is contained in:
parent
f0a30b8452
commit
6b39dd5641
@ -0,0 +1,52 @@
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { GoogleLoginButton } from "..";
|
||||
|
||||
//Mocking related hooks
|
||||
const mockUseGoogleLogin = vi.fn(() => ({
|
||||
isPending: false,
|
||||
signInWithGoogle: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../hooks/useGoogleLogin", () => ({
|
||||
useGoogleLogin: () => mockUseGoogleLogin(),
|
||||
}));
|
||||
|
||||
describe.concurrent("GoogleLoginButton", () => {
|
||||
it("renders correctly", () => {
|
||||
const { getByTestId } = render(<GoogleLoginButton />);
|
||||
|
||||
const loginButton = getByTestId("google-login-button");
|
||||
|
||||
expect(loginButton).toBeDefined();
|
||||
});
|
||||
|
||||
it("calls signInWithGoogle on button click", () => {
|
||||
const mockSignInWithGoogle = vi.fn();
|
||||
mockUseGoogleLogin.mockReturnValue({
|
||||
isPending: false,
|
||||
signInWithGoogle: mockSignInWithGoogle,
|
||||
});
|
||||
|
||||
const { getByTestId } = render(<GoogleLoginButton />);
|
||||
const loginButton = getByTestId("google-login-button");
|
||||
fireEvent.click(loginButton);
|
||||
|
||||
expect(mockSignInWithGoogle).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("doesn't call signInWithGoogle on button click when pending", () => {
|
||||
const mockSignInWithGoogle = vi.fn();
|
||||
mockUseGoogleLogin.mockReturnValue({
|
||||
isPending: true,
|
||||
signInWithGoogle: mockSignInWithGoogle,
|
||||
});
|
||||
|
||||
const { getByTestId } = render(<GoogleLoginButton />);
|
||||
const loginButton = getByTestId("google-login-button");
|
||||
fireEvent.click(loginButton);
|
||||
|
||||
expect(mockSignInWithGoogle).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
@ -12,6 +12,7 @@ export const GoogleLoginButton = () => {
|
||||
isLoading={isPending}
|
||||
variant={"secondary"}
|
||||
type="button"
|
||||
data-testid="google-login-button"
|
||||
>
|
||||
Login with Google
|
||||
</Button>
|
||||
|
51
frontend/app/(auth)/logout/__tests__/page.test.tsx
Normal file
51
frontend/app/(auth)/logout/__tests__/page.test.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import Logout from "../page";
|
||||
|
||||
// mocking related hooks
|
||||
const mockUseLogout = vi.fn(() => ({
|
||||
handleLogout: vi.fn(),
|
||||
isPending: false,
|
||||
}));
|
||||
|
||||
vi.mock("../hooks/useLogout", () => ({
|
||||
useLogout: () => mockUseLogout(),
|
||||
}));
|
||||
|
||||
describe("Logout component", () => {
|
||||
it("should render correctly", () => {
|
||||
const { getByTestId } = render(<Logout />);
|
||||
const logoutPage = getByTestId("logout-page");
|
||||
expect(logoutPage).toBeDefined();
|
||||
});
|
||||
|
||||
it("should call handleLogout 1 time when logout button is clicked", () => {
|
||||
const mockHandleLogout = vi.fn();
|
||||
|
||||
mockUseLogout.mockReturnValue({
|
||||
handleLogout: mockHandleLogout,
|
||||
isPending: false,
|
||||
});
|
||||
|
||||
const { getByTestId } = render(<Logout />);
|
||||
const logoutButton = getByTestId("logout-button");
|
||||
logoutButton.click();
|
||||
|
||||
expect(mockHandleLogout).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should not call handleLogout when isPending is true", () => {
|
||||
const mockHandleLogout = vi.fn();
|
||||
|
||||
mockUseLogout.mockReturnValue({
|
||||
handleLogout: mockHandleLogout,
|
||||
isPending: true,
|
||||
});
|
||||
|
||||
const { getByTestId } = render(<Logout />);
|
||||
const logoutButton = getByTestId("logout-button");
|
||||
logoutButton.click();
|
||||
expect(mockHandleLogout).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
@ -10,7 +10,7 @@ import { useLogout } from "./hooks/useLogout";
|
||||
export default function Logout() {
|
||||
const { handleLogout, isPending } = useLogout();
|
||||
return (
|
||||
<main>
|
||||
<main data-testid="logout-page">
|
||||
<section className="w-full min-h-[80vh] h-full outline-none flex flex-col gap-5 items-center justify-center p-6">
|
||||
<PageHeading title="Logout" subtitle="See you next time" />
|
||||
<Card className="max-w-md w-full p-5 sm:p-10 text-center flex flex-col items-center gap-5">
|
||||
@ -23,6 +23,7 @@ export default function Logout() {
|
||||
isLoading={isPending}
|
||||
variant={"danger"}
|
||||
onClick={() => handleLogout()}
|
||||
data-testid="logout-button"
|
||||
>
|
||||
Log Out
|
||||
</Button>
|
||||
|
66
frontend/app/(auth)/signup/__tests__/page.test.tsx
Normal file
66
frontend/app/(auth)/signup/__tests__/page.test.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import SignUp from "../page";
|
||||
|
||||
const mockHandleSignUp = vi.fn(() => ({}));
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({ replace: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/context/SupabaseProvider", () => ({
|
||||
useSupabase: () => ({}),
|
||||
}));
|
||||
|
||||
describe("SignUp component", () => {
|
||||
it("should render correctly", () => {
|
||||
const { getByTestId } = render(<SignUp />);
|
||||
const signUpPage = getByTestId("sign-up-page");
|
||||
expect(signUpPage).toBeDefined();
|
||||
|
||||
const signUpForm = getByTestId("sign-up-form");
|
||||
expect(signUpForm).toBeDefined();
|
||||
|
||||
const emailInput = getByTestId("email-field");
|
||||
expect(emailInput).toBeDefined();
|
||||
|
||||
const passwordInput = getByTestId("password-field");
|
||||
expect(passwordInput).toBeDefined();
|
||||
|
||||
const signUpButton = getByTestId("sign-up-button");
|
||||
expect(signUpButton).toBeDefined();
|
||||
});
|
||||
|
||||
it("should correctly fill the email and password fields", () => {
|
||||
const { getByTestId } = render(<SignUp />);
|
||||
const emailInput = getByTestId("email-field") as HTMLInputElement;
|
||||
const passwordInput = getByTestId("password-field") as HTMLInputElement;
|
||||
|
||||
fireEvent.change(emailInput, { target: { value: "user@quivr.app" } });
|
||||
fireEvent.change(passwordInput, { target: { value: "password123" } });
|
||||
expect(emailInput.value).toBe("user@quivr.app");
|
||||
expect(passwordInput.value).toBe("password123");
|
||||
});
|
||||
|
||||
it("should call handleSignUp on submit", () => {
|
||||
vi.mock("../hooks/useSignUp", async () => {
|
||||
const functions = await vi.importActual<
|
||||
typeof import("../hooks/useSignUp")
|
||||
>("../hooks/useSignUp");
|
||||
|
||||
return {
|
||||
useSignUp: () => ({
|
||||
...functions.useSignUp(),
|
||||
handleSignUp: () => mockHandleSignUp(),
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const { getByTestId } = render(<SignUp />);
|
||||
const submitForm = getByTestId("sign-up-form") as HTMLFormElement;
|
||||
|
||||
fireEvent.submit(submitForm);
|
||||
expect(mockHandleSignUp).toHaveBeenCalled();
|
||||
});
|
||||
});
|
47
frontend/app/(auth)/signup/hooks/useSignUp.ts
Normal file
47
frontend/app/(auth)/signup/hooks/useSignUp.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { useSupabase } from "@/lib/context/SupabaseProvider";
|
||||
import { useToast } from "@/lib/hooks/useToast";
|
||||
import { useEventTracking } from "@/services/analytics/useEventTracking";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export const useSignUp = () => {
|
||||
const { supabase } = useSupabase();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
const { track } = useEventTracking();
|
||||
|
||||
const { publish } = useToast();
|
||||
const handleSignUp = async () => {
|
||||
void track("SIGNUP");
|
||||
setIsPending(true);
|
||||
const { error } = await supabase.auth.signUp({
|
||||
email: email,
|
||||
password: password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error("Error signing up:", error.message);
|
||||
publish({
|
||||
variant: "danger",
|
||||
text: `Error signing up: ${error.message}`,
|
||||
});
|
||||
} else {
|
||||
publish({
|
||||
variant: "success",
|
||||
text: "Confirmation Email sent, please check your email",
|
||||
});
|
||||
}
|
||||
setIsPending(false);
|
||||
};
|
||||
|
||||
return {
|
||||
handleSignUp,
|
||||
setEmail,
|
||||
password,
|
||||
setPassword,
|
||||
isPending,
|
||||
email,
|
||||
};
|
||||
};
|
@ -1,50 +1,18 @@
|
||||
/* eslint-disable */
|
||||
"use client";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
|
||||
import Button from "@/lib/components/ui/Button";
|
||||
import Card from "@/lib/components/ui/Card";
|
||||
import Field from "@/lib/components/ui/Field";
|
||||
import PageHeading from "@/lib/components/ui/PageHeading";
|
||||
import { useSupabase } from "@/lib/context/SupabaseProvider";
|
||||
import { useToast } from "@/lib/hooks/useToast";
|
||||
import { useEventTracking } from "@/services/analytics/useEventTracking";
|
||||
import { useSignUp } from "./hooks/useSignUp";
|
||||
|
||||
export default function SignUp() {
|
||||
const { supabase } = useSupabase();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
const { track } = useEventTracking();
|
||||
|
||||
|
||||
const { publish } = useToast();
|
||||
const handleSignUp = async () => {
|
||||
void track("SIGNUP")
|
||||
setIsPending(true);
|
||||
const { data, error } = await supabase.auth.signUp({
|
||||
email: email,
|
||||
password: password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error("Error signing up:", error.message);
|
||||
publish({
|
||||
variant: "danger",
|
||||
text: `Error signing up: ${error.message}`,
|
||||
});
|
||||
} else if (data) {
|
||||
publish({
|
||||
variant: "success",
|
||||
text: "Confirmation Email sent, please check your email",
|
||||
});
|
||||
}
|
||||
setIsPending(false);
|
||||
};
|
||||
|
||||
const { handleSignUp, isPending, email, password, setEmail, setPassword } =
|
||||
useSignUp();
|
||||
return (
|
||||
<main>
|
||||
<main data-testid="sign-up-page">
|
||||
<section className="min-h-[80vh] w-full h-full outline-none flex flex-col gap-5 items-center justify-center p-6">
|
||||
<PageHeading title="Sign Up" subtitle="Create your account" />
|
||||
<Card className="max-w-md w-full p-5 sm:p-10 text-left">
|
||||
@ -54,13 +22,16 @@ export default function SignUp() {
|
||||
handleSignUp();
|
||||
}}
|
||||
className="flex flex-col gap-2"
|
||||
data-testid="sign-up-form"
|
||||
>
|
||||
<Field
|
||||
name="email"
|
||||
required
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
data-testid="email-field"
|
||||
/>
|
||||
<Field
|
||||
name="password"
|
||||
@ -69,9 +40,12 @@ export default function SignUp() {
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder="Password"
|
||||
data-testid="password-field"
|
||||
/>
|
||||
<div className="flex flex-col items-center justify-center mt-2 gap-2">
|
||||
<Button isLoading={isPending}>Sign Up</Button>
|
||||
<Button data-testid="sign-up-button" isLoading={isPending}>
|
||||
Sign Up
|
||||
</Button>
|
||||
<Link href="/login">Already registered? Sign in</Link>
|
||||
</div>
|
||||
</form>
|
||||
|
Loading…
Reference in New Issue
Block a user