Skip to content

Commit d8cc233

Browse files
wmertenscpojer
authored andcommitted
jest-jasmine2: pretty-print non-Error errors (#5980)
1 parent f952f13 commit d8cc233

File tree

9 files changed

+163
-18
lines changed

9 files changed

+163
-18
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
([#5864](https://github.com/facebook/jest/pull/5864))
5555
* `[jest-editor-support]` Add `no-color` option to runner
5656
([#5909](https://github.com/facebook/jest/pull/5909))
57+
* Pretty-print non-Error object errors
58+
([#5980](https://github.com/facebook/jest/pull/5980))
5759

5860
### Fixes
5961

integration-tests/__tests__/__snapshots__/failures.test.js.snap

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,96 @@ exports[`not throwing Error objects 4`] = `
6868
"
6969
`;
7070
71+
exports[`not throwing Error objects 5`] = `
72+
"FAIL __tests__/during_tests.test.js
73+
✕ Promise thrown during test
74+
✕ Boolean thrown during test
75+
✕ undefined thrown during test
76+
✕ Object thrown during test
77+
✕ Error during test
78+
✕ done(Error)
79+
✕ done(non-error)
80+
81+
● Promise thrown during test
82+
83+
thrown: Promise {}
84+
85+
at packages/jest-jasmine2/build/expectation_result_factory.js:54:47
86+
87+
● Boolean thrown during test
88+
89+
thrown: false
90+
91+
at packages/jest-jasmine2/build/expectation_result_factory.js:54:47
92+
93+
● undefined thrown during test
94+
95+
thrown: undefined
96+
97+
at packages/jest-jasmine2/build/expectation_result_factory.js:54:47
98+
99+
● Object thrown during test
100+
101+
thrown: Object {
102+
\\"notAnError\\": Array [
103+
Object {
104+
\\"hello\\": true,
105+
\\"tooDeep\\": [Object],
106+
},
107+
],
108+
}
109+
110+
at packages/jest-jasmine2/build/expectation_result_factory.js:54:47
111+
112+
● Error during test
113+
114+
ReferenceError: doesNotExist is not defined
115+
116+
26 | test('Error during test', () => {
117+
27 | // eslint-disable-next-line no-undef
118+
> 28 | doesNotExist.alsoThisNot;
119+
29 | });
120+
30 |
121+
31 | test('done(Error)', done => {
122+
123+
at __tests__/during_tests.test.js:28:3
124+
125+
done(Error)
126+
127+
this is an error
128+
129+
30 |
130+
31 | test('done(Error)', done => {
131+
> 32 | done(new Error('this is an error'));
132+
33 | });
133+
34 |
134+
35 | test('done(non-error)', done => {
135+
136+
at __tests__/during_tests.test.js:32:8
137+
138+
done(non-error)
139+
140+
Failed: Object {
141+
\\"notAnError\\": Array [
142+
Object {
143+
\\"hello\\": true,
144+
\\"tooDeep\\": [Object],
145+
},
146+
],
147+
}
148+
149+
34 |
150+
35 | test('done(non-error)', done => {
151+
> 36 | done(deepObject);
152+
37 | });
153+
38 |
154+
155+
at packages/jest-jasmine2/build/expectation_result_factory.js:54:47
156+
at __tests__/during_tests.test.js:36:3
157+
158+
"
159+
`;
160+
71161
exports[`works with assertions in separate files 1`] = `
72162
"FAIL __tests__/test_macro.test.js
73163
✕ use some imported macro to make assertion
@@ -442,8 +532,9 @@ exports[`works with node assert 1`] = `
442532
443533
assert.ifError
444534
445-
Error
446-
1 thrown
535+
thrown: 1
536+
537+
at packages/jest-jasmine2/build/expectation_result_factory.js:54:47
447538
448539
assert.doesNotThrow
449540

integration-tests/__tests__/failures.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ test('not throwing Error objects', () => {
5252
expect(extractSummary(stderr).rest).toMatchSnapshot();
5353
stderr = runJest(dir, ['assertion_count.test.js']).stderr;
5454
expect(extractSummary(cleanupStackTrace(stderr)).rest).toMatchSnapshot();
55+
stderr = runJest(dir, ['during_tests.test.js']).stderr;
56+
expect(extractSummary(stderr).rest).toMatchSnapshot();
5557
});
5658

5759
test('works with node assert', () => {

integration-tests/__tests__/stack_trace.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('Stack Trace', () => {
7878
expect(result.status).toBe(1);
7979

8080
expect(stderr).toMatch(/this is unexpected\./);
81-
expect(stderr).toMatch(/this is a string\. thrown/);
81+
expect(stderr).toMatch(/this is a string\./);
8282

8383
expect(stderr).toMatch(/\s+at\s(?:.+?)\s\(__tests__\/test_error.test\.js/);
8484

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
const deepObject = {
4+
notAnError: [{hello: true, tooDeep: {notVisible: true}}],
5+
};
6+
7+
test('Promise thrown during test', () => {
8+
throw Promise.resolve(5);
9+
});
10+
11+
test('Boolean thrown during test', () => {
12+
// eslint-disable-next-line no-throw-literal
13+
throw false;
14+
});
15+
16+
test('undefined thrown during test', () => {
17+
// eslint-disable-next-line no-throw-literal
18+
throw undefined;
19+
});
20+
21+
test('Object thrown during test', () => {
22+
// eslint-disable-next-line no-throw-literal
23+
throw deepObject;
24+
});
25+
26+
test('Error during test', () => {
27+
// eslint-disable-next-line no-undef
28+
doesNotExist.alsoThisNot;
29+
});
30+
31+
test('done(Error)', done => {
32+
done(new Error('this is an error'));
33+
});
34+
35+
test('done(non-error)', done => {
36+
done(deepObject);
37+
});

packages/jest-jasmine2/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"jest-message-util": "^22.4.0",
1919
"jest-snapshot": "^22.4.0",
2020
"jest-util": "^22.4.1",
21-
"source-map-support": "^0.5.0"
21+
"source-map-support": "^0.5.0",
22+
"pretty-format": "^22.4.0"
2223
},
2324
"devDependencies": {
2425
"jest-runtime": "^22.4.2"

packages/jest-jasmine2/src/__tests__/expectation_result_factory.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('expectationResultFactory', () => {
2828
passed: false,
2929
};
3030
const result = expectationResultFactory(options);
31-
expect(result.message).toEqual('');
31+
expect(result.message).toEqual('thrown: undefined');
3232
});
3333

3434
it('returns the result if failed (with `message`).', () => {
@@ -66,6 +66,6 @@ describe('expectationResultFactory', () => {
6666
passed: false,
6767
};
6868
const result = expectationResultFactory(options);
69-
expect(result.message).toEqual('Expected `Pass`, received `Fail`. thrown');
69+
expect(result.message).toEqual('Expected `Pass`, received `Fail`.');
7070
});
7171
});

packages/jest-jasmine2/src/expectation_result_factory.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,36 @@
77
* @flow
88
*/
99

10+
import prettyFormat from 'pretty-format';
11+
1012
function messageFormatter({error, message, passed}) {
1113
if (passed) {
1214
return 'Passed.';
1315
}
1416
if (message) {
1517
return message;
1618
}
17-
if (!error) {
18-
return '';
19+
if (typeof error === 'string') {
20+
return error;
21+
}
22+
if (
23+
// duck-type Error, see #2549
24+
error &&
25+
typeof error === 'object' &&
26+
typeof error.message === 'string' &&
27+
typeof error.name === 'string'
28+
) {
29+
return `${error.name}: ${error.message}`;
1930
}
20-
return error.message && error.name
21-
? `${error.name}: ${error.message}`
22-
: `${error.toString()} thrown`;
31+
return `thrown: ${prettyFormat(error, {maxDepth: 3})}`;
2332
}
2433

2534
function stackFormatter(options, errorMessage) {
2635
if (options.passed) {
2736
return '';
2837
}
29-
const {stack} = options.error || new Error(errorMessage);
38+
const stack =
39+
(options.error && options.error.stack) || new Error(errorMessage).stack;
3040
return stack;
3141
}
3242

packages/jest-jasmine2/src/jasmine/Env.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3232

3333
import queueRunner from '../queue_runner';
3434
import treeProcessor from '../tree_processor';
35+
import prettyFormat from 'pretty-format';
3536

3637
// Try getting the real promise object from the context, if available. Someone
3738
// could have overridden it in a test. Async functions return it implicitly.
@@ -547,19 +548,20 @@ export default function(j$) {
547548
};
548549

549550
this.fail = function(error) {
550-
let message = 'Failed';
551-
if (error) {
552-
message += ': ';
553-
message += error.message || error;
554-
}
551+
// duck-type Error, see #2549
552+
const isError =
553+
typeof error === 'object' &&
554+
typeof error.message === 'string' &&
555+
typeof error.name === 'string';
556+
const message = `Failed: ${prettyFormat(error, {maxDepth: 3})}`;
555557

556558
currentRunnable().addExpectationResult(false, {
557559
matcherName: '',
558560
passed: false,
559561
expected: '',
560562
actual: '',
561563
message,
562-
error: error && error.message ? error : null,
564+
error: isError ? error : null,
563565
});
564566
};
565567
}

0 commit comments

Comments
 (0)