组件发出 axios 请求被挂载两次,以便异步测试通过,如果它在测试失败后被挂载。为什么

Component making axios request being mounted twice in order for asynchronous test to pass, if it is mounted once the test fails. WHY

我正在调用内部服务器以返回任何数据,为了模拟这个我正在使用 axios-mock-adapter 并发回一个包含 5 个东西的数组。我必须安装组件两次才能通过此测试。这是我的组件:

   import React, { Component, Fragment } from 'react'
   import axios from 'axios'

  export default class HelloWorld extends Component {
     constructor(props) {
       super(props)
       this.state = {
        goodbye: false,
        data: []
    }
}

async componentDidMount() {
    await this.func()
    console.log("RUNNING");
}

func = async () => {
    let data;
    try {
        data = await axios.get('http://localhost:8080');
    }
    catch(e) {
        console.log("ERROR");
        throw(e)
    }

    this.setState({data: data.data})

}

goodbye = () => {
    this.setState((state, currentProps) => ({...state, goodbye: !state.goodbye}))
}

render() {
    return (
        <Fragment>
            <h1>
                Hello World
            </h1>
            <button id="test-button" onClick={this.goodbye}>Say Goodbye</button>
            {
                !this.state.goodbye ? null :
                <h1 className="goodbye">GOODBYE WORLD</h1>
            }
        </Fragment>
    )
}

}

这是测试:

it('there is data being returned', async () => { 

    let mock = new MockAdapter(axios)
    const data = new Array(5).fill('Hello World')

    mock.onGet('http://localhost:8080').reply(200, data)

    const component =  await mount(<HelloWorld />) 


    //if this line below is commented out the test fails
    await component.instance().componentDidMount();

    expect(component.state('data')).toHaveLength(5)

})

不确定为什么我必须安装组件然后再次安装它。有人有什么想法吗?

通过放置一个 beforeEach 并将 done() 传递给它来解决它,如下所示:

 beforeEach( async (done) => {

    let mock = new MockAdapter(axios)
    const data = new Array(5).fill('Hello World')

    mock.onGet('http://localhost:8080'). reply(200, data)

    component =  await mount(<HelloWorld />)  

    done()
 })

模拟的 axios 响应是异步发生的,因此在事件循环的下一个滴答之前您不会得到响应。这一行:

await component.instance().componentDidMount();

在继续同步操作之前正在等待响应,这就是为什么它在那里时有效,而当您删除该行时无效的原因。还有一些其他解决方案可以使用 - 您可以用以下内容替换该行:

await Promise.resolve();

或者使用这样的辅助函数:

const wait = () => new Promise(resolve => setTimeout(resolve, 0));

并将您的 await component.instance().componentDidMount(); 替换为:

await wait();

其中任何一个都将等待事件循环的一个滴答声,这将允许模拟响应返回。您可能还需要在获取模拟数据后调用 component.update()。另一件事:mount(<HelloWorld />) 是同步的并且 return 不是一个承诺,所以不需要 await 它。