酶:在模拟 "click" 时,测试异步更改的状态值
Enzyme: on simulating "click", test asynchronously changed state value
我正在尝试测试一个 state
值(例如:state.name
),它会在单击按钮时异步更改。
最初
state.name
是"Random Value"
- 单击 按钮时
state.name
从 "Random Value"
[= 更改为 "peter"
55=]
- 在浏览器中按预期工作
- 需要它在我的测试
中的button.simulate('click')
上工作相同
我的组件App.js
:
import React, { Component } from 'react';
class App extends Component {
state = {name: "Random Value"};
render() {
return (
<div className="App">
<div>{this.state.name}</div>
<button onClick={this.handleClick}>GetData</button>
</div>
);
}
handleClick = () => {
const currentContext = this;
fetch('http://api-call/getdata')
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
// jsonData.name = "peter"
currentContext.setState({name: jsonData.name});
})
}
}
export default App;
测试文件App.test.js
describe('<App/>', () => {
it('should handle click correctly', () => {
const wrapper = shallow(<App />);
expect(wrapper.find('button').length).toBe(1);
expect(wrapper.state().name).toEqual("Random Value");
wrapper.find('button').simulate('click');
expect(wrapper.update().state().name).toEqual("peter");
});
});
结果:
// FAILED!
Expected value to equal:
"peter"
Received:
"Random Value"
我还尝试了什么?
各种各样的解决方案,比如使用 async await
、setImmediate
然后 wrapper.update()
和许多其他东西。也许我做错了什么或错过了什么。无论如何,我已经花了一个晚上试图做到这一点。我需要 enzyme
专家的帮助。
谢谢
首先你需要以某种方式模拟 fetch
。发送真实请求不仅打破了单元测试的隔离,还增加了不一致的风险。当您不知道什么时候可以完成时,等待响应也更难。有不同的方法可以实现这一目标。 jest-fetch-mock
就是其中之一。
此外,我建议您不要检查 state
,而是检查 render()
结果。
function getName(wrapper) {
return wrapper.find('.App > div').at(0).props().children;
}
it('should handle click correctly', async () => {
fetch.mockResponseOnce(JSON.stringify({ name: '12345' }));
const wrapper = shallow(<App />);
expect(wrapper.find('button').length).toBe(1);
expect(getName(wrapper)).toEqual("Random Value");
wrapper.find('button').simulate('click');
await Promise.resolve();
expect(getName(wrapper)).toEqual("peter");
});
这是怎么回事。 await Promise.resolve()
只是等待,直到所有已经解决的承诺都是 运行。这意味着如果没有,我们的模拟响应将不会在按钮单击和 expect
运行 之间 运行。
另一种获得积极结果的方法是 handleClick()
向 return 承诺我们可以等待:
...
handleClick = () => {
const currentContext = this;
return fetch('http://api-call/getdata')
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
// jsonData.name = "peter"
currentContext.setState({name: jsonData.name});
})
}
....
it('should handle click correctly', async () => {
....
expect(getName(wrapper)).toEqual("Random Value");
await wrapper.find('button').simulate('click');
expect(getName(wrapper)).toEqual("peter");
});
或没有异步等待语法:
it('should handle click correctly', () => {
....
expect(getName(wrapper)).toEqual("Random Value");
return wrapper.find('button').simulate('click').then(() => {
expect(getName(wrapper)).toEqual("peter");
});
});
但我真的不喜欢这种方式,因为事件处理程序必须 return 它通常不会做的承诺。
更多关于 microtasks(Promises)/macrotasks(timers, events) 你可以在这里阅读:https://abc.danch.me/microtasks-macrotasks-more-on-the-event-loop-881557d7af6f
更多关于在玩笑中测试异步代码的信息,你最好查看他们的文档:https://jestjs.io/docs/en/asynchronous
我正在尝试测试一个 state
值(例如:state.name
),它会在单击按钮时异步更改。
最初
state.name
是"Random Value"
- 单击 按钮时
state.name
从"Random Value"
[= 更改为"peter"
55=] - 在浏览器中按预期工作
- 需要它在我的测试 中的
button.simulate('click')
上工作相同
我的组件App.js
:
import React, { Component } from 'react';
class App extends Component {
state = {name: "Random Value"};
render() {
return (
<div className="App">
<div>{this.state.name}</div>
<button onClick={this.handleClick}>GetData</button>
</div>
);
}
handleClick = () => {
const currentContext = this;
fetch('http://api-call/getdata')
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
// jsonData.name = "peter"
currentContext.setState({name: jsonData.name});
})
}
}
export default App;
测试文件App.test.js
describe('<App/>', () => {
it('should handle click correctly', () => {
const wrapper = shallow(<App />);
expect(wrapper.find('button').length).toBe(1);
expect(wrapper.state().name).toEqual("Random Value");
wrapper.find('button').simulate('click');
expect(wrapper.update().state().name).toEqual("peter");
});
});
结果:
// FAILED!
Expected value to equal:
"peter"
Received:
"Random Value"
我还尝试了什么?
各种各样的解决方案,比如使用 async await
、setImmediate
然后 wrapper.update()
和许多其他东西。也许我做错了什么或错过了什么。无论如何,我已经花了一个晚上试图做到这一点。我需要 enzyme
专家的帮助。
谢谢
首先你需要以某种方式模拟 fetch
。发送真实请求不仅打破了单元测试的隔离,还增加了不一致的风险。当您不知道什么时候可以完成时,等待响应也更难。有不同的方法可以实现这一目标。 jest-fetch-mock
就是其中之一。
此外,我建议您不要检查 state
,而是检查 render()
结果。
function getName(wrapper) {
return wrapper.find('.App > div').at(0).props().children;
}
it('should handle click correctly', async () => {
fetch.mockResponseOnce(JSON.stringify({ name: '12345' }));
const wrapper = shallow(<App />);
expect(wrapper.find('button').length).toBe(1);
expect(getName(wrapper)).toEqual("Random Value");
wrapper.find('button').simulate('click');
await Promise.resolve();
expect(getName(wrapper)).toEqual("peter");
});
这是怎么回事。 await Promise.resolve()
只是等待,直到所有已经解决的承诺都是 运行。这意味着如果没有,我们的模拟响应将不会在按钮单击和 expect
运行 之间 运行。
另一种获得积极结果的方法是 handleClick()
向 return 承诺我们可以等待:
...
handleClick = () => {
const currentContext = this;
return fetch('http://api-call/getdata')
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
// jsonData.name = "peter"
currentContext.setState({name: jsonData.name});
})
}
....
it('should handle click correctly', async () => {
....
expect(getName(wrapper)).toEqual("Random Value");
await wrapper.find('button').simulate('click');
expect(getName(wrapper)).toEqual("peter");
});
或没有异步等待语法:
it('should handle click correctly', () => {
....
expect(getName(wrapper)).toEqual("Random Value");
return wrapper.find('button').simulate('click').then(() => {
expect(getName(wrapper)).toEqual("peter");
});
});
但我真的不喜欢这种方式,因为事件处理程序必须 return 它通常不会做的承诺。
更多关于 microtasks(Promises)/macrotasks(timers, events) 你可以在这里阅读:https://abc.danch.me/microtasks-macrotasks-more-on-the-event-loop-881557d7af6f
更多关于在玩笑中测试异步代码的信息,你最好查看他们的文档:https://jestjs.io/docs/en/asynchronous