使用 Axios 和 Jest 在 React 中测试异步行为

考虑以下过度简化的 React 组件。当您单击该按钮时,它会对外部 URL 进行 API 调用。


如果成功,则递增计数器

如果不成功,则递减计数器

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需要 aPromise作为参数,但在我的情况下,我正在模拟点击,它进一步调用返回 a 的处理程序Promise,所以我不能await在那个 axiosPromise上直接完成。


这里测试的最佳实践是什么?


手掌心
浏览 137回答 2
2回答

忽然笑

我认为以下方法可以解决问题:describe('an error occurred while updating', () => {&nbsp; beforeEach(() => {});&nbsp; &nbsp; it('decrements the counter', async () => {&nbsp; &nbsp; &nbsp; const promise = Promise.reject('boo');&nbsp; &nbsp; &nbsp; axios.patch.mockImplementationOnce(() => promise);&nbsp; &nbsp; &nbsp; const wrapper = mount(&nbsp; &nbsp; &nbsp; &nbsp; <MyCoolButton initialCounter={99} />&nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; &nbsp; // Click the button&nbsp; &nbsp; &nbsp; wrapper.find(`.cool-button`).first().simulate('click');&nbsp; &nbsp; &nbsp; //do catch().then to make sure test executes after&nbsp; &nbsp; &nbsp; //&nbsp; component caught the rejection.&nbsp; &nbsp; &nbsp; return promise.catch(x=>x).then(() => {&nbsp; &nbsp; &nbsp; &nbsp; // Check for decrmented value&nbsp; &nbsp; &nbsp; &nbsp; const body = wrapper.find('.container span');&nbsp; &nbsp; &nbsp; &nbsp; expect(body).to.have.text('Counter value is: 98');&nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; });});以下是一些用于开玩笑的异步示例

莫回无

在进行断言之前,您需要挂载组件并模拟点击事件:describe("an error occurred while updating", () => {&nbsp; let wrapper;&nbsp; beforeEach(() => {&nbsp; &nbsp; axios.patch.mockRejectedValue("Mock error message");&nbsp; &nbsp; wrapper = mount(<MyCoolButton initialCounter={99} />);&nbsp; &nbsp; wrapper.find(".cool-button").simulate("click");&nbsp; });&nbsp; it("decrements the counter", () => {&nbsp; &nbsp; expect(wrapper.find(".container span").text()).toEqual(&nbsp; &nbsp; &nbsp; "Counter value is: 98"&nbsp; &nbsp; );&nbsp; });});
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript