简体   繁体   English

Jest:测试超时后拒绝的承诺

[英]Jest: Test for promise that rejects after timeout

I'm trying to write a test for the sad path of this function:我正在尝试为这个函数的悲伤路径编写一个测试:

const awaitFirstStreamForPage = async page => {
  try {
    await page.waitForSelector('[data-stream="true"]', {
      timeout: MAX_DELAY_UNTIL_FIRST_STREAM,
    })
  } catch (e) {
    throw new Error(`no stream found for ${MAX_DELAY_UNTIL_FIRST_STREAM}ms`)
  }
}

I managed to write a test that passes, but it takes 10 seconds to run because it actually waits for the test to finish.我设法编写了一个通过的测试,但运行需要 10 秒,因为它实际上在等待测试完成。

describe('awaitFirstStreamForPage()', () => {
  it('given a page and no active stream appearing: should throw', async () => {
    jest.setTimeout(15000)

    const browser = await puppeteer.launch({ headless: true })
    const page = await getPage(browser)

    let error

    try {
      await awaitFirstStreamForPage(page)
    } catch (err) {
      error = err
    }

    const actual = error.message
    const expected = 'no stream found for 10000ms'

    expect(actual).toEqual(expected)

    await browser.close()
    jest.setTimeout(5000)
  })
})

There is probably a way to solve it using Jest's fake timers, but I couldn't get it to work.可能有一种方法可以使用 Jest 的假计时器来解决它,但我无法让它工作。 Here is my best attempt:这是我最好的尝试:

const flushPromises = () => new Promise(res => process.nextTick(res))

describe('awaitFirstStreamForPage()', () => {
  it('given a page and no active stream appearing: should throw', async () => {
    jest.useFakeTimers()

    const browser = await puppeteer.launch({ headless: true })
    const page = await getPage(browser)

    let error

    try {
      awaitFirstStreamForPage(page)
      jest.advanceTimersByTime(10000)
      await flushPromises()
    } catch (err) {
      error = err
    }

    const actual = error.message
    const expected = 'no stream found for 10000ms'

    expect(actual).toEqual(expected)

    await browser.close()
    jest.useRealTimers()
  })
})

which fails and throws with失败并抛出

(node:9697) UnhandledPromiseRejectionWarning: Error: no stream found for 10000ms

Even though I wrapped the failing function in a try/catch .即使我将失败的函数包装在try/catch How do you test a function like this using fake timers?您如何使用假计时器测试这样的功能?

It's impossible to catch a rejection from awaitFirstStreamForPage(page) with try..catch if it's not awaited.如果没有等待,则不可能使用try..catchawaitFirstStreamForPage(page)捕获拒绝。

A rejection should be caught but after calling advanceTimersByTime and potentially after flushPromises .的拒绝应被抓到,但打完电话后advanceTimersByTime后可能flushPromises

It can be:有可能:

const promise = awaitFirstStreamForPage(page);
promise.catch(() => { /* suppress UnhandledPromiseRejectionWarning */ });

jest.advanceTimersByTime(10000)
await flushPromises();
await expect(promise).rejects.toThrow('no stream found for 10000ms');

The problem doesn't seem to be the use of fake timers: the error you expected is the one being thrown.问题似乎不是使用假计时器:您期望的错误是被抛出的错误。 However, when testing functions that throw errors in Jest, you should wrap the error-throwing code in a function, like this:但是,在 Jest 中测试抛出错误的函数时,您应该将抛出错误的代码包装在一个函数中,如下所示:

expect(()=> {/* code that will throw error */}).toThrow()

More details here: https://jestjs.io/docs/en/expect#tothrowerror更多细节在这里: https : //jestjs.io/docs/en/expect#tothrowerror

Edit: For an async function, you should use rejects before toThrow ;编辑:对于异步函数,您应该在toThrow之前使用rejects see this example: Can you write async tests that expect toThrow?看这个例子: 你能编写期望 toThrow 的异步测试吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM