Skip to content

Commit d56c6cd

Browse files
mcollinaaduh95
authored andcommitted
test_runner: ignore erased TS lines in coverage
Fixes: #54753 Signed-off-by: Matteo Collina <matteo.collina@gmail.com> PR-URL: #63510 Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com>
1 parent e3c6629 commit d56c6cd

7 files changed

Lines changed: 111 additions & 3 deletions

File tree

‎lib/internal/modules/typescript.js‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ function processTypeScriptCode(code, options) {
145145
returntransformedCode;
146146
}
147147

148+
functionstripTypeScriptTypesForCoverage(code){
149+
validateString(code,'code');
150+
returnprocessTypeScriptCode(code,{mode: 'strip-only'});
151+
}
152+
148153

149154
/**
150155
* Performs type-stripping to TypeScript source code internally.
@@ -205,4 +210,5 @@ function addSourceMap(code, sourceMap) {
205210
module.exports={
206211
stripTypeScriptModuleTypes,
207212
stripTypeScriptTypes,
213+
stripTypeScriptTypesForCoverage,
208214
};

‎lib/internal/test_runner/coverage.js‎

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
StringPrototypeIncludes,
1717
StringPrototypeLocaleCompare,
1818
StringPrototypeStartsWith,
19+
StringPrototypeTrim,
1920
}=primordials;
2021
const{
2122
copyFileSync,
@@ -44,6 +45,20 @@ const kIgnoreRegex = /\/\* node:coverage ignore next (?<count>\d+ )?\*\//;
4445
constkLineEndingRegex=/\r?\n$/u;
4546
constkLineSplitRegex=/(?<=\r?\n)/u;
4647
constkStatusRegex=/\/\*node:coverage(?<status>enable|disable)\*\//;
48+
constkTypeOnlyImportRegex=/^\s*import\s+type\b/u;
49+
constkTypeScriptSourceRegex=/\.(?:cts|mts|ts)$/u;
50+
51+
letstripTypeScriptTypesForCoverage;
52+
53+
functiongetStripTypeScriptTypesForCoverage(){
54+
if(!process.config.variables.node_use_amaro){
55+
return;
56+
}
57+
58+
stripTypeScriptTypesForCoverage??=
59+
require('internal/modules/typescript').stripTypeScriptTypesForCoverage;
60+
returnstripTypeScriptTypesForCoverage;
61+
}
4762

4863
classCoverageLine{
4964
constructor(line,startOffset,src,length=src?.length){
@@ -69,6 +84,7 @@ class TestCoverage {
6984
}
7085

7186
#sourceLines =newSafeMap();
87+
#typeScriptLines =newSafeSet();
7288

7389
getLines(fileUrl,source){
7490
// Split the file source into lines. Make sure the lines maintain their
@@ -133,6 +149,57 @@ class TestCoverage {
133149
returnlines;
134150
}
135151

152+
markTypeScriptOnlyLines(fileUrl,source){
153+
if(this.#typeScriptLines.has(fileUrl)){
154+
return;
155+
}
156+
this.#typeScriptLines.add(fileUrl);
157+
158+
if(RegExpPrototypeExec(kTypeScriptSourceRegex,fileUrl)===null){
159+
return;
160+
}
161+
162+
constlines=this.getLines(fileUrl,source);
163+
if(!lines){
164+
return;
165+
}
166+
167+
letstrippedLines;
168+
conststripSource=getStripTypeScriptTypesForCoverage();
169+
170+
if(stripSource){
171+
source??=readFileSync(fileURLToPath(fileUrl),'utf8');
172+
173+
try{
174+
strippedLines=RegExpPrototypeSymbolSplit(
175+
kLineSplitRegex,
176+
stripSource(source),
177+
);
178+
}catch{
179+
strippedLines=undefined;
180+
}
181+
}
182+
183+
for(leti=0;i<lines.length;++i){
184+
constoriginalLine=lines[i].src;
185+
186+
if(StringPrototypeTrim(originalLine).length===0){
187+
continue;
188+
}
189+
190+
if(strippedLines?.[i]!==undefined){
191+
if(StringPrototypeTrim(strippedLines[i]).length===0){
192+
lines[i].ignore=true;
193+
}
194+
continue;
195+
}
196+
197+
if(RegExpPrototypeExec(kTypeOnlyImportRegex,originalLine)!==null){
198+
lines[i].ignore=true;
199+
}
200+
}
201+
}
202+
136203
summary(){
137204
internalBinding('profiler').takeCoverage();
138205
constcoverage=this.getCoverageFromDirectory();
@@ -368,10 +435,12 @@ class TestCoverage {
368435
offset+=length+1;
369436
returncoverageLine;
370437
});
371-
if(data.sourcesContent!=null){
372-
for(letj=0;j<data.sources.length;++j){
373-
this.getLines(data.sources[j],data.sourcesContent[j]);
438+
for(letj=0;j<data.sources.length;++j){
439+
constsource=data.sourcesContent?.[j];
440+
if(source!=null){
441+
this.getLines(data.sources[j],source);
374442
}
443+
this.markTypeScriptOnlyLines(data.sources[j],source);
375444
}
376445
constsourceMap=newSourceMap(data,{__proto__: null, lineLengths });
377446

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
console.log('Hi');
2+
export{};
3+
//# sourceMappingURL=a.mjs.map

‎test/fixtures/test-runner/source-maps/type-only-import/dist/a.mjs.map‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
importtype{}from'node:assert';
2+
3+
console.log('Hi');
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import'./dist/a.mjs';

‎test/parallel/test-runner-coverage-source-map.js‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,31 @@ describe('Coverage with source maps', async () => {
7373
t.assert.strictEqual(spawned.code,1);
7474
});
7575

76+
awaitit('should ignore erased TypeScript import type lines',async(t)=>{
77+
constreport=generateReport([
78+
'# ----------------------------------------------------------',
79+
'# file | line % | branch % | funcs % | uncovered lines',
80+
'# ----------------------------------------------------------',
81+
'# src | | | | ',
82+
'# a.mts | 100.00 | 100.00 | 100.00 | ',
83+
'# test.mjs | 100.00 | 100.00 | 100.00 | ',
84+
'# ----------------------------------------------------------',
85+
'# all files | 100.00 | 100.00 | 100.00 | ',
86+
'# ----------------------------------------------------------',
87+
]);
88+
89+
constspawned=awaitcommon.spawnPromisified(process.execPath,[
90+
...flags,
91+
'test.mjs',
92+
],{
93+
cwd: fixtures.path('test-runner','source-maps','type-only-import'),
94+
});
95+
96+
t.assert.strictEqual(spawned.stderr,'');
97+
t.assert.ok(spawned.stdout.includes(report));
98+
t.assert.strictEqual(spawned.code,0);
99+
});
100+
76101
awaitit('properly accounts for line endings in source maps',async(t)=>{
77102
constreport=generateReport([
78103
'# ------------------------------------------------------------------',

0 commit comments

Comments
 (0)