使用setTimeout和Jest测试Promise

8yparm6h  于 2023-09-28  发布在  Jest
关注(0)|答案(2)|浏览(141)

我正在尝试理解Jest的异步测试。
我的模块有一个函数,它接受一个布尔值并返回一个值的Promise。executer函数调用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.

你能解释一下我哪里出错了吗?我可以做些什么来获得一个通过测试,让promise按预期解决?

gj3fmq9x

gj3fmq9x1#

jest.useFakeTimers()的调用将每个计时器函数模拟为您必须控制的函数。您可以手动将计时器提前,而不是自动运行计时器。jest.runTimersToTime(msToRun)函数将其提前msToRun毫秒。很常见的情况是,您希望快进到每个计时器都已经过去,计算所有计时器完成所需的时间会很麻烦,因此Jest提供了jest.runAllTimers(),它假装已经过去了足够的时间。
测试中的问题是,您从未在测试中调用jest.runAllTimers(),而是在afterAll钩子中调用它,该钩子在测试完成后被调用。在测试过程中,计时器保持为零,因此实际上不会调用回调,Jest会在预定义的时间间隔(默认值:5s),以防止被潜在的无休止的测试卡住。只有在测试超时后,才调用jest.runAllTimers(),此时它不做任何事情,因为所有测试都已经完成。
你需要做的是启动promise,然后提前计时器。

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

p1iqtdky2#

所以,我遇到了一个类似的问题,我想用setTimeout()伪造一个异步函数--它返回一个promise。但是我一直得到一个Exceeded timeout...错误。
我在async await语法中修复它时遇到了一些问题。最后,我通过将const x = await ...分成两行并将jest.runAllTimers()放在它们之间来解决这个问题。(您也可以在相同的方法中使用jest.advanceTimersByTime())。
下面是一个完整的测试,我用settime伪造一个promise:

it('test promise with set timeout', async () => {
    jest.useFakeTimers();
    const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

    const asyncFunction = async () => {
        await sleep(100);
        return true;
    };

    const resultPromise = asyncFunction();

    jest.runAllTimers();

    const result = await resultPromise;

    expect(result).toBe(true);
    jest.useRealTimers();
});

PS.如果你有多个测试,你可能会更好地把useFakeTimersuseRealTimers放进beforeEachafterEach块。

相关问题