我正在尝试测试是否使用酶和玩笑来调用React组件方法。当<section>
元素变得不集中(模糊时)时,应该调用该函数。该组件已连接到Redux存储,但也按名称导出,以使Redux脱离方程式。下面是该组件的简化版本:
export class Section extends React.Component {
constructor(props) {
super(props)
this.formRef = React.createRef();
this.submitForm = this.submitForm.bind(this);
this.state = {
formSubmitted: false
}
}
submitForm() {
console.log("form submitted");
this.setState({ formSubmitted: true })
if (this.formRef && this.formRef.current) {
this.formRef.current.submit();
}
}
render() {
return (
<section onBlur={this.submitForm}>
<form ref={this.formRef} action={url} method='post'>
<input type="text" name="something" />
</form>
</section>
);
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Section);
我尝试了spyOn
部分的各种组合,因为这似乎是问题的根源。都失败了。
import React from 'react';
import { shallow } from 'enzyme';
import { Section } from './Section';
describe('Section', () => {
it('should submit form on blur', () => {
const wrapper = shallow(<Section content={{ body: [] }} />);
const spy = spyOn(wrapper.instance(), 'submitForm');
const spy2 = spyOn(Section.prototype, 'submitForm');
const spy3 = jest.spyOn(wrapper.instance(), 'submitForm');
const spy4 = jest.spyOn(Section.prototype, 'submitForm');
wrapper.find('section').simulate('blur');
expect(wrapper.state().formSubmitted).toEqual(true);
expect(spy).toHaveBeenCalled();
expect(spy2).toHaveBeenCalled();
expect(spy3).toHaveBeenCalled();
expect(spy4).toHaveBeenCalled();
})
})
除了测试expect(...).toHaveBeenCalled
之外,我还给了组件一个状态并对其进行了测试,以验证该函数是否确实被调用了,这似乎是事实。
console.log('form submitted')
出现在控制台中。
测试expect(wrapper.state().formSubmitted).toEqual(true);
通过了,这向我表明正在调用正确的函数。但是,我不想仅仅为了测试就拥有不必要的状态。刚刚添加状态以声明正在调用“ submitForm”方法。
断言expect(...).toHaveBeenCalled()
全部失败,并显示错误Expected spy to have been called, but it was not called
或Expected mock function to have been called, but it was not called.
答案 0 :(得分:3)
有趣的是,这个问题直接深入到JavaScript的一些较不寻常的方面。
submitForm
最初被定义为prototype method:
class Section extends React.Component {
...
submitForm() { ... }
...
}
...表示您将像这样创建spy
:
jest.spyOn(Section.prototype, 'submitForm');
...但是随后它被重新定义为constructor
中的instance property:
this.submitForm = this.submitForm.bind(this);
...表示您将立即创建spy
,如下所示:
jest.spyOn(wrapper.instance(), 'submitForm');
...但静止无效,因为onBlur
在this.submitForm
期间直接绑定绑定到render
:
<section onBlur={this.submitForm}>
因此,当前编写代码的方式实际上无法监视submitForm
,因为创建spy
需要一个instance
,但是instance
才可用组件已渲染,并且onBlur
在渲染期间直接绑定到this.submitForm
。
将onBlur
更改为调用this.submitForm
的函数,以便每触发onBlur
时,它将调用当前值 this.submitForm
:
render() {
return (
<section onBlur={() => this.submitForm()}>
<form ref={this.formRef} action={url} method='post'>
<input type="text" name="something" />
</form>
</section>
);
}
...然后,当您将{{1}上的submitForm
替换为spy
时,instance
将在spy
触发时被调用:
onBlur
答案 1 :(得分:1)
实际上,您想验证submit()
失去焦点时是否调用了表单的Section
,对吗?因此,您无需验证是否已调用内部方法-它无法确保是否提交表单。如果进行重构,也会导致假阴性结果(内部方法已重命名,一切正常,但测试失败)。
您可以改为模拟ref对象。然后,您将可以验证表单是否已提交
it('should submit form on blur', () => {
const wrapper = shallow(<Section content={{ body: [] }} />);
wrapper.instance().formRef.current = { submit: jest.fn()};
wrapper.find('section').simulate('blur');
expect(wrapper.instance().formRef.current.submit).toHaveBeenCalled();
})
确定测试还取决于组件的内部(包含ref的onto属性)。但是这样我相信测试更可靠。