当使用假计时器和promise的组合时,我在让Jest测试框架(版本23.2.0)很好地工作时遇到了一点麻烦。我哪里做错了?
假设我有以下模块:
// timing.js
export const timeout = ms =>
new Promise(resolve => {
setTimeout(resolve, ms)
})
我的测试文件看起来像:
// timing.test.js
import { timeout } from './timing'
describe('timeout()', () => {
beforeEach(() => {
jest.useFakeTimers()
})
it('resolves in a given amount of time', () => {
const spy = jest.fn()
timeout(100).then(spy)
expect(spy).not.toHaveBeenCalled()
jest.advanceTimersByTime(100)
expect(spy).toHaveBeenCalled()
})
})
此操作失败,输出如下:
● timeout › resolves in a given amount of time
expect(jest.fn()).toHaveBeenCalled()
Expected mock function to have been called, but it was not called.
15 |
16 | jest.advanceTimersByTime(100)
> 17 | expect(spy).toHaveBeenCalled()
| ^
18 | })
19 | })
20 |
at Object.<anonymous> (src/timing.test.js:17:17)
但是,如果我删除promise:
// timing.js
export const timeout = ms => ({
then: resolve => {
setTimeout(resolve, ms)
}
})
。。。测试就会通过
timeout
✓ resolves in a given amount of time (5ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.304s
更新
虽然这不是最优雅的解决方案,但我目前正在使用下面的测试。它工作,但我仍然好奇为什么原来的一个没有
import { timeout } from './timing'
describe('timeout', () => {
it('resolves in a given amount of time', done => {
setTimeout(() => done(new Error('it didn\'t resolve or took longer than expected')), 10)
return timeout(9).then(done)
})
})
4条答案
按热度按时间dkqlctbz1#
目前最好的替代方案是使用异步版本的假定时器。所以你会
而不是调用
clock.tick
。请参阅the answer below了解更多详情。暂不支持
你没有做错什么-它现在不工作-抱歉。在我们这一方开始工作之前,必须发生以下事情:
advanceTimeByTime(100)
的事情,并使其与promise一起工作。问题是
.then(spy)
只会在以后被调用。由于我们是志愿者,这些事情没有具体的时间轴。我希望SimenB在未来的2-3个月内完成合并,我将在下个月与V8团队跟进。
你现在能做什么
你可以编写一个异步测试:
如果有其他需要等待的内容,您可以在超时后添加期望。
toe950272#
从
jest@26.0.0
开始,您可以在两种不同的伪计时器实现之间进行选择。我发现
jest.useFakeTimers('legacy')
可以使用theflushPromises
workaround与Promises一起工作,但不能与Date
一起工作,而jest.useFakeTimers('modern')
可以与Date
一起工作,但不能与Promises一起工作,因为await flushPromises()
永远不会解析。我发现最好的解决方案是使用
@sinonjs/fake-timers
,因为它可以同时使用Promises和Date
,而没有任何变通方法或黑客:mqxuamgl3#
在我的例子中,计时器回调调用了其他异步函数,所以其他解决方案对我不起作用。我最终发现,通过手动确保promise队列为空,所有的异步代码都将完成运行,我可以让测试工作:
v2g6jxz64#
我想我会添加一个更新的答案,只依赖于Jest,因为在2023年3月6日,Jest在29.5版本中公开了异步API!
这意味着Ben提到使用
@sinonjs/fake-timers
的tickAsync(ms)
的答案现在可以直接在Jest中使用: