Next.js表单验证测试问题:提交按钮点击未触发验证
Next.js表单验证测试问题排查方案
问题描述
在Next.js应用中做表单验证测试时遇到问题:表单包含多个输入框,提交无效表单时页面应显示错误提示,但测试里点击提交按钮的操作似乎没生效,无法触发验证错误提示。
测试文件代码
import Login from "@/app/components/auth/login-form/login"; import { render, screen, fireEvent } from "@testing-library/react"; jest.mock("next/navigation", () => ({ useRouter: jest.fn(), })); describe('Login Form Component', () => { it('should render the login form component with validation errors', async () => { render(<Login />); const button = screen.getByRole('button', { name: 'Login to your account' }); fireEvent.change(screen.getByPlaceholderText('name@company.com'), { target: { value: '' } }); fireEvent.click(button, new MouseEvent('click')); expect(screen.getByTestId('email-error')).toBeInTheDocument(); }); });
组件代码
"use client"; import { RegisterForm } from "@/app/types/types"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useForm } from "react-hook-form" export default function Login() { const router = useRouter(); const { register, handleSubmit, formState: { errors } } = useForm<RegisterForm>({ defaultValues: { email: '', password: '' } }); const handleClose = () => { router.back(); } async function handlePostData(data: RegisterForm) { console.log(data); } return ( <> <div className="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600 border-gray-200"> <h3 className="text-xl font-semibold text-gray-900 dark:text-white"> Sign in to our platform </h3> <button onClick={handleClose} type="button" className="end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-hide="authentication-modal"> <svg className="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14"> <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> </svg> <span className="sr-only">Close modal</span> </button> </div> <div className="p-4 md:p-5"> <form className="space-y-4" onSubmit={handleSubmit((data) => handlePostData(data))}> <div> <label htmlFor="email" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label> <input type="email" {...register("email", { required: 'email is required to signin' })} id="email" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="name@company.com" /> {errors.email && <p className="text-red-500" data-testid="email-error">{errors.email?.message}</p>} </div> <div> <label htmlFor="password" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your password</label> <input type="password" id="password" placeholder="••••••••" {...register("password", { required: 'password is required to signin' })} className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" /> {errors.password && <p className="text-red-500" data-testid="password-error">{errors.password?.message}</p>} </div> <button type="submit" className="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Login to your account</button> <div className="text-sm font-medium text-gray-500 dark:text-gray-300"> Not registered? <Link href="/signup" className="text-blue-700 hover:underline dark:text-blue-500">Create an account</Link> </div> </form> </div> </> ) }
解决方法
直接触发表单提交事件:替换点击按钮的操作,改为获取表单元素并触发
submit事件。按钮点击可能因事件冒泡或其他逻辑干扰失效,直接操作表单更可靠:const form = screen.getByRole('form'); fireEvent.submit(form);使用
waitFor等待错误提示渲染:react-hook-form的错误状态更新可能需要React完成一次重渲染,用waitFor包裹断言确保元素已加载:import { render, screen, fireEvent, waitFor } from "@testing-library/react"; // ...测试代码 await waitFor(() => { expect(screen.getByTestId('email-error')).toBeInTheDocument(); });移除不必要的输入框状态设置:组件默认值已将email设为空字符串,无需再用
fireEvent.change设置空值,避免干扰表单初始状态。确认react-hook-form的验证模式:在
useForm中明确设置mode: "onSubmit",确保提交时触发验证:const { register, handleSubmit, formState: { errors } } = useForm<RegisterForm>({ defaultValues: { email: '', password: '' }, mode: "onSubmit" // 明确指定提交时验证 });检查按钮选择器是否准确:尝试用
screen.getByText('Login to your account')获取按钮,避免getByRole的name匹配规则导致找不到元素。异步处理表单提交函数:由于
handlePostData是异步函数,可在测试中模拟它或确保验证逻辑不受异步操作影响,比如用jest.spyOn模拟:jest.spyOn(global.console, 'log').mockImplementation(() => {});
内容的提问来源于stack exchange,提问作者jordan
相关产品推荐
相关产品推荐

