使用带有Jest的setTimeout测试Promise

Sim*_*ell 10 javascript testing asynchronous jestjs

我正在尝试了解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 }
Run Code Online (Sandbox Code Playgroud)

我想用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')
            })
    })
})
Run Code Online (Sandbox Code Playgroud)

我得到以下错误/失败的测试,无论我是否打电话 jest.runAllTimers()

Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
Run Code Online (Sandbox Code Playgroud)

你能解释一下我出错的地方以及我可以采取什么措施来获得通过预期解决的承诺?

Mic*_*ngo 13

调用jest.useFakeTimers()每个定时器函数的模拟,你必须控制一个.您可以手动前进,而不是自动运行计时器.该jest.runTimersToTime(msToRun)函数将提前msToRun几毫秒.你想要快速前进直到每个计时器都过去是很常见的,计算所有计时器完成所需的时间是很麻烦的,所以Jest提供了jest.runAllTimers()假装已经过去的时间.

您的测试中的问题是您从未调用jest.runAllTimers()过测试,但是您在afterAll钩子中调用它,在测试完成调用它.在测试期间,计时器保持为零,因此您的回调从未被实际调用过,并且Jest在预定义的时间间隔(默认值:5s)后中止它,以防止陷入潜在的无限测试.只有在测试超时后,才会调用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
    })
})
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案!是否可以使用 async/await 语法编写此测试? (2认同)