Skip to content

Commit 63d0fae

Browse files
committed
Merge pull request #555 from novemberborn/errors-are-errors
Consistent error determination
2 parents 11e82e9 + 86ff25e commit 63d0fae

File tree

8 files changed

+73
-30
lines changed

8 files changed

+73
-30
lines changed

api.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,7 @@ Api.prototype._handleStats = function (stats) {
114114
Api.prototype._handleTest = function (test) {
115115
test.title = this._prefixTitle(test.file) + test.title;
116116

117-
var isError = test.error.message;
118-
119-
if (isError) {
117+
if (test.error) {
120118
if (test.error.powerAssertContext) {
121119
var message = formatter(test.error.powerAssertContext);
122120

@@ -132,8 +130,6 @@ Api.prototype._handleTest = function (test) {
132130
}
133131

134132
this.errors.push(test);
135-
} else {
136-
test.error = null;
137133
}
138134

139135
this.emit('test', test);

index.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,13 @@ function test(props) {
4646
return;
4747
}
4848

49-
props.error = hasError ? serializeError(props.error) : {};
50-
51-
if (props.error.stack) {
52-
props.error.stack = beautifyStack(props.error.stack);
49+
if (hasError) {
50+
props.error = serializeError(props.error);
51+
if (props.error.stack) {
52+
props.error.stack = beautifyStack(props.error.stack);
53+
}
54+
} else {
55+
props.error = null;
5356
}
5457

5558
send('test', props);

lib/test.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var co = require('co-with-promise');
77
var observableToPromise = require('observable-to-promise');
88
var isPromise = require('is-promise');
99
var isObservable = require('is-observable');
10+
var inspect = require('util').inspect;
1011
var assert = require('./assert');
1112
var enhanceAssert = require('./enhance-assert');
1213
var globals = require('./globals');
@@ -70,10 +71,6 @@ Test.prototype._setAssertError = function (err) {
7071
return;
7172
}
7273

73-
if (err === undefined) {
74-
err = 'undefined';
75-
}
76-
7774
this.assertError = err;
7875
};
7976

@@ -95,7 +92,15 @@ Test.prototype._run = function () {
9592
try {
9693
ret = this.fn(this._publicApi());
9794
} catch (err) {
98-
this._setAssertError(err);
95+
if (err instanceof Error) {
96+
this._setAssertError(err);
97+
} else {
98+
this._setAssertError(new assert.AssertionError({
99+
actual: err,
100+
message: 'Non-error thrown with value: ' + inspect(err, {depth: null}),
101+
operator: 'catch'
102+
}));
103+
}
99104
}
100105

101106
return ret;
@@ -156,7 +161,7 @@ Test.prototype.run = function () {
156161
if (!(err instanceof Error)) {
157162
err = new assert.AssertionError({
158163
actual: err,
159-
message: 'Promise rejected with "' + err + '"',
164+
message: 'Promise rejected with: ' + inspect(err, {depth: null}),
160165
operator: 'promise'
161166
});
162167
}
@@ -192,11 +197,14 @@ Object.defineProperty(Test.prototype, 'end', {
192197

193198
Test.prototype._end = function (err) {
194199
if (err) {
195-
this._setAssertError(new assert.AssertionError({
196-
actual: err,
197-
message: 'Callback called with an error → ' + err,
198-
operator: 'callback'
199-
}));
200+
if (!(err instanceof Error)) {
201+
err = new assert.AssertionError({
202+
actual: err,
203+
message: 'Callback called with an error: ' + inspect(err, {depth: null}),
204+
operator: 'callback'
205+
});
206+
}
207+
this._setAssertError(err);
200208

201209
this.exit();
202210
return;

test/api.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,17 @@ test('uncaught exception will throw an error', function (t) {
287287
});
288288
});
289289

290+
test('errors can occur without messages', function (t) {
291+
t.plan(2);
292+
293+
var api = new Api([path.join(__dirname, 'fixture/error-without-message.js')]);
294+
api.run()
295+
.then(function () {
296+
t.is(api.failCount, 1);
297+
t.is(api.errors.length, 1);
298+
});
299+
});
300+
290301
test('stack traces for exceptions are corrected using a source map file', function (t) {
291302
t.plan(4);
292303

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import test from '../../';
2+
3+
test('throw an error without a message', () => {
4+
throw new Error();
5+
});

test/hooks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ test('don\'t display hook title if it did not fail', function (t) {
309309
fork(path.join(__dirname, 'fixture', 'hooks-passing.js'))
310310
.run()
311311
.on('test', function (test) {
312-
t.same(test.error, {});
312+
t.same(test.error, null);
313313
t.is(test.title, 'pass');
314314
})
315315
.then(function () {

test/promise.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ test('reject with non-Error', function (t) {
318318
}).run().then(function (result) {
319319
t.is(result.passed, false);
320320
t.is(result.reason.name, 'AssertionError');
321-
t.is(result.reason.message, 'Promise rejected with "failure"');
321+
t.is(result.reason.message, 'Promise rejected with: \'failure\'');
322322
t.end();
323323
});
324324
});

test/test.js

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,26 @@ test('end can be used as callback without maintaining thisArg', function (t) {
128128
});
129129

130130
test('end can be used as callback with error', function (t) {
131+
var err = new Error('failed');
131132
ava.cb(function (a) {
132-
a.end(new Error('failed'));
133+
a.end(err);
133134
}).run().then(function (result) {
134135
t.is(result.passed, false);
135-
t.true(result.reason instanceof Error);
136-
// TODO: Question - why not just set the reason to the error?
137-
t.match(result.reason.message, /Callback called with an error/);
136+
t.is(result.reason, err);
137+
t.end();
138+
});
139+
});
140+
141+
test('end can be used as callback with a non-error as its error argument', function (t) {
142+
var nonError = {foo: 'bar'};
143+
ava.cb(function (a) {
144+
a.end(nonError);
145+
}).run().then(function (result) {
146+
t.is(result.passed, false);
147+
t.ok(result.reason);
148+
t.is(result.reason.name, 'AssertionError');
149+
t.is(result.reason.actual, nonError);
150+
t.is(result.reason.message, 'Callback called with an error: { foo: \'bar\' }');
138151
t.end();
139152
});
140153
});
@@ -364,17 +377,24 @@ test('fails with thrown falsy value', function (t) {
364377
}).run();
365378

366379
t.is(result.passed, false);
367-
t.is(result.reason, 0);
380+
t.is(result.reason.actual, 0);
381+
t.is(result.reason.message, 'Non-error thrown with value: 0');
382+
t.is(result.reason.name, 'AssertionError');
383+
t.is(result.reason.operator, 'catch');
368384
t.end();
369385
});
370386

371-
test('throwing undefined will be converted to string "undefined"', function (t) {
387+
test('fails with thrown non-error object', function (t) {
388+
var obj = {foo: 'bar'};
372389
var result = ava(function () {
373-
throw undefined; // eslint-disable-line no-throw-literal
390+
throw obj;
374391
}).run();
375392

376393
t.is(result.passed, false);
377-
t.is(result.reason, 'undefined');
394+
t.is(result.reason.actual, obj);
395+
t.is(result.reason.message, 'Non-error thrown with value: { foo: \'bar\' }');
396+
t.is(result.reason.name, 'AssertionError');
397+
t.is(result.reason.operator, 'catch');
378398
t.end();
379399
});
380400

0 commit comments

Comments
 (0)