我试图在Jest中模拟一个缓慢的网络(使用React测试库(。我试图设置的条件是这样的:
- UI处于特定状态
- 异步AJAX请求被触发
- ui更改状态
- 异步请求完成
在我看来,这将是一个非常常见的要求,因为使用异步编程,您必须了解在发送AJAX请求和完成请求之间可能发生的情况。然而,我在这方面根本找不到任何讨论或工具。
这个回复非常专门用于测试libaray,但我认为这个概念通常适用。
首先,我意识到,如果你启动异步操作来响应用户事件(比如点击(,那么你就没有问题——一旦你调用了fireEvent.click
,你就处于状态3,然后你可以使用waitFor()
等待,直到你进入状态4。
其次,如果您的环境为异步操作的promise提供了一个句柄,那么您当然可以等待它,这样您就不会有问题了。
在我的例子中,异步操作是由计时器触发的,因为它在react组件内部,所以我从外部获得了该计时器的句柄。所以我的场景是这样的:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { message: "initial" };
}
componentDidMount = () => setTimeout(async () => {
this.setState({ message: "loading" });
var message = await this.props.longRunningOperation();
this.setState({ message });
}, 5000);
render = () => <div>{this.state.message}</div>
}
组件状态最初是"0";初始";,在它安装后5秒,它启动长时间运行操作并将状态设置为"0";加载";,然后,当它得到响应时,它将状态设置为该响应的文本。我的测试用例如下:
test("long running response", async () => {
const fakeLongRunningOperation = async () => new Promise(resolve =>
setTimeout(() => resolve("success"), 2000));
jest.useFakeTimers();
var app = render(<App longRunningOperation={fakeLongRunningOperation} />);
jest.advanceTimersByTime(4000)
expect(app.queryByText("initial")).not.toBeNull();
jest.advanceTimersByTime(2000)
expect(app.queryByText("loading")).not.toBeNull();
jest.advanceTimersByTime(2000)
await waitFor(() => { expect(app.queryByText("success")).not.toBeNull() });
});
我们用一个函数来伪造长期运行的操作;成功;在2秒延迟之后。在4秒之后,我们期望状态仍然是"0";初始";,那么在另外2秒之后,我们期望它是"0";加载";再过2秒钟;成功";。我们使用了假定时器,这样测试实际上就不需要8秒的时间。
希望这能帮助其他试图做类似事情的人。