Как я могу издеваться над методом window.alert в шутку? - PullRequest
0 голосов
/ 04 декабря 2018

У меня есть следующий компонент React:

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.

Теперь, когда я запускаю тест, я получаю это:

expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0

Что является ошибкой, потому что mock не вызывается, по-видимому.Но я обещаю вам, что компонент формы предупреждает сообщение при нажатии на его кнопку.

Я подозреваю, что по некоторым причинам поддельный window.alert не используется компонентом Form, когда щелчок выполняется программно с использованием фермента.

Кто-нибудь?

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

В конфигурации Jest с JSDOM global.window === global, поэтому его можно смоделировать на window.

Желательно смоделировать его как

jest.spyOn(window, 'alert').mockImplementation(() => {});

, поскольку window.alert = jest.fn() загрязняет другие тестыв этом наборе.

Проблема с тестированием черного ящика заключается в том, что устранение неполадок затруднено, и полагаться на поведение, ожидаемое от реального DOM, может вызвать проблемы, поскольку Enzyme не обязательно поддерживает это поведение.Неизвестно, была ли вызвана действительная проблема, handleSubmit, или нет, то, что alert макет не был вызван, является просто доказательством того, что что-то пошло не так.

В этом случае click событие на кнопке выигралоне вызывает submit событие в родительской форме, потому что Enzyme не поддерживает это по проекту .

Правильная стратегия юнит-тестирования состоит в том, чтобы настроить шпионов или издевательства для всех юнитов, кроме протестированных.один, который является обработчиком события submit.Обычно это shallow вместо 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.

Более изолированным модульным тестом было бы утверждать, что form был предоставлен ожидаемый onSubmit реквизит и напрямую вызывать formWrapper.instance()._handleSubmit(...).

0 голосов
/ 04 декабря 2018

Вместо window вы можете использовать global.

global.alert = jest.fn();

Это связано с тем, что браузеры используют имя window, а nodejs использует имя global.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...