开玩笑:测试超时后拒绝的承诺
Posted
技术标签:
【中文标题】开玩笑:测试超时后拒绝的承诺【英文标题】:Jest: Test for promise that rejects after timeout 【发布时间】:2021-01-10 13:01:53 【问题描述】:我正在尝试为这个函数的悲惨路径写一个测试:
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_STREAMms`)
我设法编写了一个通过的测试,但它需要 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
中。你如何使用假计时器测试这样的功能?
【问题讨论】:
【参考方案1】:如果没有等待,则不可能通过try..catch
捕获来自awaitFirstStreamForPage(page)
的拒绝。
应该在调用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');
【讨论】:
【参考方案2】:问题似乎不在于使用假计时器:您预期的错误是被抛出的错误。但是,当测试在 Jest 中抛出错误的函数时,您应该将抛出错误的代码包装在一个函数中,如下所示:
expect(()=> /* code that will throw error */).toThrow()
更多详情:https://jestjs.io/docs/en/expect#tothrowerror
编辑:对于异步函数,您应该在toThrow
之前使用rejects
;看这个例子:Can you write async tests that expect toThrow?
【讨论】:
toThrow
捕获同步错误。应该是rejects.toThrow
。这还不够,因为操作(advanceTimersByTime)需要同时执行。这里使用了假定时器,使测试时间短于 10 秒。以上是关于开玩笑:测试超时后拒绝的承诺的主要内容,如果未能解决你的问题,请参考以下文章