web-dev-qa-db-ja.com

JestでsetTimeoutを使用してPromiseをテストする

私はジェストの非同期テストを理解しようとしています。

私のモジュールには、ブール値を受け入れ、値の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が解決するテストに合格するために何をすればよいのか説明できますか?

12
Simon Dell

jest.useFakeTimers()への呼び出しは、すべてのタイマー関数をあなたが作成したものでモックしますmust制御します。タイマーを自動的に実行する代わりに、手動で進めます。 jest.runTimersToTime(msToRun) 関数は、それをmsToRunミリ秒進めます。すべてのタイマーが経過するまで早送りすることは非常に一般的であり、すべてのタイマーが完了するまでにかかる時間を計算するのは面倒なので、Jestは jest.runAllTimers() を提供しています、十分な時間が経過したように見せかけます。

テストの問題は、テストではjest.runAllTimers()を呼び出さないが、afterAllフックで呼び出すafterテストが終了したことです。 。テスト中、タイマーはゼロのままなので、コールバックが実際に呼び出されることはなく、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
    })
})
12
Michael Jungo