笑话:测试超时后拒绝的承诺
Jest: Test for promise that rejects after timeout
我正在尝试为这个函数的悲伤路径编写一个测试:
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
中。你如何使用假计时器测试这样的功能?
问题似乎不是使用假计时器:您预期的错误是抛出的错误。但是,在 Jest 中测试抛出错误的函数时,您应该将 error-throwing 代码包装在函数中,如下所示:
expect(()=> {/* code that will throw error */}).toThrow()
此处有更多详细信息:https://jestjs.io/docs/en/expect#tothrowerror
编辑:对于异步函数,您应该在 toThrow
之前使用 rejects
;看这个例子:
如果不等待 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');
我正在尝试为这个函数的悲伤路径编写一个测试:
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
中。你如何使用假计时器测试这样的功能?
问题似乎不是使用假计时器:您预期的错误是抛出的错误。但是,在 Jest 中测试抛出错误的函数时,您应该将 error-throwing 代码包装在函数中,如下所示:
expect(()=> {/* code that will throw error */}).toThrow()
此处有更多详细信息:https://jestjs.io/docs/en/expect#tothrowerror
编辑:对于异步函数,您应该在 toThrow
之前使用 rejects
;看这个例子:
如果不等待 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');