React Testing Library点击按钮触发Formik提交时Mock函数未调用问题
存在的问题
- 变量名拼写错误:测试代码中导入的API模块命名是
ItemAPI,但创建spy时写的是itemAPI,大小写不匹配导致mock根本没生效,原createItem方法没有被替换。 - Input值绑定冲突:Input组件同时写了
value={props.initialValues.Name}和{...props.getFieldProps("Name")},前者会把输入框的值固定为初始空值,你触发change事件修改的值根本不会同步到Formik的状态中,也不会带到onSubmit里。 - 没有等待异步逻辑执行完成:Formik的onSubmit是异步函数,你点击提交按钮后直接同步执行断言,此时onSubmit里的异步逻辑还没跑完,自然检测不到
mockCreateItem的调用。你测试直接给Button的onClick绑test能正常触发,就是因为这个调用是同步的,而异步的onSubmit内部调用需要等待执行完成才能检测到。
可行解决方案
- 修正测试里的API模块变量名,把
jest.spyOn(itemAPI, "createItem")改为jest.spyOn(ItemAPI, "createItem") - 删除Input组件上多余的
value={props.initialValues.Name}属性,getFieldProps已经内置了value和onChange的绑定,不需要额外赋值初始值,否则会覆盖表单输入的内容。 - 测试用例改为async函数,点击提交后用
waitFor包裹断言,等待异步逻辑执行完成再校验调用情况,修改后的测试代码参考:
import { waitFor } from '@testing-library/react'; describe("item form tests", () =>{ test("add new item", async () =>{ let mockCreateItem = jest.spyOn(ItemAPI, "createItem").mockResolvedValue({}); let spy = jest.fn(); render(<ItemForm test={spy}/>) const name = screen.getByRole('textbox',{name:"Name"}) const submit = screen.getByRole('button',{id:"item_form_submit"}) fireEvent.change(name,{target:{value:"Kitchen Item"}}) fireEvent.click(submit); await waitFor(() => { expect(mockCreateItem).toHaveBeenCalledTimes(1) expect(mockCreateItem).toHaveBeenCalledWith({Name:"Kitchen Item"}) // expect(spy).toHaveBeenCalledTimes(1) }) }) })
内容的提问来源于stack exchange,提问作者Poorna
相关产品推荐
相关产品推荐

