daisy-client / src /components /__tests__ /Form.test.tsx
Jessedbrown's picture
feat/init-daisy-client
6d643ca
Raw History Blame Contribute Delete
4.85 kB
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()
);
});
});
});