Skip to content

Commit aee022c

Browse files
committed
test: put helper in test-runner-output into common
1 parent 5dd478c commit aee022c

File tree

2 files changed

+114
-95
lines changed

2 files changed

+114
-95
lines changed

test/common/assertSnapshot.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const path = require('node:path');
44
const test = require('node:test');
55
const fs = require('node:fs/promises');
66
const assert = require('node:assert/strict');
7+
const { hostname } = require('node:os');
78

89
const stackFramesRegexp = /(?<=\n)(\s+)((.+?)\s+\()?(?:\(?(.+?):(\d+)(?::(\d+))?)\)?(\s+\{)?(\[\d+m)?(\n|$)/g;
910
const windowNewlineRegexp = /\r/g;
@@ -100,6 +101,97 @@ async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ...
100101
await assertSnapshot(transform(`${stdout}${stderr}`), filename);
101102
}
102103

104+
function replaceTestDuration(str) {
105+
return str
106+
.replaceAll(/duration_ms: [0-9.]+/g, 'duration_ms: *')
107+
.replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *');
108+
}
109+
110+
const root = path.resolve(__dirname, '..', '..');
111+
const color = '(\\[\\d+m)';
112+
const stackTraceBasePath = new RegExp(`${color}\\(${root.replaceAll(/[\\^$*+?.()|[\]{}]/g, '\\$&')}/?${color}(.*)${color}\\)`, 'g');
113+
114+
function replaceSpecDuration(str) {
115+
return str
116+
.replaceAll(/[0-9.]+ms/g, '*ms')
117+
.replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *')
118+
.replace(stackTraceBasePath, '$3');
119+
}
120+
121+
function replaceJunitDuration(str) {
122+
return str
123+
.replaceAll(/time="[0-9.]+"/g, 'time="*"')
124+
.replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *')
125+
.replaceAll(`hostname="${hostname()}"`, 'hostname="HOSTNAME"')
126+
.replaceAll(/file="[^"]*"/g, 'file="*"')
127+
.replace(stackTraceBasePath, '$3');
128+
}
129+
130+
function removeWindowsPathEscaping(str) {
131+
return common.isWindows ? str.replaceAll(/\\\\/g, '\\') : str;
132+
}
133+
134+
function replaceTestLocationLine(str) {
135+
return str.replaceAll(/(js:)(\d+)(:\d+)/g, '$1(LINE)$3');
136+
}
137+
138+
// The Node test coverage returns results for all files called by the test. This
139+
// will make the output file change if files like test/common/index.js change.
140+
// This transform picks only the first line and then the lines from the test
141+
// file.
142+
function pickTestFileFromLcov(str) {
143+
const lines = str.split(/\n/);
144+
const firstLineOfTestFile = lines.findIndex(
145+
(line) => line.startsWith('SF:') && line.trim().endsWith('output.js'),
146+
);
147+
const lastLineOfTestFile = lines.findIndex(
148+
(line, index) => index > firstLineOfTestFile && line.trim() === 'end_of_record',
149+
);
150+
return (
151+
lines[0] + '\n' + lines.slice(firstLineOfTestFile, lastLineOfTestFile + 1).join('\n') + '\n'
152+
);
153+
}
154+
155+
const defaultTransform = transform(
156+
replaceWindowsLineEndings,
157+
replaceStackTrace,
158+
removeWindowsPathEscaping,
159+
transformProjectRoot(),
160+
replaceWindowsPaths,
161+
replaceTestDuration,
162+
replaceTestLocationLine,
163+
);
164+
const specTransform = transform(
165+
replaceSpecDuration,
166+
replaceWindowsLineEndings,
167+
replaceStackTrace,
168+
replaceWindowsPaths,
169+
);
170+
const junitTransform = transform(
171+
replaceJunitDuration,
172+
replaceWindowsLineEndings,
173+
replaceStackTrace,
174+
replaceWindowsPaths,
175+
);
176+
const lcovTransform = transform(
177+
replaceWindowsLineEndings,
178+
replaceStackTrace,
179+
transformProjectRoot(),
180+
replaceWindowsPaths,
181+
pickTestFileFromLcov,
182+
);
183+
184+
function ensureCwdIsProjectRoot() {
185+
if (process.cwd() !== root) {
186+
process.chdir(root);
187+
}
188+
}
189+
190+
function canColorize() {
191+
// Loading it lazily to avoid breaking `NODE_REGENERATE_SNAPSHOTS`.
192+
return require('internal/tty').getColorDepth() > 2;
193+
}
194+
103195
module.exports = {
104196
assertSnapshot,
105197
getSnapshotPath,
@@ -111,4 +203,11 @@ module.exports = {
111203
spawnAndAssert,
112204
transform,
113205
transformProjectRoot,
206+
replaceTestDuration,
207+
defaultTransform,
208+
specTransform,
209+
junitTransform,
210+
lcovTransform,
211+
ensureCwdIsProjectRoot,
212+
canColorize,
114213
};

test/parallel/test-runner-output.mjs

Lines changed: 15 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -3,100 +3,23 @@ import * as common from '../common/index.mjs';
33
import * as fixtures from '../common/fixtures.mjs';
44
import * as snapshot from '../common/assertSnapshot.js';
55
import { describe, it } from 'node:test';
6-
import { hostname } from 'node:os';
7-
import { chdir, cwd } from 'node:process';
8-
import { fileURLToPath } from 'node:url';
6+
7+
const {
8+
defaultTransform,
9+
specTransform,
10+
junitTransform,
11+
lcovTransform,
12+
replaceTestDuration,
13+
ensureCwdIsProjectRoot,
14+
canColorize,
15+
} = snapshot;
16+
17+
ensureCwdIsProjectRoot();
918

1019
const skipForceColors =
1120
process.config.variables.icu_gyp_path !== 'tools/icu/icu-generic.gyp' ||
1221
process.config.variables.node_shared_openssl;
1322

14-
// We're using dynamic import here to not break `NODE_REGENERATE_SNAPSHOTS`.
15-
const canColorize = (await import('internal/tty')).default.getColorDepth() > 2;
16-
const skipCoverageColors = !canColorize;
17-
18-
function replaceTestDuration(str) {
19-
return str
20-
.replaceAll(/duration_ms: [0-9.]+/g, 'duration_ms: *')
21-
.replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *');
22-
}
23-
24-
const root = fileURLToPath(new URL('../..', import.meta.url)).slice(0, -1);
25-
26-
const color = '(\\[\\d+m)';
27-
const stackTraceBasePath = new RegExp(`${color}\\(${root.replaceAll(/[\\^$*+?.()|[\]{}]/g, '\\$&')}/?${color}(.*)${color}\\)`, 'g');
28-
29-
function replaceSpecDuration(str) {
30-
return str
31-
.replaceAll(/[0-9.]+ms/g, '*ms')
32-
.replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *')
33-
.replace(stackTraceBasePath, '$3');
34-
}
35-
36-
function replaceJunitDuration(str) {
37-
return str
38-
.replaceAll(/time="[0-9.]+"/g, 'time="*"')
39-
.replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *')
40-
.replaceAll(`hostname="${hostname()}"`, 'hostname="HOSTNAME"')
41-
.replaceAll(/file="[^"]*"/g, 'file="*"')
42-
.replace(stackTraceBasePath, '$3');
43-
}
44-
45-
function removeWindowsPathEscaping(str) {
46-
return common.isWindows ? str.replaceAll(/\\\\/g, '\\') : str;
47-
}
48-
49-
function replaceTestLocationLine(str) {
50-
return str.replaceAll(/(js:)(\d+)(:\d+)/g, '$1(LINE)$3');
51-
}
52-
53-
// The Node test coverage returns results for all files called by the test. This
54-
// will make the output file change if files like test/common/index.js change.
55-
// This transform picks only the first line and then the lines from the test
56-
// file.
57-
function pickTestFileFromLcov(str) {
58-
const lines = str.split(/\n/);
59-
const firstLineOfTestFile = lines.findIndex(
60-
(line) => line.startsWith('SF:') && line.trim().endsWith('output.js')
61-
);
62-
const lastLineOfTestFile = lines.findIndex(
63-
(line, index) => index > firstLineOfTestFile && line.trim() === 'end_of_record'
64-
);
65-
return (
66-
lines[0] + '\n' + lines.slice(firstLineOfTestFile, lastLineOfTestFile + 1).join('\n') + '\n'
67-
);
68-
}
69-
70-
const defaultTransform = snapshot.transform(
71-
snapshot.replaceWindowsLineEndings,
72-
snapshot.replaceStackTrace,
73-
removeWindowsPathEscaping,
74-
snapshot.transformProjectRoot(),
75-
snapshot.replaceWindowsPaths,
76-
replaceTestDuration,
77-
replaceTestLocationLine,
78-
);
79-
const specTransform = snapshot.transform(
80-
replaceSpecDuration,
81-
snapshot.replaceWindowsLineEndings,
82-
snapshot.replaceStackTrace,
83-
snapshot.replaceWindowsPaths,
84-
);
85-
const junitTransform = snapshot.transform(
86-
replaceJunitDuration,
87-
snapshot.replaceWindowsLineEndings,
88-
snapshot.replaceStackTrace,
89-
snapshot.replaceWindowsPaths,
90-
);
91-
const lcovTransform = snapshot.transform(
92-
snapshot.replaceWindowsLineEndings,
93-
snapshot.replaceStackTrace,
94-
snapshot.transformProjectRoot(),
95-
snapshot.replaceWindowsPaths,
96-
pickTestFileFromLcov
97-
);
98-
99-
10023
const tests = [
10124
{ name: 'test-runner/output/abort.js', flags: ['--test-reporter=tap'] },
10225
{
@@ -225,7 +148,7 @@ const tests = [
225148
name: 'test-runner/output/non-tty-forced-color-output.js',
226149
transform: specTransform,
227150
},
228-
canColorize ? {
151+
canColorize() ? {
229152
name: 'test-runner/output/assertion-color-tty.mjs',
230153
flags: ['--test', '--stack-trace-limit=0'],
231154
transform: specTransform,
@@ -276,7 +199,7 @@ const tests = [
276199
name: 'test-runner/output/coverage-width-80.mjs',
277200
flags: ['--test-reporter=tap', '--test-coverage-exclude=!test/**'],
278201
} : false,
279-
process.features.inspector && !skipCoverageColors ? {
202+
process.features.inspector && canColorize() ? {
280203
name: 'test-runner/output/coverage-width-80-color.mjs',
281204
flags: ['--test-coverage-exclude=!test/**'],
282205
transform: specTransform,
@@ -302,7 +225,7 @@ const tests = [
302225
name: 'test-runner/output/coverage-width-100-uncovered-lines.mjs',
303226
flags: ['--test-reporter=tap', '--test-coverage-exclude=!test/**'],
304227
} : false,
305-
process.features.inspector && !skipCoverageColors ? {
228+
process.features.inspector && canColorize() ? {
306229
name: 'test-runner/output/coverage-width-80-uncovered-lines-color.mjs',
307230
flags: ['--test-coverage-exclude=!test/**'],
308231
transform: specTransform,
@@ -348,9 +271,6 @@ const tests = [
348271
}),
349272
}));
350273

351-
if (cwd() !== root) {
352-
chdir(root);
353-
}
354274
describe('test runner output', { concurrency: true }, () => {
355275
for (const { name, fn } of tests) {
356276
it(name, fn);

0 commit comments

Comments
 (0)