开玩笑:测试在超时后拒绝的承诺

时间:2020-09-24 08:59:25

标签: javascript unit-testing timer jestjs settimeout

我正在尝试为此功能的悲伤路径编写测试:

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

我设法编写了一个通过的测试,但由于它实际上等待测试完成,因此需要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)
  })
})

也许有一种方法可以使用Jest的假计时器来解决,但我无法使其正常工作。这是我的最佳尝试:

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

失败并抛出

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

即使我将失败的函数包装在try/catch中。您如何使用假计时器测试这样的功能?

2 个答案:

答案 0 :(得分:2)

如果尚未等待awaitFirstStreamForPage(page)的拒绝,try..catch就是不可能的。

应该捕获拒绝,但是要在调用advanceTimersByTime之后并且可能在flushPromises之后。

可以是:

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

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

答案 1 :(得分:0)

问题似乎不在于使用假计时器:您所期望的错误是引发的错误。但是,在测试在Jest中引发错误的函数时,应将引发错误的代码包装在一个函数中,如下所示:

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

此处有更多详细信息:https://jestjs.io/docs/en/expect#tothrowerror

编辑:对于异步功能,您应该在rejects之前使用toThrow;请参见以下示例:Can you write async tests that expect toThrow?

相关问题