等待开玩笑不会等待设置超时,无论多长时间



我正在使用Formik创建一个React web应用程序的表单。提交如下代码:

const submitForm = (values) => {
console.log(JSON.stringify(values, null, 2));
setFormStatus(status.loading);
// handle request.
axios
.put("#", values)
.then(() => {
console.log("Submission Success");
setFormStatus(status.success);
})
.catch(() => {
console.log(`Submission Failure`);
setFormStatus(status.failure);
})
.then(() => {
console.log("Submission CleanUp");
setTimeout(() => {
console.log("Neutralizing Form");
setFormStatus(status.neutral);
// tell to animate.
setSwitchSubmitBtn(!switchSubmitBtn);
}, 2000);
});
};

在轴请求后,在我将status状态设置回中性之前,将有2s延迟。

但是,我使用Jest进行测试。,waitFor不像预期的那样工作。提交的超时似乎被阻塞了,因为无论我等待多长时间的提交,它都不会发生。我通过使用jest.advanceTimer找到了解决方案,但在waitFor中添加相同数量的延迟不起作用。
it("INPUT_FORM_TC_008", async () => {
jest.useFakeTimers();
render(<InputForm />);
axios.put.mockImplementation(async () => {
console.log("MOCKED PUT");
return Promise.reject();
});
// click submit Button
user.click(screen.getByTestId("submitBtn"));
await waitFor(() => {
expect(screen.queryByTestId("crossIcon")).not.toBeNull();
});
act(() => {
jest.advanceTimersByTime(2000);
});
await waitFor(() => {
// crossIcon will be unmounted once `status` changes to neutral.
expect(screen.queryByTestId("crossIcon")).toBeNull();
});
});

如果我不使用jest.advanceTimer,下面的代码将无法工作,即使我设置的超时时间比提交的要长得多。

await waitFor(() => {
expect(screen.queryByTestId("crossIcon")).toBeNull();
}, 5000);

我怀疑这是有关事件循环的东西,但我试图设置超时为20ms在提交和它的工作。所以我在寻找为什么会发生这种情况的原因。

我尝试使用Jest使用setTimeOut测试状态更改。我希望在setTimeOut中指定的时间之后,状态应该改变。但是使用waitFor即使设置更长的超时也不能工作。

问题是您正在立即退出的作用域中设置setTimeout。由于函数的闭包,这段代码在实际运行时应该仍然可以工作,但是在Jest中,测试会说,"好吧,看起来没有更多的同步代码了";并在等待执行前完成测试。

如果你想了解更多关于setTimeout为什么会这样做的信息,你可以查看MDN的文章:https://developer.mozilla.org/en-US/docs/Web/API/setTimeout

简单来说,它使用了"事件循环"这就是JS处理异步代码的方式,同时仍然是一种同步语言。当你使用setTimeout时,你只是简单地将函数执行添加到事件循环中,并说,"现在不要执行这段代码,运行其他代码,直到2000毫秒过去,然后运行这段代码。"这在你的实现中很好,因为你允许2000ms过去。但是Jest不会等待,它只是说"没有更多的代码要执行,事件循环中没有准备好的东西,测试必须完成";并立即清理一切。

你可以通过在承诺中包装setTimeout来解决这个问题,比如:

//........
.then(() => {
console.log("Submission CleanUp");
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Neutralizing Form");
resolve(status.neutral);
}, 2000);
})
});

然后让你的实际实现代码等待promise解析,并在promise解析后设置formStatus和submissionButton状态。这将是一个更简单的API,将允许更大的抽象,并且将使测试更容易,因为您现在可以在测试中等待此执行以.then()块完成。

相关内容

  • 没有找到相关文章

最新更新