Skip to content

Commit 82d1c36

Browse files
mihir254targos
authored andcommitted
test_runner: display failed test stack trace with dot reporter
PR-URL: #52655 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
1 parent 4076782 commit 82d1c36

7 files changed

Lines changed: 379 additions & 84 deletions

File tree

‎lib/internal/test_runner/reporter/dot.js‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
'use strict';
2-
const{ MathMax }=primordials;
2+
const{
3+
ArrayPrototypePush,
4+
MathMax,
5+
}=primordials;
6+
constcolors=require('internal/util/colors');
7+
const{ formatTestReport }=require('internal/test_runner/reporter/utils');
38

49
module.exports=asyncfunction*dot(source){
510
letcount=0;
611
letcolumns=getLineLength();
7-
forawait(const{ type }ofsource){
12+
constfailedTests=[];
13+
forawait(const{ type, data }ofsource){
814
if(type==='test:pass'){
915
yield'.';
1016
}
1117
if(type==='test:fail'){
1218
yield'X';
19+
ArrayPrototypePush(failedTests,data);
1320
}
1421
if((type==='test:fail'||type==='test:pass')&&++count===columns){
1522
yield'\n';
@@ -20,6 +27,12 @@ module.exports = async function* dot(source) {
2027
}
2128
}
2229
yield'\n';
30+
if(failedTests.length>0){
31+
yield`\n${colors.red}Failed tests:${colors.white}\n\n`;
32+
for(consttestoffailedTests){
33+
yieldformatTestReport('test:fail',test);
34+
}
35+
}
2336
};
2437

2538
functiongetLineLength(){

‎lib/internal/test_runner/reporter/spec.js‎

Lines changed: 14 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,35 @@
11
'use strict';
2-
32
const{
43
ArrayPrototypeJoin,
54
ArrayPrototypePop,
65
ArrayPrototypePush,
76
ArrayPrototypeShift,
87
ArrayPrototypeUnshift,
9-
hardenRegExp,
10-
RegExpPrototypeSymbolSplit,
11-
SafeMap,
12-
StringPrototypeRepeat,
138
}=primordials;
149
constassert=require('assert');
1510
constTransform=require('internal/streams/transform');
16-
const{ inspectWithNoCustomRetry }=require('internal/errors');
1711
constcolors=require('internal/util/colors');
1812
const{ kSubtestsFailed }=require('internal/test_runner/test');
1913
const{ getCoverageReport }=require('internal/test_runner/utils');
2014
const{ relative }=require('path');
15+
const{
16+
formatTestReport,
17+
indent,
18+
reporterColorMap,
19+
reporterUnicodeSymbolMap,
20+
}=require('internal/test_runner/reporter/utils');
2121

22-
constsymbols={
23-
'__proto__': null,
24-
'test:fail': '\u2716 ',
25-
'test:pass': '\u2714 ',
26-
'test:diagnostic': '\u2139 ',
27-
'test:coverage': '\u2139 ',
28-
'arrow:right': '\u25B6 ',
29-
'hyphen:minus': '\uFE63 ',
30-
};
3122
classSpecReporterextendsTransform{
3223
#stack =[];
3324
#reported =[];
34-
#indentMemo =newSafeMap();
3525
#failedTests =[];
3626
#cwd =process.cwd();
37-
#inspectOptions;
38-
#colors;
3927

4028
constructor(){
4129
super({__proto__: null,writableObjectMode: true});
4230
colors.refresh();
43-
this.#inspectOptions ={__proto__: null,colors: colors.shouldColorize(process.stdout),breakLength: Infinity};
44-
this.#colors ={
45-
'__proto__': null,
46-
'test:fail': colors.red,
47-
'test:pass': colors.green,
48-
'test:diagnostic': colors.blue,
49-
};
5031
}
5132

52-
#indent(nesting){
53-
letvalue=this.#indentMemo.get(nesting);
54-
if(value===undefined){
55-
value=StringPrototypeRepeat(' ',nesting);
56-
this.#indentMemo.set(nesting,value);
57-
}
58-
59-
returnvalue;
60-
}
61-
#formatError(error,indent){
62-
if(!error)return'';
63-
consterr=error.code==='ERR_TEST_FAILURE' ? error.cause : error;
64-
constmessage=ArrayPrototypeJoin(
65-
RegExpPrototypeSymbolSplit(
66-
hardenRegExp(/\r?\n/),
67-
inspectWithNoCustomRetry(err,this.#inspectOptions),
68-
),`\n${indent} `);
69-
return`\n${indent}${message}\n`;
70-
}
71-
#formatTestReport(type,data,prefix='',indent='',hasChildren=false){
72-
letcolor=this.#colors[type]??colors.white;
73-
letsymbol=symbols[type]??' ';
74-
const{ skip, todo }=data;
75-
constduration_ms=data.details?.duration_ms ? ` ${colors.gray}(${data.details.duration_ms}ms)${colors.white}` : '';
76-
lettitle=`${data.name}${duration_ms}`;
77-
78-
if(skip!==undefined){
79-
title+=` # ${typeofskip==='string'&&skip.length ? skip : 'SKIP'}`;
80-
}elseif(todo!==undefined){
81-
title+=` # ${typeoftodo==='string'&&todo.length ? todo : 'TODO'}`;
82-
}
83-
consterror=this.#formatError(data.details?.error,indent);
84-
if(hasChildren){
85-
// If this test has had children - it was already reported, so slightly modify the output
86-
consterr=!error||data.details?.error?.failureType==='subtestsFailed' ? '' : `\n${error}`;
87-
return`${prefix}${indent}${color}${symbols['arrow:right']}${colors.white}${title}${err}`;
88-
}
89-
if(skip!==undefined){
90-
color=colors.gray;
91-
symbol=symbols['hyphen:minus'];
92-
}
93-
return`${prefix}${indent}${color}${symbol}${title}${colors.white}${error}`;
94-
}
9533
#handleTestReportEvent(type,data){
9634
constsubtest=ArrayPrototypeShift(this.#stack);// This is the matching `test:start` event
9735
if(subtest){
@@ -106,15 +44,15 @@ class SpecReporter extends Transform {
10644
assert(parent.type==='test:start');
10745
constmsg=parent.data;
10846
ArrayPrototypeUnshift(this.#reported,msg);
109-
prefix+=`${this.#indent(msg.nesting)}${symbols['arrow:right']}${msg.name}\n`;
47+
prefix+=`${indent(msg.nesting)}${reporterUnicodeSymbolMap['arrow:right']}${msg.name}\n`;
11048
}
11149
lethasChildren=false;
11250
if(this.#reported[0]&&this.#reported[0].nesting===data.nesting&&this.#reported[0].name===data.name){
11351
ArrayPrototypeShift(this.#reported);
11452
hasChildren=true;
11553
}
116-
constindent=this.#indent(data.nesting);
117-
return`${this.#formatTestReport(type,data,prefix,indent,hasChildren)}\n`;
54+
constindentation=indent(data.nesting);
55+
return`${formatTestReport(type,data,prefix,indentation,hasChildren)}\n`;
11856
}
11957
#handleEvent({ type, data }){
12058
switch(type){
@@ -132,9 +70,10 @@ class SpecReporter extends Transform {
13270
case'test:stdout':
13371
returndata.message;
13472
case'test:diagnostic':
135-
return`${this.#colors[type]}${this.#indent(data.nesting)}${symbols[type]}${data.message}${colors.white}\n`;
73+
return`${reporterColorMap[type]}${indent(data.nesting)}${reporterUnicodeSymbolMap[type]}${data.message}${colors.white}\n`;
13674
case'test:coverage':
137-
returngetCoverageReport(this.#indent(data.nesting),data.summary,symbols['test:coverage'],colors.blue,true);
75+
returngetCoverageReport(indent(data.nesting),data.summary,
76+
reporterUnicodeSymbolMap['test:coverage'],colors.blue,true);
13877
}
13978
}
14079
_transform({ type, data },encoding,callback){
@@ -145,10 +84,10 @@ class SpecReporter extends Transform {
14584
callback(null,'');
14685
return;
14786
}
148-
constresults=[`\n${this.#colors['test:fail']}${symbols['test:fail']}failing tests:${colors.white}\n`];
87+
constresults=[`\n${reporterColorMap['test:fail']}${reporterUnicodeSymbolMap['test:fail']}failing tests:${colors.white}\n`];
14988
for(leti=0;i<this.#failedTests.length;i++){
15089
consttest=this.#failedTests[i];
151-
constformattedErr=this.#formatTestReport('test:fail',test);
90+
constformattedErr=formatTestReport('test:fail',test);
15291

15392
if(test.file){
15493
constrelPath=relative(this.#cwd,test.file);
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
'use strict';
2+
const{
3+
ArrayPrototypeJoin,
4+
RegExpPrototypeSymbolSplit,
5+
SafeMap,
6+
StringPrototypeRepeat,
7+
hardenRegExp,
8+
}=primordials;
9+
constcolors=require('internal/util/colors');
10+
const{ inspectWithNoCustomRetry }=require('internal/errors');
11+
constindentMemo=newSafeMap();
12+
13+
constinspectOptions={
14+
__proto__: null,
15+
colors: colors.shouldColorize(process.stdout),
16+
breakLength: Infinity,
17+
};
18+
19+
constreporterUnicodeSymbolMap={
20+
'__proto__': null,
21+
'test:fail': '\u2716 ',
22+
'test:pass': '\u2714 ',
23+
'test:diagnostic': '\u2139 ',
24+
'test:coverage': '\u2139 ',
25+
'arrow:right': '\u25B6 ',
26+
'hyphen:minus': '\uFE63 ',
27+
};
28+
29+
constreporterColorMap={
30+
'__proto__': null,
31+
get'test:fail'(){
32+
returncolors.red;
33+
},
34+
get'test:pass'(){
35+
returncolors.green;
36+
},
37+
get'test:diagnostic'(){
38+
returncolors.blue;
39+
},
40+
};
41+
42+
functionindent(nesting){
43+
letvalue=indentMemo.get(nesting);
44+
if(value===undefined){
45+
value=StringPrototypeRepeat(' ',nesting);
46+
indentMemo.set(nesting,value);
47+
}
48+
returnvalue;
49+
}
50+
51+
functionformatError(error,indent){
52+
if(!error)return'';
53+
consterr=error.code==='ERR_TEST_FAILURE' ? error.cause : error;
54+
constmessage=ArrayPrototypeJoin(
55+
RegExpPrototypeSymbolSplit(
56+
hardenRegExp(/\r?\n/),
57+
inspectWithNoCustomRetry(err,inspectOptions),
58+
),`\n${indent} `);
59+
return`\n${indent}${message}\n`;
60+
}
61+
62+
functionformatTestReport(type,data,prefix='',indent='',hasChildren=false){
63+
letcolor=reporterColorMap[type]??colors.white;
64+
letsymbol=reporterUnicodeSymbolMap[type]??' ';
65+
const{ skip, todo }=data;
66+
constduration_ms=data.details?.duration_ms ? ` ${colors.gray}(${data.details.duration_ms}ms)${colors.white}` : '';
67+
lettitle=`${data.name}${duration_ms}`;
68+
69+
if(skip!==undefined){
70+
title+=` # ${typeofskip==='string'&&skip.length ? skip : 'SKIP'}`;
71+
}elseif(todo!==undefined){
72+
title+=` # ${typeoftodo==='string'&&todo.length ? todo : 'TODO'}`;
73+
}
74+
consterror=formatError(data.details?.error,indent);
75+
if(hasChildren){
76+
// If this test has had children - it was already reported, so slightly modify the output
77+
consterr=!error||data.details?.error?.failureType==='subtestsFailed' ? '' : `\n${error}`;
78+
return`${prefix}${indent}${color}${reporterUnicodeSymbolMap['arrow:right']}${colors.white}${title}${err}`;
79+
}
80+
if(skip!==undefined){
81+
color=colors.gray;
82+
symbol=reporterUnicodeSymbolMap['hyphen:minus'];
83+
}
84+
return`${prefix}${indent}${color}${symbol}${title}${colors.white}${error}`;
85+
}
86+
87+
module.exports={
88+
__proto__: null,
89+
reporterUnicodeSymbolMap,
90+
reporterColorMap,
91+
formatTestReport,
92+
indent,
93+
};

0 commit comments

Comments
 (0)