开玩笑:在setInterval内部等待可防止调用setTimeout

时间:2019-11-14 00:05:40

标签: javascript jestjs

我正在尝试用Jest模拟setInterval中的setTimeout,但是看到令人困惑的行为,并且我不知道它是否是错误,或者我做错了什么。

在传递给setInterval的异步函数内部等待将导致setTimeout永远不会运行。如果我在下面的函数中删除了await,则setTimeout成功设置。

jest.setTimeout(10000);

let interval;

/**
 * Check for a promise to return true before clearing an interval and setting a timeout
 * @param {boolean} shouldAwaitRes - toggle whether to await inside the async callback
 * @param {function} callback - mock function to call inside timeout
 */
const check = async (shouldAwaitRes, callback) => {
  const res = shouldAwaitRes ? await Promise.resolve(true) : Promise.resolve(true);

  if (res) {
    clearInterval(interval);

    setTimeout(() => {
      callback();
    }, 2000);
  }
};

/**
 * Set an interval with an async function that awaits a response
 * @param {boolean} shouldAwaitRes - toggle whether to await inside the async callback
 * @param {function} callback - mock function to pass into set timeout
 */
const setAsyncInterval = async (shouldAwaitRes, callback) => {
  interval = setInterval(check, 1000, shouldAwaitRes, callback);
};

/**
 * Wait 6 seconds for real timers to run
 */
const pause = async () => {
  return new Promise(resolve => {
    setTimeout(resolve, 6000);
  });
};

// ----------------------------------
// Tests

describe('Timers', () => {
  let callback;
  beforeEach(() => {
    callback = jest.fn();
  });

  afterEach(() => {
    jest.resetAllMocks();
  });

  describe('No Fake Timers Used', () => {
    it('should call the callback inside the async setInterval callback when awaiting', async done => {
      await setAsyncInterval(true, callback); // setting to true to await inside async callback

      // Pause 6 seconds to let the timers runs
      await pause();

      expect(callback).toBeCalled(); // callback is called

      done();
    });
  });

  describe('Fake Timers', () => {
    beforeEach(() => {
      jest.useFakeTimers();
    });

    afterEach(() => {
      jest.clearAllTimers();
    });

    it('should call the callback inside the async setInterval callback when NOT awaiting', async done => {
      await setAsyncInterval(false, callback); // setting to false to disable awaiting inside async callback

      // Advance Time 6 seconds
      jest.advanceTimersByTime(6000);

      expect(callback).toBeCalled(); // callback is called

      done();
    });

    // The below test fails
    it('should call the callback inside the async setInterval callback when awaiting', async done => {
      await setAsyncInterval(true, callback); // setting to true to enable awaiting inside async callback

      // Advance Time 6 seconds
      jest.advanceTimersByTime(6000);

      expect(callback).toBeCalled(); // callback is NOT called

      done();
    });
  });
});

还向Jest报告,看是否可能是错误:https://github.com/facebook/jest/issues/9181

编辑:更新了样本复制案例并添加了开玩笑

0 个答案:

没有答案