如何用react-testing-library测试React-hook-form+MUI TextField校验?
问题出在你把trigger mock成jest.fn()了——这直接跳过了react-hook-form的原生校验触发逻辑,自然不会生成错误提示。下面是正确的测试思路和代码:
先确认组件实现(参考示例)
import { useForm, Controller } from 'react-hook-form'; import { z } from 'zod'; import { TextField } from '@mui/material'; import { zodResolver } from '@hookform/resolvers/zod'; const schema = z.object({ input: z.string().max(10, 'Invalid input'), }); type FormValues = z.infer<typeof schema>; export default function MyForm() { const { control, handleSubmit, formState: { errors } } = useForm<FormValues>({ resolver: zodResolver(schema), defaultValues: { input: '' }, }); const onSubmit = (data: FormValues) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="input" control={control} render={({ field }) => ( <TextField {...field} label="Input" error={!!errors.input} helperText={errors.input?.message} variant="outlined" /> )} /> <button type="submit">Submit</button> </form> ); }
正确的测试代码
核心是不要mock trigger,让react-hook-form的原生校验逻辑正常运行:
import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import MyForm from './MyForm'; test('shows error when input exceeds 10 characters', async () => { const user = userEvent.setup(); render(<MyForm />); // 找到输入框并输入超过10字符的内容 const input = screen.getByLabelText('Input'); await user.type(input, 'abcdefghijk'); // 11个字符 // 触发校验:RHF默认校验时机是onBlur,所以手动触发失去焦点 await user.blur(input); // 等待校验完成、DOM更新后断言错误信息存在 await waitFor(() => { expect(screen.getByText('Invalid input')).toBeInTheDocument(); }); // 另一种方式:通过提交表单触发校验 // const submitBtn = screen.getByText('Submit'); // await user.click(submitBtn); // await waitFor(() => { // expect(screen.getByText('Invalid input')).toBeInTheDocument(); // }); });
关键注意点
- 别mock
trigger:这个方法是react-hook-form内部触发校验的核心,手动mock会直接阻断校验流程,必须保留原生实现。 - 触发对应校验时机:RHF默认校验时机是
onBlur和onSubmit,测试时需要主动触发这两个行为之一,才能让zod的校验逻辑运行并生成错误信息。如果你的组件设置了mode: 'onChange',则只需输入内容后直接等待错误出现即可。 - 用
waitFor异步断言:校验和DOM更新是异步过程,必须用waitFor等待元素渲染完成后再查询。
内容的提问来源于stack exchange,提问作者Vladut Clapou
相关产品推荐
相关产品推荐

