javascript 使用 setTimeout 和 Jest 测试 Promise
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46710564/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Testing a Promise using setTimeout with Jest
提问by Simon Dell
I'm trying to understand Jest's asynchronous testing.
我试图了解 Jest 的异步测试。
My module has a function which accepts a boolean and returns a Promise of a value. The executer function calls setTimeout, and in the timed out callback the promise resolves or rejects depending on the boolean initially supplied. The code looks like this:
我的模块有一个函数,它接受一个布尔值并返回一个值的 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 }
I'd like to test this using Jest. I guess that I need to use the mock timers Jest provides, so my test script looks a bit like this:
我想用 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')
})
})
})
I get the following error/failed test, whether or not I call jest.runAllTimers()
我收到以下错误/失败的测试,无论我是否打电话 jest.runAllTimers()
Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
Can you explain where I'm going wrong and what I might do to get a passing test that the promise resolves as expected?
你能解释一下我哪里出错了,我可以做些什么来通过测试,承诺按预期解决吗?
回答by Michael Jungo
The call to jest.useFakeTimers()mocks every timer function with one that you mustcontrol. Instead of the timer running automatically, you would advance it manually. The jest.runTimersToTime(msToRun)function would advance it by msToRunmilliseconds. It's very common that you want to fast-forward until every timer has elapsed and it would be cumbersome to calculate the time it takes for all the timers to finish, so Jest provides jest.runAllTimers(), which pretends that enough time has passed.
对jest.useFakeTimers()每个计时器函数的调用都使用您必须控制的函数来模拟。您可以手动推进计时器,而不是自动运行计时器。该jest.runTimersToTime(msToRun)函数会将其提前msToRun几毫秒。您想要快进直到每个计时器都过去是很常见的,并且计算所有计时器完成所需的时间会很麻烦,因此 Jest 提供jest.runAllTimers(),它假装已经过去了足够的时间。
The problem in your test is that you never call jest.runAllTimers()in the test, but you call it in the afterAllhook, which is called afterthe tests have finished. During your test the timer remains at zero so your callback is never actually called and Jest aborts it after a predefined interval (default: 5s) to prevent being stuck with a potentially endless test. Only after the test has timed out, you call jest.runAllTimers(), at which point it doesn't do anything, since all tests have already finished.
测试中的问题是你从不调用jest.runAllTimers()测试,而是在afterAll钩子中调用它,在测试完成后调用它。在您的测试期间,计时器保持为零,因此您的回调永远不会被实际调用,并且 Jest 在预定义的时间间隔(默认值:5 秒)后中止它,以防止被潜在的无休止的测试卡住。只有在测试超时后,您才调用jest.runAllTimers(),此时它什么都不做,因为所有测试都已经完成。
What you need to do is launch the promise and then advance the timer.
您需要做的是启动承诺,然后提前计时器。
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
})
})

