当我尝试测试我的重试 util 函数时,jest.advanceTimersByTime 不起作用

Joj*_*oji 5 javascript unit-testing typescript jestjs

我有一个我想测试的重试 util 函数。看起来像这样

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();
};

Run Code Online (Sandbox Code Playgroud)

它的作用是在给定的时间间隔内重试该函数一段时间。

我想我可以使用jest.advanceTimersByTime提前计时器来测试重试发生的次数。

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();
};

Run Code Online (Sandbox Code Playgroud)

但似乎无论我将计时器提前多少,该函数都只会被调用一次。

您可以在codesandbox上找到代码:https://codesandbox.io/s/lucid-knuth-e810e ?file=/src/index.test.ts

但是, codesandbox有一个已知问题TypeError: jest.advanceTimersByTime is not a function,它会不断抛出此错误。该错误不会在本地出现。

Ada*_*dam 7

正是因为这个

这是我在测试助手文件中使用的内容:

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

在我的测试文件中,我导入了我的助手,而不是调用jest.advanceTimersByTime,而是调用await了我的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);


Run Code Online (Sandbox Code Playgroud)