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>({ resolver: zodResolver(formSchema), defaultValues: { email: '', password: '', }, }); return (
( Email )} /> ( Password )} /> ); }; describe('Form', () => { it('should render form fields correctly', () => { render(); 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(); 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(); 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(); 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() ); }); }); });