diff --git a/apps/web/modules/signup-view.test.tsx b/apps/web/modules/signup-view.test.tsx new file mode 100644 index 0000000000..9888b88b99 --- /dev/null +++ b/apps/web/modules/signup-view.test.tsx @@ -0,0 +1,103 @@ +import { zodResolver } from "@hookform/resolvers/zod"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { useForm, FormProvider } from "react-hook-form"; +import { describe, expect, it } from "vitest"; +import { z } from "zod"; + +import { signupSchema as apiSignupSchema } from "@calcom/prisma/zod-utils"; + +const signupSchema = apiSignupSchema.extend({ + apiError: z.string().optional(), + cfToken: z.string().optional(), +}); + +type FormValues = z.infer; + +function TestSignupForm() { + const formMethods = useForm({ + resolver: zodResolver(signupSchema), + defaultValues: { + username: "", + email: "", + password: "", + }, + mode: "onTouched", + }); + + const { + register, + formState: { errors }, + } = formMethods; + + return ( + +
+ + + {errors.email && {errors.email.message}} + + + + {errors.password && {errors.password.message}} +
+
+ ); +} + +describe("Signup form validation mode", () => { + it("should not show email error while user is still typing", async () => { + const user = userEvent.setup(); + render(); + + const emailInput = screen.getByTestId("email-input"); + await user.type(emailInput, "test"); + + expect(screen.queryByTestId("email-error")).not.toBeInTheDocument(); + }); + + it("should show email error after the field is blurred with invalid value", async () => { + const user = userEvent.setup(); + render(); + + const emailInput = screen.getByTestId("email-input"); + await user.type(emailInput, "invalid-email"); + fireEvent.blur(emailInput); + + await waitFor(() => { + expect(screen.getByTestId("email-error")).toBeInTheDocument(); + }); + }); + + it("should not show email error if field is blurred with valid email", async () => { + const user = userEvent.setup(); + render(); + + const emailInput = screen.getByTestId("email-input"); + await user.type(emailInput, "test@example.com"); + fireEvent.blur(emailInput); + + await waitFor(() => { + expect(screen.queryByTestId("email-error")).not.toBeInTheDocument(); + }); + }); + + it("should revalidate on each keystroke after the field has been touched and blurred", async () => { + const user = userEvent.setup(); + render(); + + const emailInput = screen.getByTestId("email-input"); + + await user.type(emailInput, "bad"); + fireEvent.blur(emailInput); + await waitFor(() => { + expect(screen.getByTestId("email-error")).toBeInTheDocument(); + }); + + await user.clear(emailInput); + await user.type(emailInput, "valid@email.com"); + await waitFor(() => { + expect(screen.queryByTestId("email-error")).not.toBeInTheDocument(); + }); + }); +}); diff --git a/apps/web/modules/signup-view.tsx b/apps/web/modules/signup-view.tsx index 061b75e02d..f287ff9e33 100644 --- a/apps/web/modules/signup-view.tsx +++ b/apps/web/modules/signup-view.tsx @@ -200,7 +200,7 @@ export default function Signup({ const formMethods = useForm({ resolver: zodResolver(signupSchema), defaultValues: prepopulateFormValues satisfies FormValues, - mode: "onChange", + mode: "onTouched", }); const { register,