[英]TypeError: dispatch is not a function when I try to test a method using JEST
[英]jest.advanceTimersByTime doesn't work when I try to test my retry util function
我有一个我想测试的重试工具 function。 看起来像这样
export const sleep = (t: number) => new Promise((r) => setTimeout(r, t));
type RetryFn = (
fn: Function,
config: {
retryIntervel: number;
retryTimeout: number;
predicate: Function;
onRetrySuccess?: Function;
onRetryFail?: Function;
}
) => Promise<any>;
export const retry: RetryFn = async (
fn,
{ predicate, onRetrySuccess, onRetryFail, retryIntervel, retryTimeout }
) => {
const startTime = Date.now();
let retryCount = 0;
while (Date.now() - startTime < retryTimeout) {
try {
const ret = await fn();
if (predicate(ret)) {
if (retryCount > 0) onRetrySuccess && onRetrySuccess();
return ret;
} else {
throw new Error();
}
} catch {
retryCount++;
}
await sleep(retryIntervel);
}
if (onRetryFail) onRetryFail();
};
它所做的是在给定的时间间隔内重试 function 一段时间。
我想我可以使用jest.advanceTimersByTime
来提前计时器来测试重试发生了多少次。
import { retry } from "./index";
const value = Symbol("test");
function mockFnFactory(numFailure: number, fn: Function) {
let numCalls = 0;
return function () {
fn();
numCalls++;
if (numCalls <= numFailure) {
console.log("numCalls <= numFailure");
return Promise.resolve({ payload: null });
} else {
console.log("numCalls => numFailure");
return Promise.resolve({
payload: value
});
}
};
}
describe("retry function", () => {
beforeEach(() => {
jest.useFakeTimers();
});
it("retrys function on 1st attempt, and succeed thereafter", async () => {
const fn = jest.fn();
const onRetrySuccessFn = jest.fn();
const mockFn = mockFnFactory(3, fn);
retry(mockFn, {
predicate: (res: any) => res.payload === value,
onRetrySuccess: onRetrySuccessFn,
retryIntervel: 1000,
retryTimeout: 5 * 60 * 1000
});
jest.advanceTimersByTime(1000);
expect(fn).toHaveBeenCalledTimes(1);
expect(onRetrySuccessFn).not.toHaveBeenCalled();
jest.advanceTimersByTime(1000);
expect(fn).toHaveBeenCalledTimes(2); // 🚨 fail
expect(onRetrySuccessFn).not.toHaveBeenCalled();
jest.advanceTimersByTime(2000);
expect(fn).toHaveBeenCalledTimes(3);// 🚨 fail
expect(onRetrySuccessFn).toHaveBeenCalledTimes(1);
});
});
但似乎无论我将计时器提前多少,function 都只会被调用一次。
您可以在https://codesandbox.io/s/lucid-knuth-e810e?file=/src/index.test.ts找到代码沙盒上的代码
但是,codesandbox 存在一个已知问题,它不断抛出此错误TypeError: jest.advanceTimersByTime is not a function
。 此错误不会出现在本地。
就是因为这个。
这是我在测试助手文件中使用的内容:
const tick = () => new Promise(res => setImmediate(res));
export const advanceTimersByTime = async time => jest.advanceTimersByTime(time) && (await tick());
export const runOnlyPendingTimers = async () => jest.runOnlyPendingTimers() && (await tick());
export const runAllTimers = async () => jest.runAllTimers() && (await tick());
在我的测试文件中,我导入了我的助手,而不是调用jest.advanceTimersByTime
,我await
我的advanceTimersByTime
function。
在您的具体示例中,您只需要在调用 AdvanceTimersByTime 后await
advanceTimersByTime
- 如下所示:
// top of your test file
const tick = () => new Promise(res => setImmediate(res));
... the rest of your existing test file
jest.advanceTimersByTime(1000);
expect(fn).toHaveBeenCalledTimes(1);
expect(onRetrySuccessFn).not.toHaveBeenCalled();
jest.advanceTimersByTime(1000);
await tick(); // this line
expect(fn).toHaveBeenCalledTimes(2);
expect(onRetrySuccessFn).not.toHaveBeenCalled();
jest.advanceTimersByTime(2000);
await tick(); // this line
expect(fn).toHaveBeenCalledTimes(3)
expect(onRetrySuccessFn).toHaveBeenCalledTimes(1);
我有点晚了,但我今天必须解决这个问题,我通过制作这个新的实用程序 function 解决了这个问题。
// So we can wait setTimeout loops
export const advanceTimersByNTimes = (n = 1, time = 1000) => {
for (let i = 0; i < n; i++) {
act(() => {
jest.advanceTimersByTime(time * 1);
});
}
};
这就是我在测试中使用它的方式:
await waitFor(() => {
expect(screen.queryByTestId("timeout-exceeded-container")).toBeNull();
});
advanceTimersByNTimes(11);
await waitFor(() => {
expect(screen.queryByTestId("timeout-exceeded-container")).not.toBeNull();
});
没有其他东西对我有用,包括这里的答案。
这是我的代码中没有上述技巧就无法工作的部分(供参考):
setTimeout(() => setSeconds((prev) => prev + 1), 1000);
无论我将 jest.advanceTimersByTime 设置为什么,它都会步进到 2 倍,这些调用需要包装在act
块中才能计数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.