Тестирование асин c поведения в React с Ax ios и Jest - PullRequest
2 голосов
/ 21 апреля 2020

Рассмотрим следующий упрощенный компонент React. Когда вы нажимаете кнопку, он вызывает API-интерфейс к внешнему URL-адресу.

  • Если он успешен, он увеличивает счетчик
  • Если он неудачен, он уменьшает счетчик
import axios from 'axios';
import PropTypes from 'prop-types';
import React from 'react';

class MyCoolButton extends React.Component {
  static propTypes = {
    initialCounter: PropTypes.number.isRequired
  };

  constructor(props) { 
    super(props);

    this.onClick = this.onClick.bind(this);

    this.state = {
      counter: props.initialCounter
    }
  }

  onClick() {
    const url = `/some/url/here`;
    const data = { foo: 'bar' };
    const config = { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } };

    const { counter } = this.state;

    return axios.patch(url, data, config)
      .then((response) => { /* Success! */ this.setState({ counter: counter + 1 }); })
      .catch((error) => { /* Failure :( */ this.setState({ counter: counter - 1 }); });
  }

  render() {
    return (
      <div className="container">
        <span>Counter value is: {this.state.counter}</span>
        <input className="cool-button" type="button" onClick={this.onClick} />
      </div>        
    );
  }

}

export default MyCoolButton;

Я хотел написать тестовый пример с использованием Jest, чтобы убедиться, что в случае сбоя мы правильно уменьшаем кнопку.

Я попробовал следующее:

describe('an error occurred while updating', () => {
  beforeEach(() => {
    axios.patch.mockImplementationOnce(() => Promise.reject('boo'));
  });

  it('decrements the counter', async() => {
    // NOTE: The below uses Enzyme and Chai expectation helpers

    wrapper = mount(<MyCoolButton initialCounter={99} />);

    // Click the button
    wrapper.find(`.cool-button`).first().simulate('click');

    // Check for decrmented value
    const body = wrapper.find('.container span');
    expect(body).to.have.text('Counter value is: 98');
  });
});

Проблема заключается в том, что щелчок и последующее обновление state выполняются асинхронно, поэтому мы проверяем на наличие сбоев, прежде чем он сможет даже обновить компонент с ошибкой.

Многие примеры в Интернете, похоже, подсказывают async / await, что я не очень хорошо понимаю. Похоже, что await принимает Promise в качестве аргумента, но в моем случае я имитирую щелчок, который дополнительно вызывает обработчик, который возвращает Promise, поэтому я не могу await на этом топоре ios Promise для непосредственного завершения.

Какова лучшая практика тестирования здесь?

Спасибо!

Ответы [ 2 ]

1 голос
/ 21 апреля 2020

Я думаю, что сработает следующее:

describe('an error occurred while updating', () => {
  beforeEach(() => {});

    it('decrements the counter', async () => {
      const promise = Promise.reject('boo');
      axios.patch.mockImplementationOnce(() => promise);
      const wrapper = mount(
        <MyCoolButton initialCounter={99} />
      );

      // Click the button
      wrapper.find(`.cool-button`).first().simulate('click');
      //do catch().then to make sure test executes after
      //  component caught the rejection.
      return promise.catch(x=>x).then(() => {
        // Check for decrmented value
        const body = wrapper.find('.container span');
        expect(body).to.have.text('Counter value is: 98');
      });
    });
});

Здесь некоторые асин c примеры для jest

0 голосов
/ 21 апреля 2020

Вам необходимо смонтировать компонент и смоделировать событие щелчка, прежде чем сделать утверждение:

describe("an error occurred while updating", () => {
  let wrapper;

  beforeEach(() => {
    axios.patch.mockRejectedValue("Mock error message");
    wrapper = mount(<MyCoolButton initialCounter={99} />);
    wrapper.find(".cool-button").simulate("click");
  });

  it("decrements the counter", () => {
    expect(wrapper.find(".container span").text()).toEqual(
      "Counter value is: 98"
    );
  });
});
...