clearTimeout 测试不适用于 jest.useFakeTimers()

clearTimeout test not working with jest.useFakeTimers()

我正在尝试迁移到 jest.useFakeTimers() 的“现代”版本,这不是 27.x.
版本的默认版本 我的测试有一些问题,因为 Jest 一直说像 clearTimeoutsetInterval 这样的函数不是开玩笑的模拟:

// Poster.ts
// This is the class method I'm testing

startInterval(interval = 1800000) {
  this._interval && clearTimeout(this._interval)

  this._interval = (setInterval(
    () =>
      this.post()
        .then((result) => {
          this.runHandlers('autopostSuccess', result)
          return result
        })
        .catch((error) => this.runHandlers('autopostFail', error)),
    interval
  ) as unknown) as number
  return this._interval
}
// Poster.test.ts
describe('startInterval method', () => {
  const p = new Poster({ client: {} })
  beforeEach(() => {
    jest.useFakeTimers()
  })
  afterEach(() => {
    jest.useRealTimers()
  })

  it('should call clearTimeout (but only from the second use)', () => {
    const firstID = p.startInterval()
    expect(clearTimeout).not.toHaveBeenCalled() // This line fails with the following error
    p.startInterval()
    expect(clearTimeout).toHaveBeenCalledTimes(1)
    expect(clearTimeout).toHaveBeenLastCalledWith(firstID)
  })

  // ...
})

错误:

expect(received).not.toHaveBeenCalled()

Matcher error: received value must be a mock or spy function

所以,它抱怨 clearTimeout 不是模拟,即使我使用 jest.useFakeTimers()

版本:

我确定我在这里遗漏了一些东西,也许我以错误的方式使用了 useFakeTimers,但是 method docs nor the page on Timer Mocks 都没有帮助我。

有人知道为什么我的测试不起作用吗?

经过一番挖掘,我找到了很有希望的正确方法。

答案在此 issue 讨论中。

Jest added spies to the fake timers automatically. We no longer do that, people need to do e.g. jest.spyOn(global, 'setTimeout') themselves.

这对我有用。只需添加 jest.spyOn(global, 'clearTimeout') 即可。也许您甚至不需要 jest.useFakeTimers() 语句。