From a64e213f9f8f0b6f2b314ec06555218f6c727434 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 25 Dec 2024 09:18:56 +0100 Subject: [PATCH] Improve Coverage for Auth Forms --- .../authentication/SignInForm.test.tsx | 86 +++++++++++++++++-- src/components/authentication/SignInForm.tsx | 13 ++- .../authentication/SignUpForm.test.tsx | 28 ++++++ 3 files changed, 114 insertions(+), 13 deletions(-) diff --git a/src/components/authentication/SignInForm.test.tsx b/src/components/authentication/SignInForm.test.tsx index 9c106c6..7e1ac69 100644 --- a/src/components/authentication/SignInForm.test.tsx +++ b/src/components/authentication/SignInForm.test.tsx @@ -3,20 +3,40 @@ import userEvent from "@testing-library/user-event"; import SignInForm from "./SignInForm"; -const mockedMethods = vi.hoisted(function () { +const mocks = vi.hoisted(function () { + const userCredentials = { id: "123" }; return { + userCredentials, + getRedirectResultFn: vi.fn().mockResolvedValue({ userCredentials }), signInAuthUserFn: vi.fn(), + signInWithGooglePopupFn: vi.fn().mockResolvedValue({ userCredentials }), + createUserDocumentFromAuthFn: vi.fn(), + signInWithGoogleRedirectFn: vi.fn(), }; }); -vi.mock("@/utils/firebase", function () { +vi.mock("firebase/auth", async function () { + const auth = await vi.importActual("firebase/auth"); + return { ...auth, getRedirectResult: mocks.getRedirectResultFn }; +}); + +vi.mock("@/utils/firebase", async function () { + const firebase = await vi.importActual("@/utils/firebase"); return { - signInAuthUserWithEmailAndPassword: mockedMethods.signInAuthUserFn, + ...firebase, + createUserDocumentFromAuth: mocks.createUserDocumentFromAuthFn, + signInAuthUserWithEmailAndPassword: mocks.signInAuthUserFn, + signInWithGooglePopup: mocks.signInWithGooglePopupFn, + signInWithGoogleRedirect: mocks.signInWithGoogleRedirectFn, }; }); vi.spyOn(window, "alert").mockImplementation(() => {}); +beforeEach(() => { + vi.clearAllMocks(); +}); + test("should render the correct titles", function () { render(); @@ -55,14 +75,14 @@ test("should submit the form with the correct data", async function () { await user.type(passwordInput, "password"); await user.click(submitButton); - expect(mockedMethods.signInAuthUserFn).toHaveBeenCalledWith( + expect(mocks.signInAuthUserFn).toHaveBeenCalledWith( "john.doe@test.com", "password", ); }); test("should show an alert if the password is incorrect", async function () { - mockedMethods.signInAuthUserFn.mockRejectedValue({ + mocks.signInAuthUserFn.mockRejectedValue({ code: "auth/wrong-password", }); @@ -82,7 +102,7 @@ test("should show an alert if the password is incorrect", async function () { }); test("should show an alert if the user is not found", async function () { - mockedMethods.signInAuthUserFn.mockRejectedValue({ + mocks.signInAuthUserFn.mockRejectedValue({ code: "auth/user-not-found", }); @@ -100,3 +120,57 @@ test("should show an alert if the user is not found", async function () { expect(window.alert).toHaveBeenCalledWith("Wrong email or password"); }); + +test("should log an error if signing in fails", async function () { + const consoleSpy = vi.spyOn(console, "error"); + mocks.signInAuthUserFn.mockRejectedValue(new Error("Failed to sign in")); + + render(); + + const emailInput = screen.getByLabelText(/email/i); + const passwordInput = screen.getByLabelText(/password/i); + const submitButton = screen.getByRole("button", { name: /^sign in$/i }); + + const user = userEvent.setup(); + + await user.type(emailInput, "john.doe@test.com"); + await user.type(passwordInput, "password"); + await user.click(submitButton); + + expect(consoleSpy).toHaveBeenCalledWith( + "Error signing in", + expect.any(Error), + ); +}); + +test("should sign in with Google using popup successfully", async function () { + render(); + + await userEvent.click( + screen.getByRole("button", { + name: /google sign in/i, + }), + ); + + expect(mocks.signInAuthUserFn).not.toHaveBeenCalled(); + expect(mocks.signInWithGooglePopupFn).toHaveBeenCalled(); + expect(mocks.createUserDocumentFromAuthFn).not.toHaveBeenCalledWith( + mocks.userCredentials, + ); +}); + +test("should sign in with Google redirect successfully", async function () { + render(); + + await userEvent.click( + screen.getByRole("button", { + name: /google sign in/i, + }), + ); + + expect(mocks.signInAuthUserFn).not.toHaveBeenCalled(); + expect(mocks.signInWithGoogleRedirectFn).toHaveBeenCalled(); + expect(mocks.createUserDocumentFromAuthFn).not.toHaveBeenCalledWith( + mocks.userCredentials, + ); +}); diff --git a/src/components/authentication/SignInForm.tsx b/src/components/authentication/SignInForm.tsx index a3fcc29..719b947 100644 --- a/src/components/authentication/SignInForm.tsx +++ b/src/components/authentication/SignInForm.tsx @@ -51,7 +51,7 @@ export default function SignInForm({ useRedirect = false }: SignInFormProps) { (error as AuthError).code === "auth/wrong-password" || (error as AuthError).code === "auth/user-not-found" ) { - alert("Wrong email or password"); + return alert("Wrong email or password"); } console.error("Error signing in", error); } @@ -66,6 +66,10 @@ export default function SignInForm({ useRedirect = false }: SignInFormProps) { await signInWithGoogleRedirect(); } + const handleGoogleSignin = !useRedirect + ? handleLoginWithGooglePopup + : handleRedirectWithGoogle; + return (
Already have an account? @@ -94,15 +98,10 @@ export default function SignInForm({ useRedirect = false }: SignInFormProps) { - {useRedirect && ( - - )}
diff --git a/src/components/authentication/SignUpForm.test.tsx b/src/components/authentication/SignUpForm.test.tsx index 4fca3b6..d30e672 100644 --- a/src/components/authentication/SignUpForm.test.tsx +++ b/src/components/authentication/SignUpForm.test.tsx @@ -126,3 +126,31 @@ test("should show an alert if email is already in use", async function () { "Cannot create user, email already in use!", ); }); + +test("should log an error if sign up fails", async function () { + const consoleSpy = vi.spyOn(console, "error"); + mockedMethods.createAuthUserFn.mockRejectedValue( + new Error("Failed to sign up"), + ); + + render(); + + const displayNameInput = screen.getByLabelText(/display name/i); + const emailInput = screen.getByLabelText(/email/i); + const passwordInput = screen.getByLabelText(/^password/i); + const confirmPasswordInput = screen.getByLabelText(/^confirm password/i); + const submitButton = screen.getByRole("button", { name: /sign up/i }); + + const user = userEvent.setup(); + + await user.type(displayNameInput, "John Doe"); + await user.type(emailInput, "john.doe@test.com"); + await user.type(passwordInput, "password"); + await user.type(confirmPasswordInput, "password"); + await user.click(submitButton); + + expect(consoleSpy).toHaveBeenCalledWith( + "Error signing up", + expect.any(Error), + ); +});