-
Notifications
You must be signed in to change notification settings - Fork 2
feat(sign-up-page): implement sign-up page with form fields, validation, and Google sign-in option #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/sign-in-page
Are you sure you want to change the base?
feat(sign-up-page): implement sign-up page with form fields, validation, and Google sign-in option #11
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| import { render, screen } from "@testing-library/react"; | ||
| import userEvent from "@testing-library/user-event"; | ||
| import { describe, it } from "vitest"; | ||
| import { BrowserRouter } from "react-router-dom"; | ||
| import { SignUpPage } from "./SignUpPage"; | ||
|
|
||
| const renderSignUpPage = () => { | ||
| return render( | ||
| <BrowserRouter> | ||
| <SignUpPage /> | ||
| </BrowserRouter>, | ||
| ); | ||
| }; | ||
|
|
||
| describe("SignUpPage", () => { | ||
| it("should render the email input field", () => { | ||
| renderSignUpPage(); | ||
|
|
||
| expect(screen.getByLabelText(/email/i)).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("should render the password input field", () => { | ||
| renderSignUpPage(); | ||
|
|
||
| expect(screen.getByLabelText(/^password$/i)).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("should render the confirm password input field", () => { | ||
| renderSignUpPage(); | ||
|
|
||
| expect(screen.getByLabelText(/confirm password/i)).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("should allow typing in the email input", async () => { | ||
| renderSignUpPage(); | ||
| const user = userEvent.setup(); | ||
|
|
||
| const emailInput = screen.getByLabelText(/email/i); | ||
| await user.type(emailInput, "test@example.com"); | ||
|
|
||
| expect(emailInput).toHaveValue("test@example.com"); | ||
| }); | ||
|
|
||
| it("should allow typing in the password input", async () => { | ||
| renderSignUpPage(); | ||
| const user = userEvent.setup(); | ||
|
|
||
| const passwordInput = screen.getByLabelText(/^password$/i); | ||
| await user.type(passwordInput, "password123"); | ||
|
|
||
| expect(passwordInput).toHaveValue("password123"); | ||
| }); | ||
|
|
||
| it("should allow typing in the confirm password input", async () => { | ||
| renderSignUpPage(); | ||
| const user = userEvent.setup(); | ||
|
|
||
| const confirmPasswordInput = screen.getByLabelText(/confirm password/i); | ||
| await user.type(confirmPasswordInput, "password123"); | ||
|
|
||
| expect(confirmPasswordInput).toHaveValue("password123"); | ||
| }); | ||
|
|
||
| it("should render the create account button", () => { | ||
| renderSignUpPage(); | ||
|
|
||
| expect( | ||
| screen.getByRole("button", { name: /create account/i }), | ||
| ).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("should render the continue with google button", () => { | ||
| renderSignUpPage(); | ||
|
|
||
| expect( | ||
| screen.getByRole("button", { name: /continue with google/i }), | ||
| ).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("should render the sign in link", () => { | ||
| renderSignUpPage(); | ||
|
|
||
| expect(screen.getByRole("link", { name: /sign in/i })).toBeInTheDocument(); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| import { useState } from "react"; | ||
| import { Link } from "react-router-dom"; | ||
| import { Button } from "../../components/button/Button"; | ||
| import { Input } from "../../components/input/Input"; | ||
| import { Card, CardBody } from "../../components/card/Card"; | ||
| import { GoogleLogo } from "../../components/googlelogo/GoogleLogo"; | ||
|
|
||
| export const SignUpPage = () => { | ||
| const [email, setEmail] = useState(""); | ||
| const [password, setPassword] = useState(""); | ||
| const [confirmPassword, setConfirmPassword] = useState(""); | ||
|
|
||
| const handleSubmit = (event: React.FormEvent) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: 🟠 Major
if (password !== confirmPassword) return setFormError("Passwords do not match"); |
||
| event.preventDefault(); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="min-h-screen bg-linear-to-br from-blue-50 to-indigo-100 flex items-center justify-center p-4"> | ||
| <div className="w-full max-w-md"> | ||
| <Card> | ||
| <CardBody className="space-y-6"> | ||
| <div className="text-center"> | ||
| <h1 className="text-2xl font-bold text-gray-900 mb-2"> | ||
| Create Account | ||
| </h1> | ||
| <p className="text-gray-600"> | ||
| Join us to save and organize your resources | ||
| </p> | ||
| </div> | ||
|
|
||
| <form onSubmit={handleSubmit} className="space-y-4"> | ||
| <Input | ||
| label="Email" | ||
| type="email" | ||
| placeholder="Enter your email" | ||
| value={email} | ||
| onChange={(event) => setEmail(event.target.value)} | ||
| className="w-full" | ||
| required | ||
| autoComplete="off" | ||
| /> | ||
|
|
||
| <Input | ||
| label="Password" | ||
| type="password" | ||
| placeholder="Create a password" | ||
| value={password} | ||
| onChange={(event) => setPassword(event.target.value)} | ||
| className="w-full" | ||
| required | ||
| autoComplete="off" | ||
| /> | ||
|
|
||
| <Input | ||
| label="Confirm Password" | ||
| type="password" | ||
| placeholder="Confirm your password" | ||
| value={confirmPassword} | ||
| onChange={(event) => setConfirmPassword(event.target.value)} | ||
| className="w-full" | ||
| required | ||
| autoComplete="off" | ||
| /> | ||
|
|
||
| <Button type="submit" className="w-full"> | ||
| Create Account | ||
| </Button> | ||
| </form> | ||
|
|
||
| <div className="relative"> | ||
| <div className="absolute inset-0 flex items-center"> | ||
| <div className="w-full border-t border-gray-200" /> | ||
| </div> | ||
| <div className="relative flex justify-center text-sm"> | ||
| <span className="px-2 bg-white text-gray-500"> | ||
| Or sign up with | ||
| </span> | ||
| </div> | ||
| </div> | ||
|
|
||
| <Button variant="outline" className="w-full"> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: 🟠 Major The “Continue with Google” button has no action; wire it to a handler (or accept an <Button type="button" onClick={handleGoogleSignIn} ...> |
||
| <GoogleLogo /> | ||
| Continue with Google | ||
| </Button> | ||
|
|
||
| <p className="text-center text-gray-600 text-sm"> | ||
| Already have an account? | ||
| <Link | ||
| to="/signin" | ||
| className="text-blue-600 hover:text-blue-700 font-medium" | ||
| > | ||
| Sign in | ||
| </Link> | ||
| </p> | ||
| </CardBody> | ||
| </Card> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Severity: 🟠 Major
Tests are mostly presence checks; add behavior assertions (e.g., sign-in link target and validation) and use
MemoryRouterfor isolation.