File size: 4,849 Bytes
6d643ca | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { describe, expect, it, vi } from 'vitest';
import * as z from 'zod';
import { Button } from '@/components/ui/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { fireEvent, render, screen, waitFor } from '@/test/utils';
// Define a test schema for form validation
const formSchema = z.object({
email: z.string().email({ message: 'Please enter a valid email address' }),
password: z
.string()
.min(8, { message: 'Password must be at least 8 characters' }),
});
// Create a test form component
const TestForm = ({ onSubmit = vi.fn() }) => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
email: '',
password: '',
},
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="Enter your email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input
type="password"
placeholder="Enter your password"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
);
};
describe('Form', () => {
it('should render form fields correctly', () => {
render(<TestForm />);
expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument();
});
it('should validate email format', async () => {
render(<TestForm />);
const emailInput = screen.getByLabelText(/email/i);
const submitButton = screen.getByRole('button', { name: /submit/i });
// Enter invalid email
fireEvent.change(emailInput, { target: { value: 'invalid-email' } });
fireEvent.click(submitButton);
// Wait for validation message
await waitFor(() => {
expect(
screen.getByText(/please enter a valid email address/i)
).toBeInTheDocument();
});
// Enter valid email
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
// Validation message should disappear
await waitFor(() => {
expect(
screen.queryByText(/please enter a valid email address/i)
).not.toBeInTheDocument();
});
});
it('should validate password length', async () => {
render(<TestForm />);
const passwordInput = screen.getByLabelText(/password/i);
const submitButton = screen.getByRole('button', { name: /submit/i });
// Enter short password
fireEvent.change(passwordInput, { target: { value: 'short' } });
fireEvent.click(submitButton);
// Wait for validation message
await waitFor(() => {
expect(
screen.getByText(/password must be at least 8 characters/i)
).toBeInTheDocument();
});
// Enter valid password
fireEvent.change(passwordInput, { target: { value: 'validpassword' } });
// Validation message should disappear
await waitFor(() => {
expect(
screen.queryByText(/password must be at least 8 characters/i)
).not.toBeInTheDocument();
});
});
it('should call onSubmit with form data when form is valid', async () => {
const handleSubmit = vi.fn();
render(<TestForm onSubmit={handleSubmit} />);
const emailInput = screen.getByLabelText(/email/i);
const passwordInput = screen.getByLabelText(/password/i);
const submitButton = screen.getByRole('button', { name: /submit/i });
// Enter valid data
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
fireEvent.change(passwordInput, { target: { value: 'validpassword' } });
// Submit the form
fireEvent.click(submitButton);
// Check if onSubmit was called with correct data
await waitFor(() => {
expect(handleSubmit).toHaveBeenCalledWith(
{
email: 'test@example.com',
password: 'validpassword',
},
expect.anything()
);
});
});
});
|