【发布时间】:2017-08-22 03:00:11
【问题描述】:
在我的 create-react-app 中,我正在尝试测试一个组件,该组件在安装时会执行多个 setStates。
class MyComponent extends React.Component {
state = {
a: undefined,
b: undefined,
c: undefined,
};
fetchA() {
// returns a promise
}
fetchB() {
// returns a promise
}
fetchC() {
// returns a promise
}
async componentDidMount() {
const a = await fetchA();
this.setState({ a });
}
async componentDidUpdate(prevProps, prevState) {
if (prevState.a !== this.state.a) {
const [b, c] = await Promise.all([
this.fetchB(a);
this.fetchC(a);
]);
this.setState({ b, c });
}
}
...
}
在我的测试中,我做了这样的事情,试图让componentDidUpdate中的setState在做出断言之前完成。
import { mount } from 'enzyme';
describe('MyComponent', () => {
const fakeA = Promise.resolve('a');
const fakeB = Promise.resolve('b');
const fakeC = Promise.resolve('c');
MyComponent.prototype.fetchA = jest.fn(() => fakeA);
MyComponent.prototype.fetchB = jest.fn(() => fakeB);
MyComponent.prototype.fetchC = jest.fn(() => fakeC);
it('sets needed state', async () => {
const wrapper = mount(<MyComponent />);
await Promise.all([ fakeA, fakeB, fakeC ]);
expect(wrapper.state()).toEqual({
a: 'a',
b: 'b',
c: 'c',
});
});
});
这是有趣的部分:我上面的测试将失败,因为在作出断言时最后一次 setState 调用(在 componentDidUpdate 中)尚未完成。当时设置了state.a,但是还没有设置state.b和state.c。
我可以使它工作的唯一方法是在断言之前将await Promise.resolve(null) 楔入,以使最后一个setState 完成额外的滴答声/周期。这看起来太老套了。
我尝试过的另一件事是将断言包装在setImmediate() 中,只要断言通过,它就可以正常工作。如果失败,它将因为未捕获的错误而终止整个测试。
有人解决过这个问题吗?
【问题讨论】:
-
如果将
Promise.all语句替换为两个语句,例如const b = await this.fetchB(a) ...,它会起作用吗?或者模拟Promise.all。我的猜测是,这个问题是你在那里创建的承诺,开玩笑不知道。 -
你是指组件中的
Promise.all还是测试中的Promise.all?如果它在测试中,我很确定我确认 jest 等待所有三个完成。但是,只要 3 个 Promise 完成,测试就会恢复,而无需等待componentDidUpdate中的最后一个setState完成。不管怎样,我会试着按照你说的去做。 -
这个问题你解决了吗?
-
是的。看看我在下面发布的答案。
标签: reactjs unit-testing asynchronous jestjs enzyme