Skip to content

Commit c8d56fe

Browse files
authored
fix(vitest): allow testing unandled rejection/exception (#6016)
1 parent eb6ea5b commit c8d56fe

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

packages/vitest/src/runtime/execute.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,19 @@ function listenForErrors(state: () => WorkerGlobalState) {
5454
dispose.forEach(fn => fn())
5555
dispose.length = 0
5656

57-
function catchError(err: unknown, type: string) {
57+
function catchError(err: unknown, type: string, event: 'uncaughtException' | 'unhandledRejection') {
5858
const worker = state()
59+
60+
// if error happens during a test
61+
if (worker.current) {
62+
const listeners = process.listeners(event as 'uncaughtException')
63+
// if there is another listener, assume that it's handled by user code
64+
// one is Vitest's own listener
65+
if (listeners.length > 1) {
66+
return
67+
}
68+
}
69+
5970
const error = processError(err)
6071
if (!isPrimitive(error)) {
6172
error.VITEST_TEST_NAME = worker.current?.name
@@ -67,8 +78,8 @@ function listenForErrors(state: () => WorkerGlobalState) {
6778
state().rpc.onUnhandledError(error, type)
6879
}
6980

70-
const uncaughtException = (e: Error) => catchError(e, 'Uncaught Exception')
71-
const unhandledRejection = (e: Error) => catchError(e, 'Unhandled Rejection')
81+
const uncaughtException = (e: Error) => catchError(e, 'Uncaught Exception', 'uncaughtException')
82+
const unhandledRejection = (e: Error) => catchError(e, 'Unhandled Rejection', 'unhandledRejection')
7283

7384
process.on('uncaughtException', uncaughtException)
7485
process.on('unhandledRejection', unhandledRejection)
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { nextTick } from 'node:process'
2+
import { expect, test, vi } from 'vitest'
3+
4+
test('can test unhandled rejection', async () => {
5+
const fn = vi.fn()
6+
7+
const promise = new Promise<void>((resolve) => {
8+
process.on('unhandledRejection', () => {
9+
fn()
10+
resolve()
11+
})
12+
})
13+
14+
Promise.resolve().then(() => {
15+
throw new Error('unhandled rejection')
16+
})
17+
18+
await promise
19+
20+
expect(fn).toHaveBeenCalledTimes(1)
21+
})
22+
23+
test('can test unhandled exception', async () => {
24+
const fn = vi.fn()
25+
26+
const promise = new Promise<void>((resolve) => {
27+
process.on('uncaughtException', () => {
28+
fn()
29+
resolve()
30+
})
31+
})
32+
33+
nextTick(() => {
34+
throw new Error('unhandled exception')
35+
})
36+
37+
await promise
38+
39+
expect(fn).toHaveBeenCalledTimes(1)
40+
})

0 commit comments

Comments
 (0)