如何在开玩笑中模拟window.alert方法? [英] How can I mock the window.alert method in jest?
问题描述
我有以下React组件:
I have the following React component:
class Form extends React.Component {
constructor(props) {
super(props);
this.state = this._createEmptyTodo();
}
render() {
this.i18n = this.context;
return (
<div className="form">
<form onSubmit={this._handleSubmit.bind(this)}>
<input
placeholder={this.i18n.placeholders.addTitle}
type="text"
value={this.state.title}
onChange={this._handleTitleChange.bind(this)}></input>
<textarea
placeholder={this.i18n.placeholders.addDescription}
value={this.state.description}
onChange={this._handleDescriptionChange.bind(this)}></textarea>
<button>{this.i18n.buttons.submit}</button>
</form>
</div>
);
}
_handleTitleChange(e) {
this.setState({
title: e.target.value
});
}
_handleDescriptionChange(e) {
this.setState({
description: e.target.value
});
}
_handleSubmit(e) {
e.preventDefault();
var todo = {
date: new Date().getTime(),
title: this.state.title.trim(),
description: this.state.description.trim(),
done: false
};
if (!todo.title) {
alert(this.i18n.errors.title);
return;
}
if (!todo.description) {
alert(this.i18n.errors.description);
return;
}
this.props.showSpinner();
this.props.actions.addTodo(todo);
this.setState(this._createEmptyTodo());
}
_createEmptyTodo() {
return {
"pkey": null,
"title": "",
"description": ""
};
}
}
及相关测试:
const i18nContext = React.createContext();
Form.contextType = i18nContext;
describe('The <Form> component', () => {
var wrapper;
var showSpinner;
var actions = {}
beforeEach(() => {
showSpinner = jest.fn();
actions.addTodo = jest.fn();
wrapper = mount(<i18nContext.Provider value={i18n["en"]}>
<Form
showModalPanel={showSpinner}
actions={actions} />
</i18nContext.Provider>);
});
test("validate its input", () => {
window.alert = jest.fn();
wrapper.find("button").simulate("click");
expect(window.alert.mock.calls.length).toBe(1);//<<< this FAILS!
});
});
这种形式,当单击按钮时,它只是使用alert
来警告消息.
This form, when the button gets clicked, it simply alerts a message using alert
.
现在,当我运行测试时,我得到了:
Now when I run the test I get this:
expect(received).toBe(expected) // Object.is equality
Expected: 1
Received: 0
这是失败的,因为没有明显调用该模拟.但是,我向您保证,表单组件在单击其按钮时确实会警告消息.
Which is a failure because the mock does not get called apparently. But I promise you that the form component does alert a message when clicking on its button.
我怀疑由于某些原因,使用酶以编程方式执行点击时,Form
组件不会使用模拟的window.alert
.
I suspect that, for some reasons, the mocked window.alert
does not get used by the Form
component when the click is performed programmatically using enzyme.
有人吗?
推荐答案
在具有JSDOM global.window === global
的Jest配置中,因此可以在window
上对其进行模拟.
In Jest configuration with JSDOM global.window === global
, so it can be mocked on window
.
最好像这样模拟它
jest.spyOn(window, 'alert').mockImplementation(() => {});
因为window.alert = jest.fn()
污染了该套件中的其他测试.
because window.alert = jest.fn()
contaminates other tests in this suite.
黑盒测试的问题在于,故障排除难度更大,而且还依赖真实DOM预期的行为可能会导致问题,因为酶不一定支持这种行为.未知是否未调用alert
模拟不是调用了handleSubmit
的实际问题,这仅仅是出现问题的证据.
The problem with blackbox testing is that troubleshooting is harder, also relying on the behaviour that expected from real DOM may cause problems because Enzyme doesn't necessary support this behaviour. It's unknown whether the actual problem, handleSubmit
was called or not, that alert
mock wasn't called is just an evidence that something went wrong.
在这种情况下,按钮上的click
事件不会导致父表单上的submit
事件,因为Enzyme
In this case click
event on a button won't cause submit
event on parent form because Enzyme doesn't support that by design.
一种适当的单元测试策略是为除已测试的单元(即提交事件处理程序)以外的所有单元设置间谍程序或模拟程序.通常涉及到shallow
而不是mount
.
A proper unit-testing strategy is to set up spies or mocks for all units except tested one, which is submit event handler. It usually involves shallow
instead of mount
.
可能应该是:
jest.spyOn(window, 'alert').mockImplementation(() => {});
const formWrapper = wrapper.find(Form).dive();
jest.spyOn(formWrapper.instance(), '_handleSubmit');
formWrapper.find("form").simulate("submit");
expect(formWrapper.instance()._handleSubmit).toBeCalled();
expect(window.alert).toBeCalledWith(...);
应直接使用formWrapper.setState
更改状态,而不是DOM事件模拟.
State should be changed directly with formWrapper.setState
instead of DOM events simulation.
更孤立的单元测试是断言form
已提供预期的onSubmit
道具,并直接调用formWrapper.instance()._handleSubmit(...)
.
A more isolated unit test would be to assert that form
was provided with expected onSubmit
prop and call formWrapper.instance()._handleSubmit(...)
directly.
这篇关于如何在开玩笑中模拟window.alert方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!