Skip to content

Commit 991d361

Browse files
committed
Add unhandledRejection to default value of exitOn option
1 parent 0a41c65 commit 991d361

File tree

14 files changed

+69
-25
lines changed

14 files changed

+69
-25
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ Which log level to use.\
115115
## exitOn
116116

117117
_Type_: `string[]`\
118-
_Default_: `['uncaughtException']`
118+
_Default_: `['uncaughtException', 'unhandledRejection']` for Node `>= 15.0.0`, `['uncaughtException']`
119+
otherwise.
119120

120121
Which process errors should trigger `process.exit(1)`.\
121122
[Full documentation](docs/API.md#exiton).

docs/API.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,15 @@ _Value_: array of [`'uncaughtException'`](https://nodejs.org/api/process.html#pr
109109
[`'rejectionHandled'`](https://nodejs.org/api/process.html#process_event_rejectionhandled),
110110
[`'multipleResolves'`](https://nodejs.org/api/process.html#process_event_multipleresolves)
111111
or [`'warning'`](https://nodejs.org/api/process.html#process_event_warning)\
112-
_Default_: `['uncaughtException']`
112+
_Default_: `['uncaughtException', 'unhandledRejection']` for Node `>= 15.0.0`,
113+
`['uncaughtException']` otherwise.
113114

114115
Which process errors should trigger `process.exit(1)`:
115116

116-
- `['uncaughtException']` is Node.js
117-
[default behavior](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly).
118-
- we recommend using `['uncaughtException', 'unhandledRejection']` instead since
119-
this will be
120-
[Node.js future default behavior](https://nodejs.org/dist/latest-v8.x/docs/api/deprecations.html#deprecations_dep0018_unhandled_promise_rejections).
117+
- `['uncaughtException', 'unhandledRejection']` is Node.js default behavior
118+
since Node.js `15.0.0`. Before, only
119+
[`uncaughtException`](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly)
120+
was enabled.
121121
- use `[]` to prevent any `process.exit(1)`. Recommended if your process is
122122
long-running and does not automatically restart on exit.
123123

package-lock.json

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"jest-validate": "^26.6.1",
5858
"map-obj": "^4.1.0",
5959
"moize": "^6.0.0-beta.5",
60+
"semver": "^7.3.2",
6061
"supports-color": "^7.2.0"
6162
},
6263
"devDependencies": {
@@ -69,7 +70,6 @@
6970
"husky": "^4.3.0",
7071
"jasmine": "^3.6.1",
7172
"mocha": "^8.2.0",
72-
"semver": "^7.3.2",
7373
"sinon": "^9.2.0",
7474
"strip-ansi": "^6.0.0",
7575
"tap": "^14.10.8",

src/exit.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ import process from 'process'
44
// Exit process according to `opts.exitOn` (default: ['uncaughtException']):
55
// - `uncaughtException`: default behavior of Node.js and recommended by
66
// https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly
7-
// - `unhandledRejection`: possible future behavior and recommended by Node.js.
8-
// See https://nodejs.org/dist/latest-v8.x/docs/api/deprecations.html#deprecations_dep0018_unhandled_promise_rejections
9-
// By default `unhandledRejection` is opt-in so that using this library does not
10-
// decrease stability (if the application does not restart on exit).
7+
// - `unhandledRejection`: default behavior of Node.js since 15.0.0
118
// `process.exit()` unfortunately aborts any current async operations and
129
// streams are not flushed (including stdout/stderr):
1310
// - https://github.com/nodejs/node/issues/784

src/options/main.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import { version } from 'process'
2+
13
import filterObj from 'filter-obj'
24
import { validate } from 'jest-validate'
5+
import { gte as gteVersion } from 'semver'
36

47
import { addChalk, DEFAULT_COLORS } from '../colors.js'
58
import { validateExitOn } from '../exit.js'
@@ -31,9 +34,25 @@ const isDefined = function (key, value) {
3134
return value !== undefined
3235
}
3336

37+
// Since Node 15.0.0, `unhandledRejection` makes the process exit too
38+
// TODO: remove after dropping support for Node <15.0.0
39+
const getDefaultExitOn = function () {
40+
if (isNewExitBehavior()) {
41+
return ['uncaughtException', 'unhandledRejection']
42+
}
43+
44+
return ['uncaughtException']
45+
}
46+
47+
const isNewExitBehavior = function () {
48+
return gteVersion(version, NEW_EXIT_MIN_VERSION)
49+
}
50+
51+
const NEW_EXIT_MIN_VERSION = '15.0.0'
52+
3453
const DEFAULT_OPTS = {
3554
log: defaultLog,
36-
exitOn: ['uncaughtException'],
55+
exitOn: getDefaultExitOn(),
3756
colors: DEFAULT_COLORS,
3857
}
3958

test/helpers/events/version.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
11
import { version } from 'process'
22

3-
import semver from 'semver'
3+
import { gte as gteVersion, lt as ltVersion } from 'semver'
44

55
// TODO: remove after dropping support for Node <12.0.0
66
// `--unhandled-rejections` was introduced in Node `12.0.0`
77
export const hasUnhandledFlag = function () {
8-
return semver.gte(version, UNHANDLED_FLAG_V)
8+
return gteVersion(version, UNHANDLED_FLAG_VERSION)
99
}
1010

11-
const UNHANDLED_FLAG_V = '12.0.0'
11+
const UNHANDLED_FLAG_VERSION = '12.0.0'
12+
13+
// Node 15.0.0 changed the default exit behavior on unhandled promises
14+
export const hasOldExitBehavior = function (eventName) {
15+
return (
16+
PROMISE_REJECTION_EVENTS.has(eventName) &&
17+
ltVersion(version, NEW_EXIT_MIN_VERSION)
18+
)
19+
}
20+
21+
const PROMISE_REJECTION_EVENTS = new Set([
22+
'unhandledRejection',
23+
'rejectionHandled',
24+
])
25+
26+
const NEW_EXIT_MIN_VERSION = '15.0.0'
-68 Bytes
Binary file not shown.

test/register.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import test from 'ava'
22
import { each } from 'test-each'
33

44
import { EVENTS } from './helpers/events/main.js'
5+
import { hasOldExitBehavior } from './helpers/events/version.js'
56
import { normalizeCall } from './helpers/normalize.js'
67
import { removeProcessListeners } from './helpers/remove.js'
78

@@ -11,6 +12,11 @@ removeProcessListeners()
1112

1213
each(EVENTS, ({ title }, { eventName }) => {
1314
test(`should work using the -r flag | ${title}`, async (t) => {
15+
if (hasOldExitBehavior(eventName)) {
16+
t.pass()
17+
return
18+
}
19+
1420
t.snapshot(
1521
await normalizeCall(`node ${LOADERS}/register.js ${eventName}`, {
1622
colors: false,

test/snapshots/register.js.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Generated by [AVA](https://avajs.dev).
7272
> Snapshot 1
7373
7474
{
75-
exitCode: 0,
75+
exitCode: 1,
7676
stderr: `× unhandledRejection (a promise was rejected but not handled) Error: message␊
7777
at STACK TRACE␊
7878
× rejectionHandled (a promise was rejected and handled too late) Error: message␊
@@ -96,7 +96,7 @@ Generated by [AVA](https://avajs.dev).
9696
> Snapshot 1
9797
9898
{
99-
exitCode: 0,
99+
exitCode: 1,
100100
stderr: `× unhandledRejection (a promise was rejected but not handled) Error: message␊
101101
at STACK TRACE`,
102102
stdout: '',

0 commit comments

Comments
 (0)