| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 0cd6ba3 commit 9ad9253
77 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,11 +3,30 @@ const common = require('.'); | |||
| 3 | 3 | const path = require('node:path'); | |
| 4 | 4 | const test = require('node:test'); | |
| 5 | 5 | const fs = require('node:fs/promises'); | |
| 6 | + const { realpathSync } = require('node:fs'); | ||
| 6 | 7 | const assert = require('node:assert/strict'); | |
| 7 | 8 | const { pathToFileURL } = require('node:url'); | |
| 8 | 9 | const { hostname } = require('node:os'); | |
| 9 | 10 | ||
| 10 | - const stackFramesRegexp = /(?<=\n)(\s+)((.+?)\s+\()?(?:\(?(.+?):(\d+)(?::(\d+))?)\)?(\s+\{)?(\[\d+m)?(\n|$)/g; | ||
| 11 | + /* eslint-disable @stylistic/js/max-len,no-control-regex */ | ||
| 12 | + /** | ||
| 13 | + * Group 1: Line start (including color codes and escapes) | ||
| 14 | + * Group 2: Function name | ||
| 15 | + * Group 3: Filename | ||
| 16 | + * Group 4: Line number | ||
| 17 | + * Group 5: Column number | ||
| 18 | + * Group 6: Line end (including color codes and `{` which indicates the start of an error object details) | ||
| 19 | + */ | ||
| 20 | + // Mappings: (g1 ) (g2 ) (g3 ) (g4 ) (g5 ) (g6 ) | ||
| 21 | + const internalStackFramesRegexp = /(?<=\n)(\s*(?:\x1b?\[\d+m\s+)?(?:at\s)?)(?:(.+?)\s+\()?(?:(node:.+?):(\d+)(?::(\d+))?)\)?((?:\x1b?\[\d+m)?\s*{?\n|$)/g; | ||
| 22 | + /** | ||
| 23 | + * Group 1: Filename | ||
| 24 | + * Group 2: Line number | ||
| 25 | + * Group 3: Line end and source code line | ||
| 26 | + */ | ||
| 27 | + const internalErrorSourceLines = /(?<=\n|^)(node:.+?):(\d+)(\n.*\n\s*\^(?:\n|$))/g; | ||
| 28 | + /* eslint-enable @stylistic/js/max-len,no-control-regex */ | ||
| 29 | + | ||
| 11 | 30 | const windowNewlineRegexp = /\r/g; | |
| 12 | 31 | ||
| 13 | 32 | // Replaces the current Node.js executable version strings with a | |
@@ -17,14 +36,33 @@ function replaceNodeVersion(str) { | |||
| 17 | 36 | return str.replaceAll(`Node.js ${process.version}`, 'Node.js <node-version>'); | |
| 18 | 37 | } | |
| 19 | 38 | ||
| 20 | - function replaceStackTrace(str, replacement = '$1*$7$8\n') { | ||
| 21 | - return str.replace(stackFramesRegexp, replacement); | ||
| 39 | + // Collapse consecutive identical lines containing the keyword into | ||
| 40 | + // one single line. The `str` should have been processed by `replaceWindowsLineEndings`. | ||
| 41 | + function foldIdenticalLines(str, keyword) { | ||
| 42 | + const lines = str.split('\n'); | ||
| 43 | + const folded = lines.filter((line, idx) => { | ||
| 44 | + if (idx === 0) { | ||
| 45 | + return true; | ||
| 46 | + } | ||
| 47 | + if (line.includes(keyword) && line === lines[idx - 1]) { | ||
| 48 | + return false; | ||
| 49 | + } | ||
| 50 | + return true; | ||
| 51 | + }); | ||
| 52 | + return folded.join('\n'); | ||
| 22 | 53 | } | |
| 23 | 54 | ||
| 55 | + const kInternalFrame = '<node-internal-frames>'; | ||
| 56 | + // Replace non-internal frame `at TracingChannel.traceSync (node:diagnostics_channel:328:14)` | ||
| 57 | + // as well as `at node:internal/main/run_main_module:33:47` with `at <node-internal-frames>`. | ||
| 58 | + // Also replaces error source line like: | ||
| 59 | + // node:internal/mod.js:44 | ||
| 60 | + // throw err; | ||
| 61 | + // ^ | ||
| 24 | 62 | function replaceInternalStackTrace(str) { | |
| 25 | - // Replace non-internal frame `at TracingChannel.traceSync (node:diagnostics_channel:328:14)` | ||
| 26 | - // as well as `at node:internal/main/run_main_module:33:47` with `*`. | ||
| 27 | - return str.replaceAll(/(\W+).*[(\s]node:.*/g, '$1*'); | ||
| 63 | + const result = str.replaceAll(internalErrorSourceLines, `$1:<line>$3`) | ||
| 64 | + .replaceAll(internalStackFramesRegexp, `$1${kInternalFrame}$6`); | ||
| 65 | + return foldIdenticalLines(result, kInternalFrame); | ||
| 28 | 66 | } | |
| 29 | 67 | ||
| 30 | 68 | // Replaces Windows line endings with posix line endings for unified snapshots | |
@@ -36,7 +74,12 @@ function replaceWindowsLineEndings(str) { | |||
| 36 | 74 | // Replaces all Windows path separators with posix separators for unified snapshots | |
| 37 | 75 | // across platforms. | |
| 38 | 76 | function replaceWindowsPaths(str) { | |
| 39 | - return common.isWindows ? str.replaceAll(path.win32.sep, path.posix.sep) : str; | ||
| 77 | + if (!common.isWindows) { | ||
| 78 | + return str; | ||
| 79 | + } | ||
| 80 | + // Only replace `\` and `\\` with a leading letter, colon, or a `.`. | ||
| 81 | + // Avoid replacing escaping patterns like ` \#`, `\ `, or `\\`. | ||
| 82 | + return str.replaceAll(/(?<=(\w:|\.|\w+)(?:\S|\\ )*)\\\\?/g, '/'); | ||
| 40 | 83 | } | |
| 41 | 84 | ||
| 42 | 85 | // Removes line trailing white spaces. | |
@@ -55,30 +98,53 @@ function replaceWarningPid(str) { | |||
| 55 | 98 | return str.replaceAll(/\(node:\d+\)/g, '(node:<pid>)'); | |
| 56 | 99 | } | |
| 57 | 100 | ||
| 58 | - // Replaces path strings representing the nodejs/node repo full project root with | ||
| 59 | - // `<project-root>`. Also replaces file URLs containing the full project root path. | ||
| 60 | - // The project root path may contain unicode characters. | ||
| 61 | - function transformProjectRoot(replacement = '<project-root>') { | ||
| 62 | - const projectRoot = path.resolve(__dirname, '../..'); | ||
| 101 | + // Replaces a path with a placeholder. The path can be a platform specific path | ||
| 102 | + // or a file URL. | ||
| 103 | + function transformPath(dirname, replacement) { | ||
| 63 | 104 | // Handles output already processed by `replaceWindowsPaths`. | |
| 64 | - const winPath = replaceWindowsPaths(projectRoot); | ||
| 65 | - // Handles URL encoded project root in file URL strings as well. | ||
| 66 | - const urlEncoded = pathToFileURL(projectRoot).pathname; | ||
| 105 | + const winPath = replaceWindowsPaths(dirname); | ||
| 106 | + // Handles URL encoded path in file URL strings as well. | ||
| 107 | + const urlEncoded = pathToFileURL(dirname).pathname; | ||
| 67 | 108 | // On Windows, paths are case-insensitive, so we need to use case-insensitive | |
| 68 | 109 | // regex replacement to handle cases where the drive letter case differs. | |
| 69 | 110 | const flags = common.isWindows ? 'gi' : 'g'; | |
| 70 | 111 | const urlEncodedRegex = new RegExp(RegExp.escape(urlEncoded), flags); | |
| 71 | - const projectRootRegex = new RegExp(RegExp.escape(projectRoot), flags); | ||
| 112 | + const dirnameRegex = new RegExp(RegExp.escape(dirname), flags); | ||
| 72 | 113 | const winPathRegex = new RegExp(RegExp.escape(winPath), flags); | |
| 73 | 114 | return (str) => { | |
| 74 | 115 | return str.replaceAll('\\\'', "'") | |
| 75 | 116 | // Replace fileUrl first as `winPath` could be a substring of the fileUrl. | |
| 76 | 117 | .replaceAll(urlEncodedRegex, replacement) | |
| 77 | - .replaceAll(projectRootRegex, replacement) | ||
| 118 | + .replaceAll(dirnameRegex, replacement) | ||
| 78 | 119 | .replaceAll(winPathRegex, replacement); | |
| 79 | 120 | }; | |
| 80 | 121 | } | |
| 81 | 122 | ||
| 123 | + // Replaces path strings representing the nodejs/node repo full project root with | ||
| 124 | + // `<project-root>`. Also replaces file URLs containing the full project root path. | ||
| 125 | + // The project root path may contain unicode characters. | ||
| 126 | + const kProjectRoot = '<project-root>'; | ||
| 127 | + function transformProjectRoot() { | ||
| 128 | + const projectRoot = path.resolve(__dirname, '../..'); | ||
| 129 | + if (process.env.NODE_TEST_DIR) { | ||
| 130 | + const testDir = realpathSync(process.env.NODE_TEST_DIR); | ||
| 131 | + // On Jenkins CI, the test dir may be overridden by `NODE_TEST_DIR`. | ||
| 132 | + return transform( | ||
| 133 | + transformPath(projectRoot, kProjectRoot), | ||
| 134 | + transformPath(testDir, `${kProjectRoot}/test`), | ||
| 135 | + // TODO(legendecas): test-runner may print relative paths to the test relative to cwd. | ||
| 136 | + // It will be better if we could distinguish them from the project root. | ||
| 137 | + transformPath(path.relative(projectRoot, testDir), 'test'), | ||
| 138 | + ); | ||
| 139 | + } | ||
| 140 | + return transformPath(projectRoot, kProjectRoot); | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + // Replaces tmpdirs created by `test/common/tmpdir.js`. | ||
| 144 | + function transformTmpDir(str) { | ||
| 145 | + return str.replaceAll(/\/\.tmp\.\d+\//g, '/<tmpdir>/'); | ||
| 146 | + } | ||
| 147 | + | ||
| 82 | 148 | function transform(...args) { | |
| 83 | 149 | return (str) => args.reduce((acc, fn) => fn(acc), str); | |
| 84 | 150 | } | |
@@ -149,31 +215,18 @@ function replaceTestDuration(str) { | |||
| 149 | 215 | } | |
| 150 | 216 | ||
| 151 | 217 | const root = path.resolve(__dirname, '..', '..'); | |
| 152 | - const color = '(\\[\\d+m)'; | ||
| 153 | - const stackTraceBasePath = new RegExp(`${color}\\(${RegExp.escape(root)}/?${color}(.*)${color}\\)`, 'g'); | ||
| 154 | - | ||
| 155 | 218 | function replaceSpecDuration(str) { | |
| 156 | 219 | return str | |
| 157 | 220 | .replaceAll(/[0-9.]+ms/g, '*ms') | |
| 158 | - .replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *') | ||
| 159 | - .replace(stackTraceBasePath, '$3'); | ||
| 221 | + .replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *'); | ||
| 160 | 222 | } | |
| 161 | 223 | ||
| 162 | 224 | function replaceJunitDuration(str) { | |
| 163 | 225 | return str | |
| 164 | 226 | .replaceAll(/time="[0-9.]+"/g, 'time="*"') | |
| 165 | 227 | .replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *') | |
| 166 | 228 | .replaceAll(`hostname="${hostname()}"`, 'hostname="HOSTNAME"') | |
| 167 | - .replaceAll(/file="[^"]*"/g, 'file="*"') | ||
| 168 | - .replace(stackTraceBasePath, '$3'); | ||
| 169 | - } | ||
| 170 | - | ||
| 171 | - function removeWindowsPathEscaping(str) { | ||
| 172 | - return common.isWindows ? str.replaceAll(/\\\\/g, '\\') : str; | ||
| 173 | - } | ||
| 174 | - | ||
| 175 | - function replaceTestLocationLine(str) { | ||
| 176 | - return str.replaceAll(/(js:)(\d+)(:\d+)/g, '$1(LINE)$3'); | ||
| 229 | + .replaceAll(/file="[^"]*"/g, 'file="*"'); | ||
| 177 | 230 | } | |
| 178 | 231 | ||
| 179 | 232 | // The Node test coverage returns results for all files called by the test. This | |
@@ -194,40 +247,37 @@ function pickTestFileFromLcov(str) { | |||
| 194 | 247 | } | |
| 195 | 248 | ||
| 196 | 249 | // Transforms basic patterns like: | |
| 197 | - // - platform specific path and line endings, | ||
| 198 | - // - line trailing spaces, | ||
| 199 | - // - executable specific path and versions. | ||
| 250 | + // - platform specific path and line endings | ||
| 251 | + // - line trailing spaces | ||
| 252 | + // - executable specific path and versions | ||
| 253 | + // - project root path and tmpdir | ||
| 254 | + // - node internal stack frames | ||
| 200 | 255 | const basicTransform = transform( | |
| 201 | 256 | replaceWindowsLineEndings, | |
| 202 | 257 | replaceTrailingSpaces, | |
| 203 | - removeWindowsPathEscaping, | ||
| 204 | 258 | replaceWindowsPaths, | |
| 205 | 259 | replaceNodeVersion, | |
| 206 | 260 | generalizeExeName, | |
| 207 | 261 | replaceWarningPid, | |
| 262 | + transformProjectRoot(), | ||
| 263 | + transformTmpDir, | ||
| 264 | + replaceInternalStackTrace, | ||
| 208 | 265 | ); | |
| 209 | 266 | ||
| 210 | 267 | const defaultTransform = transform( | |
| 211 | 268 | basicTransform, | |
| 212 | - replaceStackTrace, | ||
| 213 | - transformProjectRoot(), | ||
| 214 | 269 | replaceTestDuration, | |
| 215 | - replaceTestLocationLine, | ||
| 216 | 270 | ); | |
| 217 | 271 | const specTransform = transform( | |
| 218 | 272 | replaceSpecDuration, | |
| 219 | 273 | basicTransform, | |
| 220 | - replaceStackTrace, | ||
| 221 | 274 | ); | |
| 222 | 275 | const junitTransform = transform( | |
| 223 | 276 | replaceJunitDuration, | |
| 224 | 277 | basicTransform, | |
| 225 | - replaceStackTrace, | ||
| 226 | 278 | ); | |
| 227 | 279 | const lcovTransform = transform( | |
| 228 | 280 | basicTransform, | |
| 229 | - replaceStackTrace, | ||
| 230 | - transformProjectRoot(), | ||
| 231 | 281 | pickTestFileFromLcov, | |
| 232 | 282 | ); | |
| 233 | 283 | ||
@@ -246,7 +296,6 @@ module.exports = { | |||
| 246 | 296 | assertSnapshot, | |
| 247 | 297 | getSnapshotPath, | |
| 248 | 298 | replaceNodeVersion, | |
| 249 | - replaceStackTrace, | ||
| 250 | 299 | replaceInternalStackTrace, | |
| 251 | 300 | replaceWindowsLineEndings, | |
| 252 | 301 | replaceWindowsPaths, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,9 +1,3 @@ | |||
| 1 | 1 | Trace: foo | |
| 2 | - at * | ||
| 3 | - at * | ||
| 4 | - at * | ||
| 5 | - at * | ||
| 6 | - at * | ||
| 7 | - at * | ||
| 8 | - at * | ||
| 9 | - at * | ||
| 2 | + at Object.<anonymous> (<project-root>/test/fixtures/console/console.js:5:9) | ||
| 3 | + at <node-internal-frames> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,5 @@ | |||
| 1 | 1 | before | |
| 2 | - <project-root>/test/fixtures/console/stack_overflow.js:* | ||
| 2 | + <project-root>/test/fixtures/console/stack_overflow.js:39 | ||
| 3 | 3 | JSON.stringify(array); | |
| 4 | 4 | ^ | |
| 5 | 5 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,7 @@ | |||
| 1 | 1 | Error: test | |
| 2 | 2 | at one (<project-root>/test/fixtures/async-error.js:4:9) | |
| 3 | 3 | at two (<project-root>/test/fixtures/async-error.js:17:9) | |
| 4 | - at process.processTicksAndRejections (node:internal/process/task_queues:104:5) | ||
| 4 | + at <node-internal-frames> | ||
| 5 | 5 | at async three (<project-root>/test/fixtures/async-error.js:20:3) | |
| 6 | 6 | at async four (<project-root>/test/fixtures/async-error.js:24:3) | |
| 7 | 7 | at async main (<project-root>/test/fixtures/errors/async_error_nexttick_main.js:7:5) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,10 +1,9 @@ | |||
| 1 | - node:punycode:54 | ||
| 1 | + node:punycode:<line> | ||
| 2 | 2 | throw new RangeError(errors[type]); | |
| 3 | 3 | ^ | |
| 4 | 4 | ||
| 5 | 5 | RangeError: Invalid input | |
| 6 | - at error (node:punycode:54:8) | ||
| 7 | - at Object.decode (node:punycode:247:5) | ||
| 6 | + at <node-internal-frames> | ||
| 8 | 7 | at Object.<anonymous> (<project-root>/test/fixtures/errors/core_line_numbers.js:13:10) | |
| 9 | 8 | ||
| 10 | 9 | Node.js <node-version> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,17 +1,17 @@ | |||
| 1 | - <project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:* | ||
| 1 | + <project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:15 | ||
| 2 | 2 | throw aggregateTwoErrors(err, originalError); | |
| 3 | 3 | ^ | |
| 4 | 4 | ||
| 5 | 5 | AggregateError: original | |
| 6 | - at Object.<anonymous> (<project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:*:*) { | ||
| 6 | + at Object.<anonymous> (<project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:15:7) { | ||
| 7 | 7 | code: 'ERR0', | |
| 8 | 8 | [errors]: [ | |
| 9 | 9 | Error: original | |
| 10 | - at Object.<anonymous> (<project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:*:*) { | ||
| 10 | + at Object.<anonymous> (<project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:9:23) { | ||
| 11 | 11 | code: 'ERR0' | |
| 12 | 12 | }, | |
| 13 | 13 | Error: second error | |
| 14 | - at Object.<anonymous> (<project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:*:*) { | ||
| 14 | + at Object.<anonymous> (<project-root>/test/fixtures/errors/error_aggregateTwoErrors.js:10:13) { | ||
| 15 | 15 | code: 'ERR1' | |
| 16 | 16 | } | |
| 17 | 17 | ] | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,13 +1,13 @@ | |||
| 1 | 1 | Exiting with code=1 | |
| 2 | - node:assert:* | ||
| 2 | + node:assert:<line> | ||
| 3 | 3 | throw new AssertionError(obj); | |
| 4 | 4 | ^ | |
| 5 | 5 | ||
| 6 | 6 | AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: | |
| 7 | 7 | ||
| 8 | 8 | 1 !== 2 | |
| 9 | 9 | ||
| 10 | - at Object.<anonymous> (<project-root>/test/fixtures/errors/error_exit.js:*:*) { | ||
| 10 | + at Object.<anonymous> (<project-root>/test/fixtures/errors/error_exit.js:32:8) { | ||
| 11 | 11 | generatedMessage: true, | |
| 12 | 12 | code: 'ERR_ASSERTION', | |
| 13 | 13 | actual: 1, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,12 +1,12 @@ | |||
| 1 | - node:events:* | ||
| 1 | + node:events:<line> | ||
| 2 | 2 | throw er; // Unhandled 'error' event | |
| 3 | 3 | ^ | |
| 4 | 4 | ||
| 5 | 5 | Error: foo:bar | |
| 6 | - at bar (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:*:*) | ||
| 7 | - at foo (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:*:*) | ||
| 6 | + at bar (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:9:12) | ||
| 7 | + at foo (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:12:10) | ||
| 8 | 8 | Emitted 'error' event at: | |
| 9 | - at quux (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:*:*) | ||
| 10 | - at Object.<anonymous> (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:*:*) | ||
| 9 | + at quux (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:19:6) | ||
| 10 | + at Object.<anonymous> (<project-root>/test/fixtures/errors/events_unhandled_error_common_trace.js:22:1) | ||
| 11 | 11 | ||
| 12 | 12 | Node.js <node-version> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,10 +1,10 @@ | |||
| 1 | - node:events:* | ||
| 1 | + node:events:<line> | ||
| 2 | 2 | throw er; // Unhandled 'error' event | |
| 3 | 3 | ^ | |
| 4 | 4 | ||
| 5 | 5 | Error | |
| 6 | - at Object.<anonymous> (<project-root>/test/fixtures/errors/events_unhandled_error_nexttick.js:*:*) | ||
| 6 | + at Object.<anonymous> (<project-root>/test/fixtures/errors/events_unhandled_error_nexttick.js:6:12) | ||
| 7 | 7 | Emitted 'error' event at: | |
| 8 | - at <project-root>/test/fixtures/errors/events_unhandled_error_nexttick.js:*:* | ||
| 8 | + at <project-root>/test/fixtures/errors/events_unhandled_error_nexttick.js:8:22 | ||
| 9 | 9 | ||
| 10 | 10 | Node.js <node-version> | |
| Back | FazBrowse Home | New Git URL |
0 commit comments