如何在开玩笑中模拟window.alert方法? [英] How can I mock the window.alert method in jest?

查看:96
本文介绍了如何在开玩笑中模拟window.alert方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆