From cc725a653af24bce6302a60c3f96a58ab3f4ee5b Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Thu, 28 Sep 2023 11:57:38 +0200 Subject: [PATCH] errors: improve performance of instantiation PR-URL: https://github.com/nodejs/node/pull/49654 Reviewed-By: Matteo Collina Reviewed-By: Yagiz Nizipli Reviewed-By: Stephen Belanger Reviewed-By: Joyee Cheung Reviewed-By: Raz Luvaton --- benchmark/{misc => error}/hidestackframes.js | 0 benchmark/error/node-error-instantiation.js | 66 ++++++++ benchmark/error/node-error-stack.js | 62 ++++++++ benchmark/error/node-error.js | 21 --- lib/internal/crypto/hkdf.js | 2 +- lib/internal/errors.js | 150 +++++++++++++----- lib/internal/fs/streams.js | 4 +- lib/internal/modules/esm/hooks.js | 4 +- lib/internal/navigator.js | 2 +- lib/internal/url.js | 2 +- lib/stream.js | 4 +- test/common/index.js | 3 +- .../output/junit_reporter.snapshot | 102 ++++++------ .../test-runner/output/spec_reporter.snapshot | 8 +- .../output/spec_reporter_cli.snapshot | 8 +- test/message/internal_assert.out | 1 - test/message/internal_assert_fail.out | 1 - test/parallel/test-repl-top-level-await.js | 4 +- 18 files changed, 306 insertions(+), 138 deletions(-) rename benchmark/{misc => error}/hidestackframes.js (100%) create mode 100644 benchmark/error/node-error-instantiation.js create mode 100644 benchmark/error/node-error-stack.js delete mode 100644 benchmark/error/node-error.js diff --git a/benchmark/misc/hidestackframes.js b/benchmark/error/hidestackframes.js similarity index 100% rename from benchmark/misc/hidestackframes.js rename to benchmark/error/hidestackframes.js diff --git a/benchmark/error/node-error-instantiation.js b/benchmark/error/node-error-instantiation.js new file mode 100644 index 00000000000000..333087b9195894 --- /dev/null +++ b/benchmark/error/node-error-instantiation.js @@ -0,0 +1,66 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const bench = common.createBenchmark(main, { + n: [1e6], + code: [ + 'built-in', + 'ERR_HTTP2_STREAM_SELF_DEPENDENCY', + 'ERR_INVALID_STATE', + 'ERR_INVALID_URL', + ], + stackTraceLimit: [0, 10], +}, { + flags: ['--expose-internals'], +}); + +function getErrorFactory(code) { + const { + ERR_HTTP2_STREAM_SELF_DEPENDENCY, + ERR_INVALID_STATE, + ERR_INVALID_URL, + } = require('internal/errors').codes; + + switch (code) { + case 'built-in': + return (n) => new Error(); + case 'ERR_HTTP2_STREAM_SELF_DEPENDENCY': + return (n) => new ERR_HTTP2_STREAM_SELF_DEPENDENCY(); + case 'ERR_INVALID_STATE': + return (n) => new ERR_INVALID_STATE(n + ''); + case 'ERR_INVALID_URL': + return (n) => new ERR_INVALID_URL({ input: n + '' }); + default: + throw new Error(`${code} not supported`); + } +} + +function main({ n, code, stackTraceLimit }) { + const getError = getErrorFactory(code); + + Error.stackTraceLimit = stackTraceLimit; + + // Warm up. + const length = 1024; + const array = []; + for (let i = 0; i < length; ++i) { + array.push(getError(i)); + } + + bench.start(); + + for (let i = 0; i < n; ++i) { + const index = i % length; + array[index] = getError(index); + } + + bench.end(n); + + // Verify the entries to prevent dead code elimination from making + // the benchmark invalid. + for (let i = 0; i < length; ++i) { + assert.strictEqual(typeof array[i], 'object'); + } +} diff --git a/benchmark/error/node-error-stack.js b/benchmark/error/node-error-stack.js new file mode 100644 index 00000000000000..06319ccd17105f --- /dev/null +++ b/benchmark/error/node-error-stack.js @@ -0,0 +1,62 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const bench = common.createBenchmark(main, { + n: [1e6], + code: [ + 'built-in', + 'ERR_HTTP2_STREAM_SELF_DEPENDENCY', + 'ERR_INVALID_STATE', + ], + stackTraceLimit: [0, 10], +}, { + flags: ['--expose-internals'], +}); + +function getErrorStackFactory(code) { + const { + ERR_INVALID_STATE, + ERR_HTTP2_STREAM_SELF_DEPENDENCY, + } = require('internal/errors').codes; + + switch (code) { + case 'built-in': + return (n) => new Error().stack; + case 'ERR_HTTP2_STREAM_SELF_DEPENDENCY': + return (n) => new ERR_HTTP2_STREAM_SELF_DEPENDENCY().stack; + case 'ERR_INVALID_STATE': + return (n) => new ERR_INVALID_STATE(n + '').stack; + default: + throw new Error(`${code} not supported`); + } +} + +function main({ n, code, stackTraceLimit }) { + const getStack = getErrorStackFactory(code); + + Error.stackTraceLimit = stackTraceLimit; + + // Warm up. + const length = 1024; + const array = []; + for (let i = 0; i < length; ++i) { + array.push(getStack(i)); + } + + bench.start(); + + for (let i = 0; i < n; ++i) { + const index = i % length; + array[index] = getStack(index); + } + + bench.end(n); + + // Verify the entries to prevent dead code elimination from making + // the benchmark invalid. + for (let i = 0; i < length; ++i) { + assert.strictEqual(typeof array[i], 'string'); + } +} diff --git a/benchmark/error/node-error.js b/benchmark/error/node-error.js deleted file mode 100644 index 3a0aef91f04a06..00000000000000 --- a/benchmark/error/node-error.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const common = require('../common'); - -const bench = common.createBenchmark(main, { - n: [1e7], -}, { - flags: ['--expose-internals'], -}); - -function main({ n }) { - const { - codes: { - ERR_INVALID_STATE, - }, - } = require('internal/errors'); - bench.start(); - for (let i = 0; i < n; ++i) - new ERR_INVALID_STATE.TypeError('test'); - bench.end(n); -} diff --git a/lib/internal/crypto/hkdf.js b/lib/internal/crypto/hkdf.js index 7f0fe5534ee843..cf3c39e8d9da5a 100644 --- a/lib/internal/crypto/hkdf.js +++ b/lib/internal/crypto/hkdf.js @@ -57,7 +57,7 @@ const validateParameters = hideStackFrames((hash, key, salt, info, length) => { validateInteger(length, 'length', 0, kMaxLength); if (info.byteLength > 1024) { - throw ERR_OUT_OF_RANGE( + throw new ERR_OUT_OF_RANGE( 'info', 'must not contain more than 1024 bytes', info.byteLength); diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 4e332e1ce18d16..6bba8ec095e86e 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -175,9 +175,10 @@ const aggregateErrors = hideStackFrames((errors, message, code) => { return err; }); +const assert = require('internal/assert'); + // Lazily loaded let util; -let assert; let internalUtil = null; function lazyInternalUtil() { @@ -371,42 +372,103 @@ function makeSystemErrorWithCode(key) { } function makeNodeErrorWithCode(Base, key) { - return function NodeError(...args) { - const limit = Error.stackTraceLimit; - if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0; - const error = new Base(); - // Reset the limit and setting the name property. - if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit; - const message = getMessage(key, args, error); - ObjectDefineProperties(error, { - [kIsNodeError]: { - __proto__: null, - value: true, - enumerable: false, - writable: false, - configurable: true, - }, - message: { - __proto__: null, - value: message, - enumerable: false, - writable: true, - configurable: true, - }, - toString: { - __proto__: null, - value() { + const msg = messages.get(key); + const expectedLength = typeof msg !== 'string' ? -1 : getExpectedArgumentLength(msg); + + switch (expectedLength) { + case 0: { + class NodeError extends Base { + code = key; + + constructor(...args) { + assert( + args.length === 0, + `Code: ${key}; The provided arguments length (${args.length}) does not ` + + `match the required ones (${expectedLength}).`, + ); + super(msg); + } + + // This is a workaround for wpt tests that expect that the error + // constructor has a `name` property of the base class. + get ['constructor']() { + return Base; + } + + get [kIsNodeError]() { + return true; + } + + toString() { return `${this.name} [${key}]: ${this.message}`; - }, - enumerable: false, - writable: true, - configurable: true, - }, - }); - captureLargerStackTrace(error); - error.code = key; - return error; - }; + } + } + return NodeError; + } + case -1: { + class NodeError extends Base { + code = key; + + constructor(...args) { + super(); + ObjectDefineProperty(this, 'message', { + __proto__: null, + value: getMessage(key, args, this), + enumerable: false, + writable: true, + configurable: true, + }); + } + + // This is a workaround for wpt tests that expect that the error + // constructor has a `name` property of the base class. + get ['constructor']() { + return Base; + } + + get [kIsNodeError]() { + return true; + } + + toString() { + return `${this.name} [${key}]: ${this.message}`; + } + } + return NodeError; + } + default: { + + class NodeError extends Base { + code = key; + + constructor(...args) { + assert( + args.length === expectedLength, + `Code: ${key}; The provided arguments length (${args.length}) does not ` + + `match the required ones (${expectedLength}).`, + ); + + ArrayPrototypeUnshift(args, msg); + super(ReflectApply(lazyInternalUtilInspect().format, null, args)); + } + + // This is a workaround for wpt tests that expect that the error + // constructor has a `name` property of the base class. + get ['constructor']() { + return Base; + } + + get [kIsNodeError]() { + return true; + } + + toString() { + return `${this.name} [${key}]: ${this.message}`; + } + } + return NodeError; + } + } } /** @@ -443,11 +505,16 @@ function E(sym, val, def, ...otherClasses) { codes[sym] = def; } +function getExpectedArgumentLength(msg) { + let expectedLength = 0; + const regex = /%[dfijoOs]/g; + while (RegExpPrototypeExec(regex, msg) !== null) expectedLength++; + return expectedLength; +} + function getMessage(key, args, self) { const msg = messages.get(key); - assert ??= require('internal/assert'); - if (typeof msg === 'function') { assert( msg.length <= args.length, // Default options do not count. @@ -457,9 +524,7 @@ function getMessage(key, args, self) { return ReflectApply(msg, self, args); } - const regex = /%[dfijoOs]/g; - let expectedLength = 0; - while (RegExpPrototypeExec(regex, msg) !== null) expectedLength++; + const expectedLength = getExpectedArgumentLength(msg); assert( expectedLength === args.length, `Code: ${key}; The provided arguments length (${args.length}) does not ` + @@ -1476,8 +1541,7 @@ E('ERR_NETWORK_IMPORT_DISALLOWED', "import of '%s' by %s is not supported: %s", Error); E('ERR_NOT_BUILDING_SNAPSHOT', 'Operation cannot be invoked when not building startup snapshot', Error); -E('ERR_NOT_SUPPORTED_IN_SNAPSHOT', - '%s is not supported in startup snapshot', Error); +E('ERR_NOT_SUPPORTED_IN_SNAPSHOT', '%s is not supported in startup snapshot', Error); E('ERR_NO_CRYPTO', 'Node.js is not compiled with OpenSSL crypto support', Error); E('ERR_NO_ICU', diff --git a/lib/internal/fs/streams.js b/lib/internal/fs/streams.js index c317f3b9202af9..6a213693342b94 100644 --- a/lib/internal/fs/streams.js +++ b/lib/internal/fs/streams.js @@ -143,8 +143,8 @@ function importFd(stream, options) { return options.fd.fd; } - throw ERR_INVALID_ARG_TYPE('options.fd', - ['number', 'FileHandle'], options.fd); + throw new ERR_INVALID_ARG_TYPE('options.fd', + ['number', 'FileHandle'], options.fd); } function ReadStream(path, options) { diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 8ad4d00bbfe06f..8dd81ca52c5318 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -407,7 +407,7 @@ class Hooks { !isAnyArrayBuffer(source) && !isArrayBufferView(source) ) { - throw ERR_INVALID_RETURN_PROPERTY_VALUE( + throw new ERR_INVALID_RETURN_PROPERTY_VALUE( 'a string, an ArrayBuffer, or a TypedArray', hookErrIdentifier, 'source', @@ -599,7 +599,7 @@ class HooksProxy { if (status === 'error') { if (body == null || typeof body !== 'object') { throw body; } if (body.serializationFailed || body.serialized == null) { - throw ERR_WORKER_UNSERIALIZABLE_ERROR(); + throw new ERR_WORKER_UNSERIALIZABLE_ERROR(); } // eslint-disable-next-line no-restricted-syntax diff --git a/lib/internal/navigator.js b/lib/internal/navigator.js index 3b8343cd7ed6f8..5971891ea73cc9 100644 --- a/lib/internal/navigator.js +++ b/lib/internal/navigator.js @@ -27,7 +27,7 @@ class Navigator { if (arguments[0] === kInitialize) { return; } - throw ERR_ILLEGAL_CONSTRUCTOR(); + throw new ERR_ILLEGAL_CONSTRUCTOR(); } /** diff --git a/lib/internal/url.js b/lib/internal/url.js index 13a9e287ffc47a..ca41c48582b19d 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -855,7 +855,7 @@ class URL { set href(value) { value = `${value}`; const href = bindingUrl.update(this.#context.href, updateActions.kHref, value); - if (!href) { throw ERR_INVALID_URL(value); } + if (!href) { throw new ERR_INVALID_URL(value); } this.#updateContext(href); } diff --git a/lib/stream.js b/lib/stream.js index 9a09401e7d016a..cdbc1fe0380694 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -64,7 +64,7 @@ for (const key of ObjectKeys(streamReturningOperators)) { const op = streamReturningOperators[key]; function fn(...args) { if (new.target) { - throw ERR_ILLEGAL_CONSTRUCTOR(); + throw new ERR_ILLEGAL_CONSTRUCTOR(); } return Stream.Readable.from(ReflectApply(op, this, args)); } @@ -82,7 +82,7 @@ for (const key of ObjectKeys(promiseReturningOperators)) { const op = promiseReturningOperators[key]; function fn(...args) { if (new.target) { - throw ERR_ILLEGAL_CONSTRUCTOR(); + throw new ERR_ILLEGAL_CONSTRUCTOR(); } return ReflectApply(op, this, args); } diff --git a/test/common/index.js b/test/common/index.js index c10dea59319264..338e773a353eff 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -720,9 +720,8 @@ function expectsError(validator, exact) { assert.fail(`Expected one argument, got ${inspect(args)}`); } const error = args.pop(); - const descriptor = Object.getOwnPropertyDescriptor(error, 'message'); // The error message should be non-enumerable - assert.strictEqual(descriptor.enumerable, false); + assert.strictEqual(Object.prototype.propertyIsEnumerable.call(error, 'message'), false); assert.throws(() => { throw error; }, validator); return true; diff --git a/test/fixtures/test-runner/output/junit_reporter.snapshot b/test/fixtures/test-runner/output/junit_reporter.snapshot index 6516387e7ed582..e0a4c331dd5c22 100644 --- a/test/fixtures/test-runner/output/junit_reporter.snapshot +++ b/test/fixtures/test-runner/output/junit_reporter.snapshot @@ -10,6 +10,7 @@ [Error [ERR_TEST_FAILURE]: thrown from sync fail todo] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from sync fail todo * @@ -18,8 +19,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -27,6 +27,7 @@ [Error [ERR_TEST_FAILURE]: thrown from sync fail todo with message] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from sync fail todo with message * @@ -35,8 +36,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -51,6 +51,7 @@ [Error [ERR_TEST_FAILURE]: thrown from sync throw fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from sync throw fail * @@ -59,8 +60,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -71,6 +71,7 @@ [Error [ERR_TEST_FAILURE]: thrown from async throw fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from async throw fail * @@ -79,8 +80,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -88,6 +88,7 @@ [Error [ERR_TEST_FAILURE]: thrown from async throw fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from async throw fail * @@ -96,8 +97,7 @@ * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -107,6 +107,7 @@ true !== false ] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: @@ -124,8 +125,7 @@ true !== false actual: true, expected: false, operator: 'strictEqual' - }, - code: 'ERR_TEST_FAILURE' + } } @@ -133,6 +133,7 @@ true !== false [Error [ERR_TEST_FAILURE]: rejected from reject fail] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: rejected from reject fail * @@ -141,8 +142,7 @@ true !== false * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -156,6 +156,7 @@ true !== false Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from subtest sync throw fail * @@ -167,8 +168,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * * * - at Test.postRun (node:internal/test_runner/test:715:19), - code: 'ERR_TEST_FAILURE' + * } @@ -176,7 +176,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail -[Error [ERR_TEST_FAILURE]: Symbol(thrown symbol from sync throw non-error fail)] { failureType: 'testCodeFailure', cause: Symbol(thrown symbol from sync throw non-error fail), code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: Symbol(thrown symbol from sync throw non-error fail)] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Symbol(thrown symbol from sync throw non-error fail) } @@ -188,7 +188,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail -[Error [ERR_TEST_FAILURE]: test did not finish before its parent and was cancelled] { failureType: 'cancelledByParent', cause: 'test did not finish before its parent and was cancelled', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: test did not finish before its parent and was cancelled] { code: 'ERR_TEST_FAILURE', failureType: 'cancelledByParent', cause: 'test did not finish before its parent and was cancelled' } @@ -205,6 +205,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail [Error [ERR_TEST_FAILURE]: this should be executed] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: this should be executed * @@ -213,8 +214,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -236,11 +236,11 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail [Error [ERR_TEST_FAILURE]: callback failure] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: callback failure * - at process.processImmediate (node:internal/timers:478:21), - code: 'ERR_TEST_FAILURE' + * } @@ -249,12 +249,13 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail -[Error [ERR_TEST_FAILURE]: passed a callback but also returned a Promise] { failureType: 'callbackAndPromisePresent', cause: 'passed a callback but also returned a Promise', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: passed a callback but also returned a Promise] { code: 'ERR_TEST_FAILURE', failureType: 'callbackAndPromisePresent', cause: 'passed a callback but also returned a Promise' } [Error [ERR_TEST_FAILURE]: thrown from callback throw] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from callback throw * @@ -263,8 +264,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail * * * - at async Test.processPendingSubtests (node:internal/test_runner/test:374:7), - code: 'ERR_TEST_FAILURE' + * } @@ -273,9 +273,9 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail Error [ERR_TEST_FAILURE]: callback invoked multiple times * * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } @@ -284,14 +284,14 @@ Error [ERR_TEST_FAILURE]: callback invoked multiple times Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'uncaughtException', cause: Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' - }, - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' + } } @@ -299,11 +299,11 @@ Error [ERR_TEST_FAILURE]: callback invoked multiple times Error [ERR_TEST_FAILURE]: thrown from callback async throw * { + code: 'ERR_TEST_FAILURE', failureType: 'uncaughtException', cause: Error: thrown from callback async throw * - at process.processImmediate (node:internal/timers:478:21), - code: 'ERR_TEST_FAILURE' + * } @@ -319,7 +319,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw -[Error [ERR_TEST_FAILURE]: customized] { failureType: 'testCodeFailure', cause: customized, code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: customized] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: customized } @@ -328,9 +328,9 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw foo: 1, [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]] }] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', - cause: { foo: 1, [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]] }, - code: 'ERR_TEST_FAILURE' + cause: { foo: 1, [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]] } } @@ -339,6 +339,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first * { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from subtest sync throw fails at first * @@ -350,8 +351,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first * * * - at Test.postRun (node:internal/test_runner/test:715:19), - code: 'ERR_TEST_FAILURE' + * } @@ -359,6 +359,7 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second * { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: thrown from subtest sync throw fails at second * @@ -370,20 +371,19 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second * * * - at async Test.run (node:internal/test_runner/test:632:9), - code: 'ERR_TEST_FAILURE' + * } -[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { code: 'ERR_TEST_FAILURE', failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms' } -[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: test timed out after 5ms] { code: 'ERR_TEST_FAILURE', failureType: 'testTimeoutFailure', cause: 'test timed out after 5ms' } @@ -391,19 +391,19 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at second -[Error [ERR_TEST_FAILURE]: custom error] { failureType: 'testCodeFailure', cause: 'custom error', code: 'ERR_TEST_FAILURE' } +[Error [ERR_TEST_FAILURE]: custom error] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: 'custom error' } Error [ERR_TEST_FAILURE]: foo * { + code: 'ERR_TEST_FAILURE', failureType: 'uncaughtException', cause: Error: foo * * - at process.processTimers (node:internal/timers:514:7), - code: 'ERR_TEST_FAILURE' + * } @@ -411,12 +411,12 @@ Error [ERR_TEST_FAILURE]: foo Error [ERR_TEST_FAILURE]: bar * { + code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: Error: bar * * - at process.processTimers (node:internal/timers:514:7), - code: 'ERR_TEST_FAILURE' + * } @@ -435,6 +435,7 @@ should loosely deep-equal bar: 2, c: [Circular *1] }] { + code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: Expected values to be loosely deep-equal: @@ -455,8 +456,7 @@ should loosely deep-equal actual: [Object], expected: [Object], operator: 'deepEqual' - }, - code: 'ERR_TEST_FAILURE' + } } @@ -464,9 +464,9 @@ should loosely deep-equal Error [ERR_TEST_FAILURE]: test could not be started because its parent finished * { + code: 'ERR_TEST_FAILURE', failureType: 'parentAlreadyFinished', - cause: 'test could not be started because its parent finished', - code: 'ERR_TEST_FAILURE' + cause: 'test could not be started because its parent finished' } diff --git a/test/fixtures/test-runner/output/spec_reporter.snapshot b/test/fixtures/test-runner/output/spec_reporter.snapshot index 5dc05d5b43c12d..8f14dc7fc9bade 100644 --- a/test/fixtures/test-runner/output/spec_reporter.snapshot +++ b/test/fixtures/test-runner/output/spec_reporter.snapshot @@ -178,9 +178,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } callback async throw (*ms) @@ -449,9 +449,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } * diff --git a/test/fixtures/test-runner/output/spec_reporter_cli.snapshot b/test/fixtures/test-runner/output/spec_reporter_cli.snapshot index 25c22069c3b8e7..a9b70560d905b2 100644 --- a/test/fixtures/test-runner/output/spec_reporter_cli.snapshot +++ b/test/fixtures/test-runner/output/spec_reporter_cli.snapshot @@ -178,9 +178,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } callback async throw (*ms) @@ -449,9 +449,9 @@ callback called twice in future tick (*ms) Error [ERR_TEST_FAILURE]: callback invoked multiple times * { + code: 'ERR_TEST_FAILURE', failureType: 'multipleCallbackInvocations', - cause: 'callback invoked multiple times', - code: 'ERR_TEST_FAILURE' + cause: 'callback invoked multiple times' } * diff --git a/test/message/internal_assert.out b/test/message/internal_assert.out index bd25c879478083..197b863bf6ae69 100644 --- a/test/message/internal_assert.out +++ b/test/message/internal_assert.out @@ -5,7 +5,6 @@ node:internal/assert:* Error [ERR_INTERNAL_ASSERTION]: This is caused by either a bug in Node.js or incorrect usage of Node.js internals. Please open an issue with this stack trace at https://github.com/nodejs/node/issues - at new NodeError (node:internal/errors:*:*) at assert (node:internal/assert:*:*) at * (*test*message*internal_assert.js:7:1) at * diff --git a/test/message/internal_assert_fail.out b/test/message/internal_assert_fail.out index 408d6d3364470d..e6895691cda9c1 100644 --- a/test/message/internal_assert_fail.out +++ b/test/message/internal_assert_fail.out @@ -6,7 +6,6 @@ Error [ERR_INTERNAL_ASSERTION]: Unreachable! This is caused by either a bug in Node.js or incorrect usage of Node.js internals. Please open an issue with this stack trace at https://github.com/nodejs/node/issues - at new NodeError (node:internal/errors:*:*) at Function.fail (node:internal/assert:*:*) at * (*test*message*internal_assert_fail.js:7:8) at * diff --git a/test/parallel/test-repl-top-level-await.js b/test/parallel/test-repl-top-level-await.js index 1abcca75f1e2a0..c8bc26fad62e5c 100644 --- a/test/parallel/test-repl-top-level-await.js +++ b/test/parallel/test-repl-top-level-await.js @@ -207,8 +207,8 @@ async function ctrlCTest() { assert.deepStrictEqual(output.slice(0, 3), [ 'await new Promise(() => {})\r', 'Uncaught:', - 'Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: ' + - 'Script execution was interrupted by `SIGINT`', + '[Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: ' + + 'Script execution was interrupted by `SIGINT`] {', ]); assert.deepStrictEqual(output.slice(-2), [ '}',