Skip to content

Commit 862edb8

Browse files
committed
report unhandled promise rejections
1 parent a73374d commit 862edb8

File tree

7 files changed

+95
-6
lines changed

7 files changed

+95
-6
lines changed

cli.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var cli = meow({
4545

4646
var testCount = 0;
4747
var fileCount = 0;
48+
var unhandledRejectionCount = 0;
4849
var errors = [];
4950

5051
function error(err) {
@@ -116,11 +117,18 @@ function run(file) {
116117
return fork(args)
117118
.on('stats', stats)
118119
.on('test', test)
120+
.on('unhandledRejections', rejections)
119121
.on('data', function (data) {
120122
process.stdout.write(data);
121123
});
122124
}
123125

126+
function rejections(data) {
127+
var unhandled = data.unhandledRejections;
128+
log.unhandledRejections(data.file, unhandled);
129+
unhandledRejectionCount += unhandled.length;
130+
}
131+
124132
function sum(arr, key) {
125133
var result = 0;
126134

@@ -145,7 +153,7 @@ function exit(results) {
145153
var failed = sum(stats, 'failCount');
146154

147155
log.write();
148-
log.report(passed, failed);
156+
log.report(passed, failed, unhandledRejectionCount);
149157
log.write();
150158

151159
if (failed > 0) {
@@ -158,7 +166,7 @@ function exit(results) {
158166

159167
// timeout required to correctly flush stderr on Node 0.10 Windows
160168
setTimeout(function () {
161-
process.exit(failed > 0 ? 1 : 0);
169+
process.exit(failed > 0 || unhandledRejectionCount > 0 ? 1 : 0);
162170
}, 0);
163171
}
164172

lib/babel.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
'use strict';
2+
var loudRejection = require('loud-rejection/api')(process);
23
var resolveFrom = require('resolve-from');
34
var createEspowerPlugin = require('babel-plugin-espower/create');
45
var requireFromString = require('require-from-string');
6+
var destroyCircular = require('destroy-circular');
57

68
var hasGenerators = parseInt(process.version.slice(1), 10) > 0;
79
var testPath = process.argv[2];
@@ -45,7 +47,41 @@ if (!avaRequired) {
4547
}
4648

4749
process.on('message', function (message) {
48-
if (message['ava-kill-command']) {
49-
process.exit(0);
50+
var command = message['ava-child-process-command'];
51+
if (command) {
52+
process.emit('ava-' + command, message.data);
5053
}
5154
});
55+
56+
process.on('ava-kill', function () {
57+
process.exit(0);
58+
});
59+
60+
process.on('ava-cleanup', function () {
61+
var unhandled = loudRejection.currentlyUnhandled();
62+
if (unhandled.length) {
63+
unhandled = unhandled.map(function (entry) {
64+
var err = entry.reason;
65+
if (typeof err === 'object') {
66+
return destroyCircular(err);
67+
}
68+
if (typeof err === 'function') {
69+
return '[Function ' + err.name + ']';
70+
}
71+
return err;
72+
});
73+
process.send({
74+
name: 'unhandledRejections',
75+
data: {
76+
unhandledRejections: unhandled
77+
}
78+
});
79+
}
80+
81+
setTimeout(function () {
82+
process.send({
83+
name: 'cleaned-up',
84+
data: {}
85+
});
86+
}, 100);
87+
});

lib/fork.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ module.exports = function (args) {
1818

1919
var ps = childProcess.fork(babel, args, options);
2020

21+
function send(command, data) {
22+
ps.send({'ava-child-process-command': command, 'data': data});
23+
}
24+
2125
var promise = new Promise(function (resolve, reject) {
2226
var testResults;
2327

@@ -26,7 +30,11 @@ module.exports = function (args) {
2630

2731
// after all tests are finished and results received
2832
// kill the forked process, so AVA can exit safely
29-
ps.send({'ava-kill-command': true});
33+
send('cleanup', true);
34+
});
35+
36+
ps.on('cleaned-up', function () {
37+
send('kill', true);
3038
});
3139

3240
ps.on('error', reject);

lib/logger.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,28 @@ x.errors = function (results) {
7070
});
7171
};
7272

73-
x.report = function (passed, failed) {
73+
x.report = function (passed, failed, unhandled) {
7474
if (failed > 0) {
7575
log.writelpad(chalk.red(failed, plur('test', failed), 'failed'));
7676
} else {
7777
log.writelpad(chalk.green(passed, plur('test', passed), 'passed'));
7878
}
79+
if (unhandled > 0) {
80+
log.writelpad(chalk.red(unhandled, 'unhandled', plur('rejection', unhandled)));
81+
}
82+
};
83+
84+
x.unhandledRejections = function (file, rejections) {
85+
if (!(rejections && rejections.length)) {
86+
return;
87+
}
88+
rejections.forEach(function (rejection) {
89+
log.write(chalk.red('Unhandled Rejection: ', file));
90+
if (rejection.stack) {
91+
log.writelpad(chalk.red(beautifyStack(rejection.stack)));
92+
} else {
93+
log.writelpad(chalk.red(JSON.stringify(rejection)));
94+
}
95+
log.write();
96+
});
7997
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"globby": "^3.0.1",
7878
"has-flag": "^1.0.0",
7979
"is-generator-fn": "^1.0.0",
80+
"loud-rejection": "^1.2.0",
8081
"max-timeout": "^1.0.0",
8182
"meow": "^3.3.0",
8283
"plur": "^2.0.0",

test/fixture/loud-rejection.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const test = require('../../');
2+
3+
test('creates an unhandled rejection', t => {
4+
Promise.reject(new Error(`You can't handle this!`));
5+
6+
setTimeout(function () {
7+
t.end();
8+
});
9+
});

test/test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,15 @@ test('Babel require hook only applies to the test file', function (t) {
10661066
});
10671067
});
10681068

1069+
test('Unhandled promises will be reported to console', function (t) {
1070+
execCli('fixture/loud-rejection.js', function (err, stdout, stderr) {
1071+
t.ok(err);
1072+
t.ok(/You can't handle this/.test(stderr));
1073+
t.ok(/1 unhandled rejection[^s]/.test(stderr));
1074+
t.end();
1075+
});
1076+
});
1077+
10691078
test('absolute paths in CLI', function (t) {
10701079
t.plan(2);
10711080

0 commit comments

Comments
 (0)