在
componentDidMount
实例的 React.Component
中,我有一个 fetch()
调用,该调用响应调用 setState
。
我可以模拟请求并使用
sinon
进行响应,但我不知道 fetch 何时会解决它的承诺链。
componentDidMount() {
fetch(new Request('/blah'))
.then((response) => {
setState(() => {
return newState;
};
});
}
在我的测试中使用
jest
和 enzyme
:
it('has new behaviour from result of set state', () => {
let component = mount(<Component />);
requests.pop().respond(200);
component.update() // fetch() has not responded yet and
// thus setState has not been called yet
// so does nothing
assertNewBehaviour(); // fails
// now setState occurs after fetch() responds sometime after
});
我需要刷新 Promise 队列/回调队列或类似的东西吗?我可以对 newBehaviour 进行超时重复检查,但这不太理想。
最好的答案似乎是使用容器模式,并从具有分离关注点的容器类传递 API 数据,并分别测试组件。这使得被测组件可以简单地将 API 数据作为 props,并使其更具可测试性。
由于您没有进行任何真正的 api 调用或其他耗时的操作,因此异步操作将在可预测的短时间内解决。
因此您只需稍等片刻即可。
it('has new behaviour from result of set state', (done) => {
let component = mount(<Component />);
requests.pop().respond(200);
setTimeout(() => {
try {
component.update();
assertNewBehaviour();
done();
} catch (error) {
done(error);
}
}, 1000);
});
React 测试库有一个
waitFor
功能,非常适合这种情况。
我将给出一个带有钩子和函数的示例,因为这是当前的反应模式。假设您有一个与此类似的组件:
export function TestingComponent(props: Props) {
const [banners, setBanners] = useState<MyType>([]);
React.useEffect(() => {
const response = await get("/...");
setBanners(response.banners);
}, []);
return (
{banners.length > 0 ? <Component> : </NoComponent>}
);
}
现在您可以编写这样的测试,以确保设置横幅时
Component
被渲染
test("when the banner matches the url it renders", async () => {
const {container} = render(<TestingComponent />);
await waitFor(() => {expect(...).toBe(...)});
});
waitFor
将等待函数中的条件满足后再继续。有一个超时,如果在 X 时间内不满足条件,测试就会失败。 查看 React 测试库文档以获取更多信息