Jest/Enzyme测试按钮点击失败:期望mock函数被调用
解决Jest/Enzyme测试中onAddClick方法相关断言失败问题
我最近卡在一个Jest/Enzyme测试上,其他点击事件的测试都能正常通过,但这个测试一直报错:
expect(jest.fn()).toHaveBeenCalled() expected mock function to have been called.
先贴出相关代码片段,方便排查问题:
渲染代码中的按钮点击事件
<button className={!this.state.name || !this.state.label || this.state.valueStore === null ? `add-custom-field-button disabled` : `add-custom-field-button`} id="test-addclick" onClick={() => {this.onAddClick()}} > Create Field </button>
onAddClick方法实现
onAddClick = () => { let obj = this.props.selectedFormJSON; this.addValueAttribute().then(()=>{ obj.FORM_COLUMN.push( { Control: this.state.control, CreateBy: this.props.user.userId, Datatype: this.state.datatype, Form_UID: this.props.selectedFormJSON.Form_UID, Help: this.state.help, ValueStore: this.state.valueStore } ) this.props.updateSelectedFormJSON(obj); if(!this.props.isNewForm && this.state.valueStore) { this.props.patchForm().then((res)=>{ if(res.Forms[0] && (res.Forms[0].Code === '200' || res.Forms[0].Code===200)) { toast(<div>Attribute Added Successfully!</div>, {type: toast.TYPE.SUCCESS,position: toast.POSITION.TOP_LEFT}) } else { toast(<div>Failed to Add Attribute!</div>, {type: toast.TYPE.ERROR,position: toast.POSITION.TOP_LEFT}) } }); } else if(this.state.valueStore) { this.props.postForm().then((res)=>{ if(res.Forms[0] && (res.Forms[0].Code === '201' || res.Forms[0].Code===201)) { toast(<div>Attribute Added Successfully!</div>, {type: toast.TYPE.SUCCESS,position: toast.POSITION.TOP_LEFT}) } else { toast(<div>Failed to Add Attribute!</div>, {type: toast.TYPE.ERROR,position: toast.POSITION.TOP_LEFT}) } }) } this.props.closeModal(); }) }
addValueAttribute方法实现
addValueAttribute = () => { return new Promise((resolve, reject) => { if(this.state.valueStore) { let {valueTables, valueDatatypes, service} = this.state; let body = { Name: this.state.name, TableName: this.props.selectedFormJSON.Entity, Datatype: this.state.datatype, ChangeType: 'I' } fetch(service.URL+'/VALUE_ATTRIBUTE', { headers: { 'Content-Type': 'application/json', 'Ocp-Apim-Subscription-Key': service.subscription_key, }, method: 'POST', credentials: 'include', body: JSON.stringify(body), }) .then((res) => { res.status === 201 && resolve(); }) .catch(() => { reject(); }) } else { //Not a value attr resolve() } }) }
测试代码
it("should call onAddClick", async () => { // use an async test method baseProps.closeModal.mockClear(); baseProps.updateSelectedFormJSON.mockClear(); const instance = wrapper.instance(); const spy = jest.spyOn(instance, 'addValueAttribute'); // spy on addValueAttribute... spy.mockImplementation(() => Promise.resolve()) // give any callbacks queued in PromiseJobs a chance to run wrapper.find('#test-addclick').at(0).simulate('click'); // simulate click expect(baseProps.updateSelectedFormJSON).toHaveBeenCalled(); // SUCCESS expect(baseProps.closeModal).toHaveBeenCalled(); // SUCCESS });
问题分析与修复方案
我仔细排查后发现,问题核心在于Promise异步执行的时机,以及按钮是否处于可点击状态这两个点:
1. 异步Promise的执行时机问题
虽然你标记了测试方法为async,但模拟点击后立刻做断言时,addValueAttribute返回的Promise回调还没执行完毕,导致依赖异步完成的方法调用还没触发。
修复方案:等待Promise回调执行完成
可以用await等待spy的Promise,或者等待事件循环清空:
it("should call onAddClick", async () => { baseProps.closeModal.mockClear(); baseProps.updateSelectedFormJSON.mockClear(); const instance = wrapper.instance(); const spy = jest.spyOn(instance, 'addValueAttribute'); spy.mockImplementation(() => Promise.resolve()); wrapper.find('#test-addclick').at(0).simulate('click'); // 等待Promise回调执行完成 await spy(); // 或者用这行等待所有异步任务:await Promise.resolve(); expect(baseProps.updateSelectedFormJSON).toHaveBeenCalled(); expect(baseProps.closeModal).toHaveBeenCalled(); });
2. 按钮可能处于禁用状态
你的按钮有禁用逻辑:!this.state.name || !this.state.label || this.state.valueStore === null,如果测试时组件state不满足条件,按钮会被禁用,点击事件根本不会触发。
修复方案:确保测试时组件state满足可点击条件
在模拟点击前,设置正确的state:
// 在渲染wrapper后、模拟点击前设置state wrapper.setState({ name: 'test-name', label: 'test-label', valueStore: 'test-value-store' // 传入非null的值 }); wrapper.find('#test-addclick').at(0).simulate('click');
另外提个小优化:可以把按钮的onClick={() => {this.onAddClick()}}简化成onClick={this.onAddClick},减少不必要的函数创建。
内容的提问来源于stack exchange,提问作者usertestREACT
相关产品推荐
相关产品推荐

