React Testing Library无法检测React Hook Form的onSubmit调用问题
问题:React Hook Form + Vitest 中 submit 回调明明被调用,但 spy 检测不到
我怀疑这是使用 React Hook Form 及其 handleSubmit 方法导致的问题,但目前仍未找到原因。
相关代码
SimpleForm 组件
'use client'; import React from 'react'; import { useForm } from 'react-hook-form'; import { Button } from '../../button'; import { Input } from '../../input'; import { cn } from '@utils/cn'; import { formVariants } from '../style'; import type { FieldValues } from 'react-hook-form'; import type { SimpleFormProps } from '@/types'; /** * * @param inputs array containing all the fiels to process * @param onSubmit * @param defaultValues * @param width max-width of the form * @param gap gap between the inputs * @param backgroundColor general setting to set a default value * @param labelPosition * @param inputVariant * @param children to pass extra buttons in the submit button zone * @returns a simple form component that process all the inputs with React Hook Form */ export const SimpleForm = <T extends FieldValues>({ inputs, onSubmit, defaultValues, width = 'md', gap = 'lg', backgroundColor: globalBackgroundColor, labelPosition: globalLabelPosition, inputVariant: globalInputVariant, children, }: SimpleFormProps<T>) => { const { register, handleSubmit, formState: { errors }, } = useForm<T>({ defaultValues }); return ( <form onSubmit={handleSubmit(onSubmit)} className={cn(formVariants({ width, gap }))} aria-label="form" > {inputs.map( ({ label, backgroundColor: customBackgroundColor, labelPosition: customlabelPosition, inputVariant: customInputVariant, ...props }) => ( <Input key={label} label={label} register={register} errors={errors} backgroundColor={customBackgroundColor ?? globalBackgroundColor} labelPosition={customlabelPosition ?? globalLabelPosition} inputVariant={customInputVariant ?? globalInputVariant} {...props} /> ) )} <div> <Button type="submit" backgroundColor={globalBackgroundColor} className="mt-12" > Submit </Button> {children} </div> </form> ); };
测试用例
import React from 'react'; import '@testing-library/jest-dom'; import { cleanup, fireEvent, render, screen } from '@testing-library/react'; import { describe, expect, test, vi, afterEach, beforeEach } from 'vitest'; import type { Mock } from 'vitest'; import { SimpleForm } from '.'; import { createFakeInputs, fillRequiredFakeInputs } from '@/test/utils'; import type { InputGenericType } from '@/types'; type InputOption = Omit<InputGenericType<any>, 'errors' | 'register'>; describe('Simple forms', () => { let fakeInputs: InputOption[]; const mockedHandleOnSubmit: Mock = vi.fn((data) => { console.log('Je suis appelée !'); console.log(data); }); beforeEach(() => { fakeInputs = createFakeInputs(); }); afterEach(() => { cleanup(); }); test('creates a form with random inputs and a submit button', () => { render(<SimpleForm inputs={fakeInputs} onSubmit={mockedHandleOnSubmit} />); screen.getByRole('form'); for (const input of fakeInputs) { screen.getByText(input.label); } screen.getByRole('button', { name: 'Submit' }); }); test('Submit button sends ', () => { render(<SimpleForm inputs={fakeInputs} onSubmit={mockedHandleOnSubmit} />); // const form = screen.getByRole('form'); fillRequiredFakeInputs(fakeInputs); const submitButton = screen.getByRole('button', { name: 'Submit' }); console.log('Before fireEvent.click(submitButton)'); fireEvent.click(submitButton); // fireEvent.submit(form); console.log('After fireEvent.click(submitButton)'); expect(mockedHandleOnSubmit).toHaveBeenCalledOnce(); }); });
测试结果
stdout | app/components/atomic/form/simple-form/simple-form.test.tsx > Simple forms > Submit button sends Before fireEvent.click(submitButton) After fireEvent.click(submitButton) Je suis appelée ! { neque: 'unde omnis minima autem fuga ad', beatae: 'labore enim qui corrupti accusamus quo', delectus: 'occaecati consequuntur et modi laborum fugiat', minima: 'dicta unde laborum repellat maiores aspernatur', praesentium: undefined } ❯ app/components/atomic/form/simple-form/simple-form.test.tsx (2) ❯ Simple forms (2) ✓ creates a form with random inputs and a submit button × Submit button sends ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ FAIL app/components/atomic/form/simple-form/simple-form.test.tsx > Simple forms > Submit button sends AssertionError: expected "spy" to be called once, but got 0 times
mockedHandleOnSubmit确实被调用了,但Vitest的spy无法检测到。
技术栈与已尝试方法
- 技术栈:NextJS(最新版)、React(最新版)、testing-library/react 14.0.0
- 已尝试:直接触发表单的onSubmit事件,结果完全相同;尝试基于Promise的方式,同样未解决问题。
内容的提问来源于stack exchange,提问作者Julien Goletto
相关产品推荐
相关产品推荐

