本文介绍了使用 setTimeout 和 Jest 测试 Promise的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解 Jest 的异步测试.

I'm trying to understand Jest's asynchronous testing.

我的模块有一个函数,它接受一个布尔值并返回一个值的 Promise.执行器函数调用 setTimeout,并且在超时回调中,promise 根据最初提供的布尔值来解析或拒绝.代码如下所示:

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:

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 提供的模拟计时器,所以我的测试脚本看起来有点像这样:

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:

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()

I get the following error/failed test, whether or not I call 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?

推荐答案

jest.useFakeTimers() 的调用使用您必须控制的一个来模拟每个计时器函数.您可以手动推进计时器,而不是自动运行计时器.jest.runTimersToTime(msT​​oRun) 函数会将它提前 msToRun 毫秒.您想要快进直到每个计时器都过去是很常见的,并且计算所有计时器完成所需的时间会很麻烦,因此 Jest 提供了 jest.runAllTimers(),它假装已经过去了足够的时间.

The call to jest.useFakeTimers() mocks every timer function with one that you must control. Instead of the timer running automatically, you would advance it manually. The jest.runTimersToTime(msToRun) function would advance it by msToRun milliseconds. 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.runAllTimers() ,而是在 afterAll 钩子中调用它,它被称为 after 测试完成.在您的测试期间,计时器保持为零,因此您的回调永远不会被实际调用,并且 Jest 在预定义的时间间隔(默认值:5 秒)后中止它,以防止被潜在的无休止的测试卡住.只有在测试超时后,您才调用 jest.runAllTimers(),此时它什么都不做,因为所有测试都已经完成.

The problem in your test is that you never call jest.runAllTimers() in the test, but you call it in the afterAll hook, which is called after the 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.

您需要做的是启动承诺,然后推进计时器.

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
    })
})

这篇关于使用 setTimeout 和 Jest 测试 Promise的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 04:31