组件发出 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
它。
我正在调用内部服务器以返回任何数据,为了模拟这个我正在使用 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
它。