我试图了解Jest的异步测试。
我的模块有一个函数,它接受一个布尔值并返回一个值的Promise。执行器函数调用setTimeout
,并且在超时回调中,promise根据最初提供的布尔值来解析或拒绝。代码如下所示:
const withPromises = (passes) => new Promise((resolve, reject) => {
const act = () => {
console.log(`in the timout callback, passed ${passes}`)
if(passes) resolve('something')
else reject(new Error('nothing'))
}
console.log('in the promise definition')
setTimeout(act, 50)
})
export default { withPromises }
我想用Jest测试一下。我想我需要使用Jest提供的模拟定时器,所以我的测试脚本看起来有点像这样:
import { withPromises } from './request_something'
jest.useFakeTimers()
describe('using a promise and mock timers', () => {
afterAll(() => {
jest.runAllTimers()
})
test('gets a value, if conditions favor', () => {
expect.assertions(1)
return withPromises(true)
.then(resolved => {
expect(resolved).toBe('something')
})
})
})
我收到以下错误/失败的测试,无论我是否致电jest.runAllTimers()
Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
你能解释一下我出错的地方以及我可以采取什么措施来获得承诺按预期解决的通过测试?
答案 0 :(得分:9)
对jest.useFakeTimers()
的调用会使用必须控制的定时器函数来模拟每个定时器功能。您可以手动前进,而不是自动运行计时器。 jest.runTimersToTime(msToRun)
函数会将其提前msToRun
毫秒。在每个计时器都已经过去之前你想要快进是很常见的,计算所有计时器完成所需的时间会很麻烦,所以Jest提供了jest.runAllTimers()
,它假装足够时间过去了。
测试中的问题是你从不在测试中调用jest.runAllTimers()
,而是在afterAll
钩子中调用它,在测试完成后称为 。在测试期间,计时器保持为零,因此您的回调从未被实际调用过,并且Jest在预定义的时间间隔(默认值:5秒)后中止它,以防止陷入潜在的无限测试。只有在测试超时后,才会调用jest.runAllTimers()
,此时它不会执行任何操作,因为所有测试都已完成。
您需要做的是启动承诺,然后推进计时器。
describe('using a promise and mock timers', () => {
test('gets a value, if conditions favor', () => {
expect.assertions(1)
// Keep a reference to the pending promise.
const pendingPromise = withPromises(true)
.then(resolved => {
expect(resolved).toBe('something')
})
// Activate the timer (pretend the specified time has elapsed).
jest.runAllTimers()
// Return the promise, so Jest waits for its completion and fails the
// test when the promise is rejected.
return pendingPromise
})
})