Skip to content

Commit 0948693

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 91c9ce5 commit 0948693

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
@@ -170,6 +170,11 @@ function getCachedCodeType(mode, sourceMap) {
170170
returnkStrippedTypeScript;
171171
}
172172

173+
functionstripTypeScriptTypesForCoverage(code){
174+
validateString(code,'code');
175+
returnprocessTypeScriptCode(code,{mode: 'strip-only'});
176+
}
177+
173178
/**
174179
* Performs type-stripping to TypeScript source code internally.
175180
* It is used by internal loaders.
@@ -236,4 +241,5 @@ function addSourceMap(code, sourceMap) {
236241
module.exports={
237242
stripTypeScriptModuleTypes,
238243
stripTypeScriptTypes,
244+
stripTypeScriptTypesForCoverage,
239245
};

‎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,
@@ -45,6 +46,20 @@ const kIgnoreRegex = /\/\* node:coverage ignore next (?<count>\d+ )?\*\//;
4546
constkLineEndingRegex=/\r?\n$/u;
4647
constkLineSplitRegex=/(?<=\r?\n)/u;
4748
constkStatusRegex=/\/\*node:coverage(?<status>enable|disable)\*\//;
49+
constkTypeOnlyImportRegex=/^\s*import\s+type\b/u;
50+
constkTypeScriptSourceRegex=/\.(?:cts|mts|ts)$/u;
51+
52+
letstripTypeScriptTypesForCoverage;
53+
54+
functiongetStripTypeScriptTypesForCoverage(){
55+
if(!process.config.variables.node_use_amaro){
56+
return;
57+
}
58+
59+
stripTypeScriptTypesForCoverage??=
60+
require('internal/modules/typescript').stripTypeScriptTypesForCoverage;
61+
returnstripTypeScriptTypesForCoverage;
62+
}
4863

4964
classCoverageLine{
5065
constructor(line,startOffset,src,length=src?.length){
@@ -70,6 +85,7 @@ class TestCoverage {
7085
}
7186

7287
#sourceLines =newSafeMap();
88+
#typeScriptLines =newSafeSet();
7389

7490
getLines(fileUrl,source){
7591
// Split the file source into lines. Make sure the lines maintain their
@@ -134,6 +150,57 @@ class TestCoverage {
134150
returnlines;
135151
}
136152

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

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)