Jest - 如何模拟网络延迟

And*_*ndy 1 asynchronous jestjs jest-fetch-mock

我正在尝试在 Jest 中模拟慢速网络(使用 React 测试库)。我试图设置的条件是这样的:

  1. UI 处于特定状态
  2. 异步 AJAX 请求被触发
  3. 用户界面改变状态
  4. 异步请求完成

在我看来,这是一个相当常见的要求,因为使用异步编程,您必须了解 AJAX 请求发送和完成之间可能发生的情况。但是,我根本找不到该领域的任何讨论或工具。

And*_*ndy 5

这个回复非常具体于react-testing-libaray,但我认为这个概念是普遍适用的。

首先,我意识到,如果您启动异步操作来响应用户事件(例如单击),那么您就不会遇到问题 - 一旦您调用了fireEvent.click,您就处于状态 3,然后您可以使用waitFor()等到你到达状态 4。

其次,如果您的环境为您提供了异步操作承诺的句柄,那么您当然可以等待,这样您就不会再遇到问题了。

就我而言,异步操作是由计时器触发的,因为它位于反应组件内部,所以我从外部获得了该计时器的句柄。所以我的场景是这样的:

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>
}
Run Code Online (Sandbox Code Playgroud)

组件状态最初为“初始”,安装后 5 秒,它会触发长时间运行的操作并将状态设置为“正在加载”,然后当它收到响应时,它将状态设置为该响应的文本。我的测试用例如下所示:

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() });
});
Run Code Online (Sandbox Code Playgroud)

我们使用一个在 2 秒延迟后返回“成功”的函数来伪造长时间运行的操作。4 秒后,我们期望状态仍为“初始”,再过 2 秒后,我们期望状态为“正在加载”,再过 2 秒后,我们期望状态为“成功”。我们使用开玩笑的假计时器,因此测试实际上不需要 8 秒来运行。

希望这对尝试做类似事情的其他人有所帮助。