diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f93f5dc6e1142..5cedb0c6734d52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,7 +41,8 @@ release.
-25.8.2
+25.9.0
+25.8.2
25.8.1
25.8.0
25.7.0
diff --git a/SECURITY.md b/SECURITY.md
index d44018e915ee80..8e62ba5618b8ee 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -152,28 +152,33 @@ does not trust is considered a vulnerability:
the correct use of Node.js APIs.
* The unavailability of the runtime, including the unbounded degradation of its
performance.
-* Memory leaks qualify as vulnerabilities when all of the following criteria are met:
- * The API is being correctly used.
- * The API doesn't have a warning against its usage in a production environment.
- * The API is public and documented.
- * The API is on stable (2.0) status.
- * The memory leak is significant enough to cause a denial of service quickly
- or in a context not controlled by the user (for example, HTTP parsing).
- * The memory leak is directly exploitable by an untrusted source without requiring application mistakes.
- * The leak cannot be reasonably mitigated through standard operational practices (like process recycling).
- * The leak occurs deterministically under normal usage patterns rather than edge cases.
- * The leak occurs at a rate that would cause practical resource exhaustion within a practical timeframe under
- typical workloads.
- * The attack demonstrates [asymmetric resource consumption](https://cwe.mitre.org/data/definitions/405.html),
- where the attacker expends significantly fewer resources than what's required by the server to process the
- attack. Attacks requiring comparable resources on the attacker's side (which can be mitigated through common
- practices like rate limiting) may not qualify.
If Node.js loads configuration files or runs code by default (without a
specific request from the user), and this is not documented, it is considered a
vulnerability.
Vulnerabilities related to this case may be fixed by a documentation update.
+#### Denial of Service (DoS) vulnerabilities
+
+For a behavior to be considered a DoS vulnerability, the PoC must meet the following criteria:
+
+* The API is being correctly used.
+* The API doesn't have a warning against its usage in a production environment.
+* The API is public and documented. If the API comes from JavaScript, the behavior must be
+ well-defined in the [ECMAScript specification](https://tc39.es/ecma262/).
+* The API has stable (2.0) status.
+* The behavior is significant enough to cause a denial of service quickly
+ or in a context not controlled by the Node.js application developer (for example, HTTP parsing).
+* The behavior is directly exploitable by an untrusted source without requiring application mistakes.
+* The behavior cannot be reasonably mitigated through standard operational practices (like process recycling).
+* The behavior occurs deterministically under normal usage patterns rather than edge cases.
+* The behavior occurs at a rate that would cause practical resource exhaustion within a practical timeframe under
+ typical workloads.
+* The attack demonstrates [asymmetric resource consumption](https://cwe.mitre.org/data/definitions/405.html),
+ where the attacker expends significantly fewer resources than what's required by the server to process the
+ attack. Attacks requiring comparable resources on the attacker's side (which can be mitigated through common
+ practices like rate limiting) may not qualify.
+
**Node.js does NOT trust**:
* Data received from the remote end of inbound network connections
diff --git a/doc/api/async_context.md b/doc/api/async_context.md
index df6a6466fda98e..b72934a25ea802 100644
--- a/doc/api/async_context.md
+++ b/doc/api/async_context.md
@@ -389,7 +389,7 @@ try {
### `asyncLocalStorage.withScope(store)`
> Stability: 1 - Experimental
@@ -527,7 +527,7 @@ probably responsible for the context loss.
## Class: `RunScope`
> Stability: 1 - Experimental
@@ -543,7 +543,7 @@ exits, whether through normal completion or by throwing an error.
### `scope.dispose()`
Explicitly ends the scope and restores the previous store value. This method
diff --git a/doc/api/cli.md b/doc/api/cli.md
index 9ef967373c63dc..4938654132073a 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -1280,7 +1280,7 @@ Enable experimental support for storage inspection
### `--experimental-stream-iter`
> Stability: 1 - Experimental
diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md
index 0bfe9a3fa3a463..cf6cde094c1b53 100644
--- a/doc/api/deprecations.md
+++ b/doc/api/deprecations.md
@@ -4488,7 +4488,7 @@ changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/62453
description: Runtime deprecation.
- - version: REPLACEME
+ - version: v25.9.0
pr-url: https://github.com/nodejs/node/pull/62321
description: Documentation-only deprecation.
-->
@@ -4513,7 +4513,7 @@ changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/62453
description: Runtime deprecation.
- - version: REPLACEME
+ - version: v25.9.0
pr-url: https://github.com/nodejs/node/pull/62321
description: Documentation-only deprecation.
-->
@@ -4528,15 +4528,26 @@ deprecated and will throw an error in a future version.
-Type: Documentation-only
+Type: Runtime
[`module.register()`][] is deprecated. Use [`module.registerHooks()`][]
instead.
+The `module.register()` API provides off-thread async hooks for customizing ES modules;
+the `module.registerHooks()` API provides similar hooks that are synchronous, in-thread, and
+work for all types of modules.
+Supporting async hooks has proven to be complex, involving worker threads orchestration, and there are issues
+that have proven unresolveable. See [caveats of asynchronous customization hooks][]. Please migrate to
+`module.registerHooks()` as soon as possible as `module.register()` will be
+removed in a future version of Node.js.
+
[DEP0142]: #dep0142-repl_builtinlibs
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
@@ -4696,6 +4707,7 @@ instead.
[`zlib.bytesWritten`]: zlib.md#zlibbyteswritten
[alloc]: buffer.md#static-method-bufferallocsize-fill-encoding
[alloc_unsafe_size]: buffer.md#static-method-bufferallocunsafesize
+[caveats of asynchronous customization hooks]: module.md#caveats-of-asynchronous-customization-hooks
[from_arraybuffer]: buffer.md#static-method-bufferfromarraybuffer-byteoffset-length
[from_string_encoding]: buffer.md#static-method-bufferfromstring-encoding
[legacy URL API]: url.md#legacy-url-api
diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md
index d0916abbe376f5..99f7af3dd3e95b 100644
--- a/doc/api/diagnostics_channel.md
+++ b/doc/api/diagnostics_channel.md
@@ -1858,7 +1858,7 @@ Emitted when [`process.execve()`][] is invoked.
> Stability: 1 - Experimental
These channels are emitted for each [`locks.request()`][] call. See
diff --git a/doc/api/fs.md b/doc/api/fs.md
index c793dc67830f7c..8c2e91fb2c8dbb 100644
--- a/doc/api/fs.md
+++ b/doc/api/fs.md
@@ -380,7 +380,7 @@ added: v10.0.0
#### `filehandle.pull([...transforms][, options])`
> Stability: 1 - Experimental
@@ -457,7 +457,7 @@ run().catch(console.error);
#### `filehandle.pullSync([...transforms][, options])`
> Stability: 1 - Experimental
@@ -1010,7 +1010,7 @@ the end of the file.
#### `filehandle.writer([options])`
> Stability: 1 - Experimental
diff --git a/doc/api/module.md b/doc/api/module.md
index 465749f28731c0..ebede62eeca3a4 100644
--- a/doc/api/module.md
+++ b/doc/api/module.md
@@ -178,12 +178,11 @@ isBuiltin('wss'); // false
added:
- v20.6.0
- v18.19.0
-deprecated: REPLACEME
+deprecated: v25.9.0
changes:
- version: REPLACEME
- pr-url: https://github.com/nodejs/node/pull/62395
- description: Documentation-only deprecation (DEP0205). Use
- `module.registerHooks()` instead.
+ pr-url: https://github.com/nodejs/node/pull/62401
+ description: Runtime deprecation (DEP0205).
- version:
- v23.6.1
- v22.13.1
diff --git a/doc/api/process.md b/doc/api/process.md
index 0180d1adf209be..ed24f30ff5232e 100644
--- a/doc/api/process.md
+++ b/doc/api/process.md
@@ -739,7 +739,7 @@ This feature is not available in [`Worker`][] threads.
## `process.addUncaughtExceptionCaptureCallback(fn)`
> Stability: 1 - Experimental
@@ -4060,7 +4060,7 @@ This implies calling `module.setSourceMapsSupport()` with an option
diff --git a/doc/api/repl.md b/doc/api/repl.md
index c26b2a56dc8ad5..3c61adb450fd71 100644
--- a/doc/api/repl.md
+++ b/doc/api/repl.md
@@ -709,7 +709,7 @@ npx codemod@latest @nodejs/repl-builtin-modules
+
> Stability: 1 - Experimental
@@ -521,7 +521,7 @@ Including the `node:` prefix on the module specifier is optional.
### `from(input)`
* `input` {string|ArrayBuffer|ArrayBufferView|Iterable|AsyncIterable|Object}
@@ -561,7 +561,7 @@ run().catch(console.error);
### `fromSync(input)`
* `input` {string|ArrayBuffer|ArrayBufferView|Iterable|Object}
@@ -591,7 +591,7 @@ console.log(textSync(fromSync('hello'))); // 'hello'
### `pipeTo(source[, ...transforms], writer[, options])`
* `source` {AsyncIterable|Iterable} The data source.
@@ -648,7 +648,7 @@ run().catch(console.error);
### `pipeToSync(source[, ...transforms], writer[, options])`
* `source` {Iterable} The sync data source.
@@ -668,7 +668,7 @@ The `writer` must have the `*Sync` methods (`writeSync`, `writevSync`,
### `pull(source[, ...transforms][, options])`
* `source` {AsyncIterable|Iterable} The data source.
@@ -739,7 +739,7 @@ ac.abort(); // Pipeline throws AbortError on next iteration
### `pullSync(source[, ...transforms])`
* `source` {Iterable} The sync data source.
@@ -753,7 +753,7 @@ Synchronous version of [`pull()`][]. All transforms must be synchronous.
### `push([...transforms][, options])`
* `...transforms` {Function|Object} Optional transforms applied to the
@@ -817,7 +817,7 @@ The writer returned by `push()` conforms to the \[Writer interface]\[].
### `duplex([options])`
* `options` {Object}
@@ -895,7 +895,7 @@ run().catch(console.error);
### `array(source[, options])`
* `source` {AsyncIterable\|Iterable\}
@@ -910,7 +910,7 @@ Collect all chunks as an array of `Uint8Array` values (without concatenating).
### `arrayBuffer(source[, options])`
* `source` {AsyncIterable\|Iterable\}
@@ -925,7 +925,7 @@ Collect all bytes into an `ArrayBuffer`.
### `arrayBufferSync(source[, options])`
* `source` {Iterable\}
@@ -939,7 +939,7 @@ Synchronous version of [`arrayBuffer()`][].
### `arraySync(source[, options])`
* `source` {Iterable\}
@@ -953,7 +953,7 @@ Synchronous version of [`array()`][].
### `bytes(source[, options])`
* `source` {AsyncIterable\|Iterable\}
@@ -986,7 +986,7 @@ run().catch(console.error);
### `bytesSync(source[, options])`
* `source` {Iterable\}
@@ -1000,7 +1000,7 @@ Synchronous version of [`bytes()`][].
### `text(source[, options])`
* `source` {AsyncIterable\|Iterable\}
@@ -1032,7 +1032,7 @@ run().catch(console.error);
### `textSync(source[, options])`
* `source` {Iterable\}
@@ -1049,7 +1049,7 @@ Synchronous version of [`text()`][].
### `ondrain(drainable)`
* `drainable` {Object} An object implementing the drainable protocol.
@@ -1104,7 +1104,7 @@ run().catch(console.error);
### `merge(...sources[, options])`
* `...sources` {AsyncIterable\|Iterable\} Two or more iterables.
@@ -1137,7 +1137,7 @@ run().catch(console.error);
### `tap(callback)`
* `callback` {Function} `(chunks) => void` Called with each batch.
@@ -1176,7 +1176,7 @@ chunks by the tapping callback; but return values are ignored.
### `tapSync(callback)`
* `callback` {Function}
@@ -1189,7 +1189,7 @@ Synchronous version of [`tap()`][].
### `broadcast([options])`
* `options` {Object}
@@ -1290,7 +1290,7 @@ Alias for `broadcast.cancel()`.
### `Broadcast.from(input[, options])`
* `input` {AsyncIterable|Iterable|Broadcastable}
@@ -1303,7 +1303,7 @@ automatically and pushed to all subscribers.
### `share(source[, options])`
* `source` {AsyncIterable} The source to share.
@@ -1384,7 +1384,7 @@ Alias for `share.cancel()`.
### `Share.from(input[, options])`
* `input` {AsyncIterable|Shareable}
@@ -1396,7 +1396,7 @@ Create a {Share} from an existing source.
### `shareSync(source[, options])`
* `source` {Iterable} The sync source to share.
@@ -1411,7 +1411,7 @@ Synchronous version of [`share()`][].
### `SyncShare.fromSync(input[, options])`
* `input` {Iterable|SyncShareable}
diff --git a/doc/api/test.md b/doc/api/test.md
index 257b17ae845f9c..48dee7d5610b93 100644
--- a/doc/api/test.md
+++ b/doc/api/test.md
@@ -3563,6 +3563,44 @@ Emitted when no more tests are queued for execution in watch mode.
Emitted when one or more tests are restarted due to a file change in watch mode.
+## `getTestContext()`
+
+
+
+* Returns: {TestContext|SuiteContext|undefined}
+
+Returns the [`TestContext`][] or [`SuiteContext`][] object associated with the
+currently executing test or suite, or `undefined` if called outside of a test or
+suite. This function can be used to access context information from within the
+test or suite function or any async operations within them.
+
+```mjs
+import { getTestContext } from 'node:test';
+
+test('example test', async () => {
+ const ctx = getTestContext();
+ console.log(`Running test: ${ctx.name}`);
+});
+
+describe('example suite', () => {
+ const ctx = getTestContext();
+ console.log(`Running suite: ${ctx.name}`);
+});
+```
+
+When called from a test, returns a [`TestContext`][].
+When called from a suite, returns a [`SuiteContext`][].
+
+If called from outside a test or suite (e.g., at the top level of a module or in
+a setTimeout callback after execution has completed), this function returns
+`undefined`.
+
+When called from within a hook (before, beforeEach, after, afterEach), this
+function returns the context of the test or suite that the hook is associated
+with.
+
## Class: `TestContext`
+
+* Type: {boolean}
+
+Indicates whether the suite and all of its subtests have passed.
+
+### `context.attempt`
+
+
+
+* Type: {number}
+
+The attempt number of the suite. This value is zero-based, so the first attempt is `0`,
+the second attempt is `1`, and so on. This property is useful in conjunction with the
+`--test-rerun-failures` option to determine the attempt number of the current run.
+
+### `context.diagnostic(message)`
+
+
+
+* `message` {string} A diagnostic message to output.
+
+Output a diagnostic message. This is typically used for logging information
+about the current suite or its tests.
+
+```js
+test.describe('my suite', (suite) => {
+ suite.diagnostic('Suite diagnostic message');
+});
+```
+
[TAP]: https://testanything.org/
[`--experimental-test-coverage`]: cli.md#--experimental-test-coverage
[`--experimental-test-module-mocks`]: cli.md#--experimental-test-module-mocks
diff --git a/doc/api/webcrypto.md b/doc/api/webcrypto.md
index 82eda8b796b2b1..ece03f4a1208a7 100644
--- a/doc/api/webcrypto.md
+++ b/doc/api/webcrypto.md
@@ -2,7 +2,7 @@
@@ -1910,7 +1910,7 @@ added: v24.7.0
#### `cShakeParams.outputLength`
* Type: {number} represents the requested output length in bits.
@@ -2339,13 +2339,13 @@ added: v15.0.0
### Class: `KangarooTwelveParams`
#### `kangarooTwelveParams.customization`
* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined}
@@ -2355,7 +2355,7 @@ The optional customization string for KangarooTwelve.
#### `kangarooTwelveParams.name`
* Type: {string} Must be `'KT128'`[^modern-algos] or `'KT256'`[^modern-algos]
@@ -2363,7 +2363,7 @@ added: REPLACEME
#### `kangarooTwelveParams.outputLength`
* Type: {number} represents the requested output length in bits.
@@ -2448,7 +2448,7 @@ added: v24.8.0
@@ -2464,7 +2464,7 @@ added: v24.8.0
#### `kmacParams.outputLength`
* Type: {number}
@@ -2741,13 +2741,13 @@ The length (in bytes) of the random salt to use.
### Class: `TurboShakeParams`
#### `turboShakeParams.domainSeparation`
* Type: {number|undefined}
@@ -2757,7 +2757,7 @@ The optional domain separation byte (0x01-0x7f). Defaults to `0x1f`.
#### `turboShakeParams.name`
* Type: {string} Must be `'TurboSHAKE128'`[^modern-algos] or `'TurboSHAKE256'`[^modern-algos]
@@ -2765,7 +2765,7 @@ added: REPLACEME
#### `turboShakeParams.outputLength`
* Type: {number} represents the requested output length in bits.
diff --git a/doc/api/zlib_iter.md b/doc/api/zlib_iter.md
index 73bdf4f7561c24..99bcdba745203d 100644
--- a/doc/api/zlib_iter.md
+++ b/doc/api/zlib_iter.md
@@ -1,6 +1,6 @@
# Iterable Compression
-
+
> Stability: 1 - Experimental
@@ -74,7 +74,7 @@ console.log(original); // 'hello'
## `compressBrotliSync([options])`
* `options` {Object}
@@ -106,7 +106,7 @@ Create a Brotli compression transform. Output is compatible with
## `compressDeflateSync([options])`
* `options` {Object}
@@ -126,7 +126,7 @@ Create a deflate compression transform. Output is compatible with
## `compressGzipSync([options])`
* `options` {Object}
@@ -146,7 +146,7 @@ and `decompressGzip()`/`decompressGzipSync()`.
## `compressZstdSync([options])`
* `options` {Object}
@@ -173,7 +173,7 @@ Create a Zstandard compression transform. Output is compatible with
## `decompressBrotliSync([options])`
* `options` {Object}
@@ -196,7 +196,7 @@ Create a Brotli decompression transform.
## `decompressDeflateSync([options])`
* `options` {Object}
@@ -212,7 +212,7 @@ Create a deflate decompression transform.
## `decompressGzipSync([options])`
* `options` {Object}
@@ -228,7 +228,7 @@ Create a gzip decompression transform.
## `decompressZstdSync([options])`
* `options` {Object}
diff --git a/doc/changelogs/CHANGELOG_V25.md b/doc/changelogs/CHANGELOG_V25.md
index fbd24d6c72f2f8..2c2b5bdbbe58d8 100644
--- a/doc/changelogs/CHANGELOG_V25.md
+++ b/doc/changelogs/CHANGELOG_V25.md
@@ -8,6 +8,7 @@
|
+25.9.0
25.8.2
25.8.1
25.8.0
@@ -52,6 +53,148 @@
* [io.js](CHANGELOG_IOJS.md)
* [Archive](CHANGELOG_ARCHIVE.md)
+
+
+## 2026-04-01, Version 25.9.0 (Current), @aduh95
+
+### Notable Changes
+
+#### Test runner module mocking improvements
+
+`MockModuleOptions.defaultExport` and `MockModuleOptions.namedExports` have been
+consolidated into a single option `MockModuleOptions.exports` to align with user
+expectations and other test runners.
+
+A `default` property on `MockModuleOptions.exports` represents the default
+export, and own enumerable properties are treated as named exports.
+
+An automated migration is available to update user code:
+
+
+```bash
+npx codemod @nodejs/mock-module-exports
+```
+
+Contributed by sangwook in [#61727](https://github.com/nodejs/node/pull/61727).
+
+#### Other notable changes
+
+* \[[`312476cb84`](https://github.com/nodejs/node/commit/312476cb84)] - **(SEMVER-MINOR)** **async\_hooks**: add using scopes to `AsyncLocalStorage` (Stephen Belanger) [#61674](https://github.com/nodejs/node/pull/61674)
+* \[[`62d2cd473b`](https://github.com/nodejs/node/commit/62d2cd473b)] - **(SEMVER-MINOR)** **cli**: add `--max-heap-size` option (tannal) [#58708](https://github.com/nodejs/node/pull/58708)
+* \[[`d0ebf0e44b`](https://github.com/nodejs/node/commit/d0ebf0e44b)] - **(SEMVER-MINOR)** **crypto**: add `TurboSHAKE` and `KangarooTwelve` Web Cryptography algorithms (Filip Skokan) [#62183](https://github.com/nodejs/node/pull/62183)
+* \[[`f85b9d9fa8`](https://github.com/nodejs/node/commit/f85b9d9fa8)] - **(SEMVER-MINOR)** **repl**: add customizable error handling (Anna Henningsen) [#62188](https://github.com/nodejs/node/pull/62188)
+* \[[`67b854d407`](https://github.com/nodejs/node/commit/67b854d407)] - **(SEMVER-MINOR)** **repl**: remove dependency on `node:domain` (Matteo Collina) [#61227](https://github.com/nodejs/node/pull/61227)
+* \[[`966b700623`](https://github.com/nodejs/node/commit/966b700623)] - **(SEMVER-MINOR)** **sea**: support code cache for ESM entrypoint in SEA (Joyee Cheung) [#62158](https://github.com/nodejs/node/pull/62158)
+* \[[`e1f0d2a014`](https://github.com/nodejs/node/commit/e1f0d2a014)] - **(SEMVER-MINOR)** **stream**: add stream/iter Implementation (James M Snell) [#62066](https://github.com/nodejs/node/pull/62066)
+
+### Commits
+
+* \[[`312476cb84`](https://github.com/nodejs/node/commit/312476cb84)] - **(SEMVER-MINOR)** **async\_hooks**: add using scopes to AsyncLocalStorage (Stephen Belanger) [#61674](https://github.com/nodejs/node/pull/61674)
+* \[[`bfff8cb2ab`](https://github.com/nodejs/node/commit/bfff8cb2ab)] - **(SEMVER-MINOR)** **benchmark**: add benchmarks for experimental stream/iter (James M Snell) [#62066](https://github.com/nodejs/node/pull/62066)
+* \[[`c721d68502`](https://github.com/nodejs/node/commit/c721d68502)] - **benchmark**: fix destructuring in dgram/single-buffer (Ali Hassan) [#62084](https://github.com/nodejs/node/pull/62084)
+* \[[`e2f03c8e92`](https://github.com/nodejs/node/commit/e2f03c8e92)] - **buffer**: improve performance of multiple Buffer operations (Ali Hassan) [#61871](https://github.com/nodejs/node/pull/61871)
+* \[[`2fcd07f1ba`](https://github.com/nodejs/node/commit/2fcd07f1ba)] - **build**: support empty libname flags in `configure.py` (Antoine du Hamel) [#62477](https://github.com/nodejs/node/pull/62477)
+* \[[`b800c57fce`](https://github.com/nodejs/node/commit/b800c57fce)] - **build**: fix timezone-update path references (Chengzhong Wu) [#62280](https://github.com/nodejs/node/pull/62280)
+* \[[`7dc5a1e9b4`](https://github.com/nodejs/node/commit/7dc5a1e9b4)] - **build**: skip dockit on IBMi (SRAVANI GUNDEPALLI) [#62189](https://github.com/nodejs/node/pull/62189)
+* \[[`f0eea0f905`](https://github.com/nodejs/node/commit/f0eea0f905)] - **build**: fix --node-builtin-modules-path (Filip Skokan) [#62115](https://github.com/nodejs/node/pull/62115)
+* \[[`62d2cd473b`](https://github.com/nodejs/node/commit/62d2cd473b)] - **(SEMVER-MINOR)** **cli**: add --max-heap-size option (tannal) [#58708](https://github.com/nodejs/node/pull/58708)
+* \[[`ac4b485698`](https://github.com/nodejs/node/commit/ac4b485698)] - **crypto**: update root certificates to NSS 3.121 (Node.js GitHub Bot) [#62485](https://github.com/nodejs/node/pull/62485)
+* \[[`d0ebf0e44b`](https://github.com/nodejs/node/commit/d0ebf0e44b)] - **(SEMVER-MINOR)** **crypto**: add TurboSHAKE and KangarooTwelve Web Cryptography algorithms (Filip Skokan) [#62183](https://github.com/nodejs/node/pull/62183)
+* \[[`3009980d9d`](https://github.com/nodejs/node/commit/3009980d9d)] - **crypto**: add crypto::GetSSLCtx API for addon access to OpenSSL contexts (Tim Perry) [#62254](https://github.com/nodejs/node/pull/62254)
+* \[[`f5725ca81d`](https://github.com/nodejs/node/commit/f5725ca81d)] - **crypto**: reject ML-KEM/ML-DSA PKCS#8 import without seed in SubtleCrypto (Filip Skokan) [#62218](https://github.com/nodejs/node/pull/62218)
+* \[[`f69ed4bc3f`](https://github.com/nodejs/node/commit/f69ed4bc3f)] - **crypto**: rename CShakeParams and KmacParams length to outputLength (Filip Skokan) [#61875](https://github.com/nodejs/node/pull/61875)
+* \[[`4d96e53570`](https://github.com/nodejs/node/commit/4d96e53570)] - **crypto**: refactor WebCrypto AEAD algorithms auth tag handling (Filip Skokan) [#62169](https://github.com/nodejs/node/pull/62169)
+* \[[`93d77719e8`](https://github.com/nodejs/node/commit/93d77719e8)] - **crypto**: read algorithm name property only once in normalizeAlgorithm (Filip Skokan) [#62170](https://github.com/nodejs/node/pull/62170)
+* \[[`3d2e23a981`](https://github.com/nodejs/node/commit/3d2e23a981)] - **deps**: update ada to 3.4.4 (Node.js GitHub Bot) [#62414](https://github.com/nodejs/node/pull/62414)
+* \[[`176d6d2205`](https://github.com/nodejs/node/commit/176d6d2205)] - **deps**: update timezone to 2026a (Node.js GitHub Bot) [#62164](https://github.com/nodejs/node/pull/62164)
+* \[[`95c7fc67ba`](https://github.com/nodejs/node/commit/95c7fc67ba)] - **deps**: update googletest to 2461743991f9aa53e9a3625eafcbacd81a3c74cd (Node.js GitHub Bot) [#62484](https://github.com/nodejs/node/pull/62484)
+* \[[`e5e9f2044a`](https://github.com/nodejs/node/commit/e5e9f2044a)] - **deps**: update simdjson to 4.5.0 (Node.js GitHub Bot) [#62382](https://github.com/nodejs/node/pull/62382)
+* \[[`905b94266a`](https://github.com/nodejs/node/commit/905b94266a)] - **deps**: update ngtcp2 to 1.21.0 (Node.js GitHub Bot) [#62051](https://github.com/nodejs/node/pull/62051)
+* \[[`180c150122`](https://github.com/nodejs/node/commit/180c150122)] - **deps**: V8: cherry-pick cf1bce40a5ef (Richard Lau) [#62449](https://github.com/nodejs/node/pull/62449)
+* \[[`bc265aa003`](https://github.com/nodejs/node/commit/bc265aa003)] - **deps**: upgrade npm to 11.12.1 (npm team) [#62448](https://github.com/nodejs/node/pull/62448)
+* \[[`f1b28612c4`](https://github.com/nodejs/node/commit/f1b28612c4)] - **deps**: V8: cherry-pick b25cd62c7ba2 (Yagiz Nizipli) [#62354](https://github.com/nodejs/node/pull/62354)
+* \[[`757719d2af`](https://github.com/nodejs/node/commit/757719d2af)] - **deps**: disable rust icu compiled\_data features (Chengzhong Wu) [#62284](https://github.com/nodejs/node/pull/62284)
+* \[[`3bdc955b63`](https://github.com/nodejs/node/commit/3bdc955b63)] - **deps**: update sqlite to 3.51.3 (Node.js GitHub Bot) [#62256](https://github.com/nodejs/node/pull/62256)
+* \[[`a9703d194a`](https://github.com/nodejs/node/commit/a9703d194a)] - **deps**: update googletest to 73a63ea05dc8ca29ec1d2c1d66481dd0de1950f1 (Node.js GitHub Bot) [#61927](https://github.com/nodejs/node/pull/61927)
+* \[[`85138935cb`](https://github.com/nodejs/node/commit/85138935cb)] - **deps**: update merve to 1.2.2 (Node.js GitHub Bot) [#62213](https://github.com/nodejs/node/pull/62213)
+* \[[`231521e75e`](https://github.com/nodejs/node/commit/231521e75e)] - **diagnostics\_channel**: add diagnostics channels for web locks (Ilyas Shabi) [#62123](https://github.com/nodejs/node/pull/62123)
+* \[[`0093863664`](https://github.com/nodejs/node/commit/0093863664)] - **doc**: deprecate `module.register()` (DEP0205) (Geoffrey Booth) [#62395](https://github.com/nodejs/node/pull/62395)
+* \[[`0b96ece6be`](https://github.com/nodejs/node/commit/0b96ece6be)] - **doc**: clarify that features cannot be both experimental and deprecated (Antoine du Hamel) [#62456](https://github.com/nodejs/node/pull/62456)
+* \[[`8d3ea975f5`](https://github.com/nodejs/node/commit/8d3ea975f5)] - **doc**: fix 'transfered' typo in quic.md (lilianakatrina684-a11y) [#62492](https://github.com/nodejs/node/pull/62492)
+* \[[`08ff16e0ba`](https://github.com/nodejs/node/commit/08ff16e0ba)] - **doc**: move sqlite type conversion section to correct level (René) [#62482](https://github.com/nodejs/node/pull/62482)
+* \[[`61cc747dd8`](https://github.com/nodejs/node/commit/61cc747dd8)] - **doc**: add Rafael to last security release steward (Rafael Gonzaga) [#62423](https://github.com/nodejs/node/pull/62423)
+* \[[`64cfa5a6fa`](https://github.com/nodejs/node/commit/64cfa5a6fa)] - **doc**: use npm-published version of doc-kit (Aviv Keller) [#62139](https://github.com/nodejs/node/pull/62139)
+* \[[`1020321fb0`](https://github.com/nodejs/node/commit/1020321fb0)] - **doc**: fix overstated Date header requirement in response.sendDate (Kit Dallege) [#62206](https://github.com/nodejs/node/pull/62206)
+* \[[`9caa7855b2`](https://github.com/nodejs/node/commit/9caa7855b2)] - **doc**: fix guaranteed typo (lilianakatrina684-a11y) [#62374](https://github.com/nodejs/node/pull/62374)
+* \[[`e254f65306`](https://github.com/nodejs/node/commit/e254f65306)] - **doc**: enhance clarification about the main field (Mowafak Almahaini) [#62302](https://github.com/nodejs/node/pull/62302)
+* \[[`9e724b53f8`](https://github.com/nodejs/node/commit/9e724b53f8)] - **doc**: remove spawn with shell example from bat/cmd section (Kit Dallege) [#62243](https://github.com/nodejs/node/pull/62243)
+* \[[`7f37c17516`](https://github.com/nodejs/node/commit/7f37c17516)] - **doc**: minor typo fix (Jeff Matson) [#62358](https://github.com/nodejs/node/pull/62358)
+* \[[`eb0ca98f01`](https://github.com/nodejs/node/commit/eb0ca98f01)] - **doc**: add path to vulnerabilities.json mention (Rafael Gonzaga) [#62355](https://github.com/nodejs/node/pull/62355)
+* \[[`198b6e0932`](https://github.com/nodejs/node/commit/198b6e0932)] - **doc**: deprecate CryptoKey use in node:crypto (Filip Skokan) [#62321](https://github.com/nodejs/node/pull/62321)
+* \[[`17e5aee6c5`](https://github.com/nodejs/node/commit/17e5aee6c5)] - **doc**: fix small environment\_variables typo (chris) [#62279](https://github.com/nodejs/node/pull/62279)
+* \[[`193d629895`](https://github.com/nodejs/node/commit/193d629895)] - **doc**: test and test-only targets do not run linter (Xavier Stouder) [#62120](https://github.com/nodejs/node/pull/62120)
+* \[[`4a1f20ec4a`](https://github.com/nodejs/node/commit/4a1f20ec4a)] - **doc**: clarify fs.ReadStream and fs.WriteStream are not constructable (Kit Dallege) [#62208](https://github.com/nodejs/node/pull/62208)
+* \[[`f976c9214d`](https://github.com/nodejs/node/commit/f976c9214d)] - **doc**: clarify that any truthy value of `shell` is part of DEP0190 (Antoine du Hamel) [#62249](https://github.com/nodejs/node/pull/62249)
+* \[[`4d83972681`](https://github.com/nodejs/node/commit/4d83972681)] - **doc**: remove outdated Chrome 66 and ndb references from debugger (Kit Dallege) [#62202](https://github.com/nodejs/node/pull/62202)
+* \[[`71f2eada5b`](https://github.com/nodejs/node/commit/71f2eada5b)] - **doc**: add throwIfNoEntry version history to fs.stat (kovan) [#62204](https://github.com/nodejs/node/pull/62204)
+* \[[`670c80893b`](https://github.com/nodejs/node/commit/670c80893b)] - **doc**: add note (and caveat) for `mock.module` about customization hooks (Jacob Smith) [#62075](https://github.com/nodejs/node/pull/62075)
+* \[[`2ff5cb13f5`](https://github.com/nodejs/node/commit/2ff5cb13f5)] - **doc,test**: clarify --eval syntax for leading '-' scripts (kovan) [#62244](https://github.com/nodejs/node/pull/62244)
+* \[[`6c6c9004c4`](https://github.com/nodejs/node/commit/6c6c9004c4)] - **esm**: fix typo in worker loader hook comment (jakecastelli) [#62475](https://github.com/nodejs/node/pull/62475)
+* \[[`1cdd23c9f3`](https://github.com/nodejs/node/commit/1cdd23c9f3)] - **esm**: fix source phase identity bug in loadCache eviction (Guy Bedford) [#62415](https://github.com/nodejs/node/pull/62415)
+* \[[`4f4ff15794`](https://github.com/nodejs/node/commit/4f4ff15794)] - **esm**: fix path normalization in `finalizeResolution` (Antoine du Hamel) [#62080](https://github.com/nodejs/node/pull/62080)
+* \[[`088167d102`](https://github.com/nodejs/node/commit/088167d102)] - **events**: avoid cloning listeners array on every emit (Gürgün Dayıoğlu) [#62261](https://github.com/nodejs/node/pull/62261)
+* \[[`0250b436ee`](https://github.com/nodejs/node/commit/0250b436ee)] - **fs**: fix cpSync to handle non-ASCII characters (Stefan Stojanovic) [#61950](https://github.com/nodejs/node/pull/61950)
+* \[[`b67a8fb171`](https://github.com/nodejs/node/commit/b67a8fb171)] - **inspector**: add Target.getTargets and extract TargetManager (Kohei) [#62487](https://github.com/nodejs/node/pull/62487)
+* \[[`ffcc5a5722`](https://github.com/nodejs/node/commit/ffcc5a5722)] - **lib**: make SubtleCrypto.supports enumerable (Filip Skokan) [#62307](https://github.com/nodejs/node/pull/62307)
+* \[[`92ef2ad8fa`](https://github.com/nodejs/node/commit/92ef2ad8fa)] - **lib**: prefer primordials in SubtleCrypto (Filip Skokan) [#62226](https://github.com/nodejs/node/pull/62226)
+* \[[`40a43ac4d0`](https://github.com/nodejs/node/commit/40a43ac4d0)] - **module**: fix coverage of mocked CJS modules imported from ESM (Marco) [#62133](https://github.com/nodejs/node/pull/62133)
+* \[[`3ef0a5b90e`](https://github.com/nodejs/node/commit/3ef0a5b90e)] - **quic**: remove CryptoKey support from session keys option (Filip Skokan) [#62335](https://github.com/nodejs/node/pull/62335)
+* \[[`3c8dd8eb8e`](https://github.com/nodejs/node/commit/3c8dd8eb8e)] - **repl**: use vm DONT\_CONTEXTIFY context (Chengzhong Wu) [#62371](https://github.com/nodejs/node/pull/62371)
+* \[[`f85b9d9fa8`](https://github.com/nodejs/node/commit/f85b9d9fa8)] - **(SEMVER-MINOR)** **repl**: add customizable error handling (Anna Henningsen) [#62188](https://github.com/nodejs/node/pull/62188)
+* \[[`e4c164e045`](https://github.com/nodejs/node/commit/e4c164e045)] - **repl**: handle exceptions from async context after close (Anna Henningsen) [#62165](https://github.com/nodejs/node/pull/62165)
+* \[[`67b854d407`](https://github.com/nodejs/node/commit/67b854d407)] - **(SEMVER-MINOR)** **repl**: remove dependency on domain module (Matteo Collina) [#61227](https://github.com/nodejs/node/pull/61227)
+* \[[`966b700623`](https://github.com/nodejs/node/commit/966b700623)] - **(SEMVER-MINOR)** **sea**: support code cache for ESM entrypoint in SEA (Joyee Cheung) [#62158](https://github.com/nodejs/node/pull/62158)
+* \[[`fe82baf970`](https://github.com/nodejs/node/commit/fe82baf970)] - **src**: improve EC JWK import performance (Filip Skokan) [#62396](https://github.com/nodejs/node/pull/62396)
+* \[[`d490b171e0`](https://github.com/nodejs/node/commit/d490b171e0)] - **src**: handle null backing store in ArrayBufferViewContents::Read (Mert Can Altin) [#62343](https://github.com/nodejs/node/pull/62343)
+* \[[`0e4af848bc`](https://github.com/nodejs/node/commit/0e4af848bc)] - **src**: convert context\_frame field in AsyncWrap to internal field (Anna Henningsen) [#62103](https://github.com/nodejs/node/pull/62103)
+* \[[`02980b8c8f`](https://github.com/nodejs/node/commit/02980b8c8f)] - **src**: enable compilation/linking with OpenSSL 4.0 (Filip Skokan) [#62410](https://github.com/nodejs/node/pull/62410)
+* \[[`064f7c2fa6`](https://github.com/nodejs/node/commit/064f7c2fa6)] - **src**: use stack allocation in indexOf latin1 path (Mert Can Altin) [#62268](https://github.com/nodejs/node/pull/62268)
+* \[[`ede52bc2dc`](https://github.com/nodejs/node/commit/ede52bc2dc)] - **src,sqlite**: fix filterFunc dangling reference (Edy Silva) [#62281](https://github.com/nodejs/node/pull/62281)
+* \[[`e1f0d2a014`](https://github.com/nodejs/node/commit/e1f0d2a014)] - **(SEMVER-MINOR)** **stream**: add stream/iter Implementation (James M Snell) [#62066](https://github.com/nodejs/node/pull/62066)
+* \[[`03839fb087`](https://github.com/nodejs/node/commit/03839fb087)] - **stream**: preserve error over AbortError in pipeline (Marco) [#62113](https://github.com/nodejs/node/pull/62113)
+* \[[`0000d2f011`](https://github.com/nodejs/node/commit/0000d2f011)] - **stream**: replace bind with arrow function for onwrite callback (Ali Hassan) [#62087](https://github.com/nodejs/node/pull/62087)
+* \[[`3796a73719`](https://github.com/nodejs/node/commit/3796a73719)] - **test**: update WPT for WebCryptoAPI to 2cb332d710 (Node.js GitHub Bot) [#62483](https://github.com/nodejs/node/pull/62483)
+* \[[`ad8309415b`](https://github.com/nodejs/node/commit/ad8309415b)] - **test**: update WPT for url to fc3e651593 (Node.js GitHub Bot) [#62379](https://github.com/nodejs/node/pull/62379)
+* \[[`bed89b037e`](https://github.com/nodejs/node/commit/bed89b037e)] - **test**: wait for reattach before initial break on restart (Yuya Inoue) [#62471](https://github.com/nodejs/node/pull/62471)
+* \[[`c9ffffcc55`](https://github.com/nodejs/node/commit/c9ffffcc55)] - **test**: disable flaky WPT Blob test on AIX (James M Snell) [#62470](https://github.com/nodejs/node/pull/62470)
+* \[[`fd41ef31f6`](https://github.com/nodejs/node/commit/fd41ef31f6)] - **(SEMVER-MINOR)** **test**: add tests for experimental stream/iter implementation (James M Snell) [#62066](https://github.com/nodejs/node/pull/62066)
+* \[[`1b9d8d3eec`](https://github.com/nodejs/node/commit/1b9d8d3eec)] - **test**: avoid flaky run wait in debugger restart test (Yuya Inoue) [#62112](https://github.com/nodejs/node/pull/62112)
+* \[[`cb08a29d51`](https://github.com/nodejs/node/commit/cb08a29d51)] - **test**: skip test-cluster-dgram-reuse on AIX 7.3 (Stewart X Addison) [#62238](https://github.com/nodejs/node/pull/62238)
+* \[[`abea0af8a9`](https://github.com/nodejs/node/commit/abea0af8a9)] - **test**: add WebCrypto Promise.prototype.then pollution regression tests (Filip Skokan) [#62226](https://github.com/nodejs/node/pull/62226)
+* \[[`47a2132269`](https://github.com/nodejs/node/commit/47a2132269)] - **test**: update WPT for WebCryptoAPI to 6a1c545d77 (Node.js GitHub Bot) [#62187](https://github.com/nodejs/node/pull/62187)
+* \[[`2c63d3006c`](https://github.com/nodejs/node/commit/2c63d3006c)] - **test\_runner**: add exports option for module mocks (sangwook) [#61727](https://github.com/nodejs/node/pull/61727)
+* \[[`44ac0e1302`](https://github.com/nodejs/node/commit/44ac0e1302)] - **test\_runner**: make it compatible with fake timers (Matteo Collina) [#59272](https://github.com/nodejs/node/pull/59272)
+* \[[`1865691275`](https://github.com/nodejs/node/commit/1865691275)] - **test\_runner**: set non-zero exit code when suite errors occur (Edy Silva) [#62282](https://github.com/nodejs/node/pull/62282)
+* \[[`0252b2bab8`](https://github.com/nodejs/node/commit/0252b2bab8)] - **tools**: bump picomatch from 4.0.3 to 4.0.4 in /tools/eslint (dependabot\[bot]) [#62439](https://github.com/nodejs/node/pull/62439)
+* \[[`3368155267`](https://github.com/nodejs/node/commit/3368155267)] - **tools**: bump yaml from 2.8.2 to 2.8.3 in /tools/doc (dependabot\[bot]) [#62437](https://github.com/nodejs/node/pull/62437)
+* \[[`5e47c359f5`](https://github.com/nodejs/node/commit/5e47c359f5)] - **tools**: adopt the `--check-for-duplicates` NCU flag (Antoine du Hamel) [#62478](https://github.com/nodejs/node/pull/62478)
+* \[[`4a604e82d0`](https://github.com/nodejs/node/commit/4a604e82d0)] - **tools**: bump picomatch in /tools/doc (dependabot\[bot]) [#62438](https://github.com/nodejs/node/pull/62438)
+* \[[`d1a98b4ddb`](https://github.com/nodejs/node/commit/d1a98b4ddb)] - **tools**: bump flatted from 3.4.1 to 3.4.2 in /tools/eslint (dependabot\[bot]) [#62375](https://github.com/nodejs/node/pull/62375)
+* \[[`c32daa1ab4`](https://github.com/nodejs/node/commit/c32daa1ab4)] - **tools**: bump eslint deps (Huáng Jùnliàng) [#62356](https://github.com/nodejs/node/pull/62356)
+* \[[`7a2fcc6d41`](https://github.com/nodejs/node/commit/7a2fcc6d41)] - **tools**: do not swallow error in `lint-nix` workflow (Antoine du Hamel) [#62292](https://github.com/nodejs/node/pull/62292)
+* \[[`c41a2871b5`](https://github.com/nodejs/node/commit/c41a2871b5)] - **tools**: add eslint-plugin-regexp (Huáng Jùnliàng) [#62093](https://github.com/nodejs/node/pull/62093)
+* \[[`56dfeb06df`](https://github.com/nodejs/node/commit/56dfeb06df)] - **tools**: fix timeout errors in `lint-nix` job (Antoine du Hamel) [#62265](https://github.com/nodejs/node/pull/62265)
+* \[[`22fc8078e8`](https://github.com/nodejs/node/commit/22fc8078e8)] - **tools**: bump flatted from 3.3.3 to 3.4.1 in /tools/eslint (dependabot\[bot]) [#62255](https://github.com/nodejs/node/pull/62255)
+* \[[`409b0663bd`](https://github.com/nodejs/node/commit/409b0663bd)] - **tools**: bump undici from 6.23.0 to 6.24.1 in /tools/doc (dependabot\[bot]) [#62250](https://github.com/nodejs/node/pull/62250)
+* \[[`67c69750f4`](https://github.com/nodejs/node/commit/67c69750f4)] - **tools**: validate all commits that are pushed to `main` (Antoine du Hamel) [#62246](https://github.com/nodejs/node/pull/62246)
+* \[[`7d9db8cd21`](https://github.com/nodejs/node/commit/7d9db8cd21)] - **tools**: keep GN files when updating Merve (Antoine du Hamel) [#62167](https://github.com/nodejs/node/pull/62167)
+* \[[`6c8fa42ba2`](https://github.com/nodejs/node/commit/6c8fa42ba2)] - **typings**: rationalise TypedArray types (René) [#62174](https://github.com/nodejs/node/pull/62174)
+* \[[`531c64d04e`](https://github.com/nodejs/node/commit/531c64d04e)] - **url**: enable simdutf for ada (Yagiz Nizipli) [#61477](https://github.com/nodejs/node/pull/61477)
+* \[[`2000caccde`](https://github.com/nodejs/node/commit/2000caccde)] - **util**: allow color aliases in styleText (sangwook) [#62180](https://github.com/nodejs/node/pull/62180)
+* \[[`0aed332ab4`](https://github.com/nodejs/node/commit/0aed332ab4)] - **wasm**: support js string constant esm import (Guy Bedford) [#62198](https://github.com/nodejs/node/pull/62198)
+* \[[`d3fd4a978b`](https://github.com/nodejs/node/commit/d3fd4a978b)] - **worker**: heap profile optimizations (Ilyas Shabi) [#62201](https://github.com/nodejs/node/pull/62201)
+* \[[`e992a34a18`](https://github.com/nodejs/node/commit/e992a34a18)] - **zlib**: fix use-after-free when reset() is called during write (Matteo Collina) [#62325](https://github.com/nodejs/node/pull/62325)
+
## 2026-03-24, Version 25.8.2 (Current), @RafaelGSS
diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js
index 04c374c00cfc3e..8ae6761fba571a 100644
--- a/lib/internal/modules/esm/loader.js
+++ b/lib/internal/modules/esm/loader.js
@@ -31,7 +31,10 @@ const {
} = require('internal/errors').codes;
const { getOptionValue } = require('internal/options');
const { isURL, pathToFileURL } = require('internal/url');
-const { kEmptyObject } = require('internal/util');
+const {
+ getDeprecationWarningEmitter,
+ kEmptyObject,
+} = require('internal/util');
const {
compileSourceTextModule,
SourceTextModuleTypes: { kUser },
@@ -955,7 +958,16 @@ function isCascadedLoaderInitialized() {
* });
* ```
*/
+const emitRegisterDeprecation = getDeprecationWarningEmitter(
+ 'DEP0205',
+ '`module.register()` is deprecated. Use `module.registerHooks()` instead.',
+ undefined,
+ false,
+);
+
function register(specifier, parentURL = undefined, options) {
+ emitRegisterDeprecation();
+
if (parentURL != null && typeof parentURL === 'object' && !isURL(parentURL)) {
options = parentURL;
parentURL = options.parentURL;
diff --git a/lib/internal/test_runner/harness.js b/lib/internal/test_runner/harness.js
index 5418a14a4410a4..fed3d3a49a241f 100644
--- a/lib/internal/test_runner/harness.js
+++ b/lib/internal/test_runner/harness.js
@@ -21,7 +21,7 @@ const {
},
} = require('internal/errors');
const { exitCodes: { kGenericUserError } } = internalBinding('errors');
-const { kCancelledByParent, Test, Suite } = require('internal/test_runner/test');
+const { kCancelledByParent, Test, Suite, TestContext, SuiteContext } = require('internal/test_runner/test');
const {
parseCommandLine,
reporterScope,
@@ -431,8 +431,27 @@ function hook(hook) {
};
}
+function getTestContext() {
+ const test = testResources.get(executionAsyncId());
+ // Exclude the reporter sentinel
+ if (test === undefined || test === reporterScope) {
+ return undefined;
+ }
+ // For hooks (hookType is set), return the test/suite being hooked (the parent)
+ const actualTest = test.hookType !== undefined ? test.parent : test;
+ if (actualTest === undefined) {
+ return undefined;
+ }
+ // Return SuiteContext for suites, TestContext for tests
+ if (actualTest instanceof Suite) {
+ return new SuiteContext(actualTest);
+ }
+ return new TestContext(actualTest);
+}
+
module.exports = {
createTestTree,
+ getTestContext,
test: runInParentContext(Test),
suite: runInParentContext(Suite),
before: hook('before'),
diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js
index 97d53c097261d7..68e780673dd8f6 100644
--- a/lib/internal/test_runner/test.js
+++ b/lib/internal/test_runner/test.js
@@ -494,6 +494,18 @@ class SuiteContext {
get fullName() {
return getFullName(this.#suite);
}
+
+ get passed() {
+ return this.#suite.passed;
+ }
+
+ get attempt() {
+ return this.#suite.attempt ?? 0;
+ }
+
+ diagnostic(message) {
+ this.#suite.diagnostic(message);
+ }
}
function parseExpectFailure(expectFailure) {
@@ -1656,4 +1668,6 @@ module.exports = {
kUnwrapErrors,
Suite,
Test,
+ TestContext,
+ SuiteContext,
};
diff --git a/lib/test.js b/lib/test.js
index fb09d0625a08fc..50d276e9b0fb16 100644
--- a/lib/test.js
+++ b/lib/test.js
@@ -5,7 +5,7 @@ const {
ObjectDefineProperty,
} = primordials;
-const { test, suite, before, after, beforeEach, afterEach } = require('internal/test_runner/harness');
+const { test, suite, before, after, beforeEach, afterEach, getTestContext } = require('internal/test_runner/harness');
const { run } = require('internal/test_runner/runner');
module.exports = test;
@@ -15,6 +15,7 @@ ObjectAssign(module.exports, {
before,
beforeEach,
describe: suite,
+ getTestContext,
it: test,
run,
suite,
diff --git a/test/es-module/test-esm-register-deprecation.mjs b/test/es-module/test-esm-register-deprecation.mjs
new file mode 100644
index 00000000000000..171e5971a091fe
--- /dev/null
+++ b/test/es-module/test-esm-register-deprecation.mjs
@@ -0,0 +1,60 @@
+import { spawnPromisified } from '../common/index.mjs';
+import * as fixtures from '../common/fixtures.mjs';
+
+import assert from 'node:assert';
+import { execPath } from 'node:process';
+import { describe, it } from 'node:test';
+
+const urlToRegister = fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs');
+const urlToRegisterEscaped = JSON.stringify(urlToRegister.href);
+
+
+describe('module.register() deprecation (DEP0205)', { concurrency: !process.env.TEST_PARALLEL }, () => {
+ it('emits DEP0205 when module.register() is called', async () => {
+ const { code, stderr } = await spawnPromisified(execPath, [
+ '--input-type=module',
+ '--eval',
+ `import { register } from 'node:module'; register(${urlToRegisterEscaped});`,
+ ]);
+
+ assert.match(stderr, /\[DEP0205\]/);
+ assert.strictEqual(code, 0);
+ });
+
+ it('only emits the warning once per process', async () => {
+ const { code, stderr } = await spawnPromisified(execPath, [
+ '--input-type=module',
+ '--eval',
+ `import { register } from 'node:module';
+ register(${urlToRegisterEscaped});
+ register(${urlToRegisterEscaped});`,
+ ]);
+
+ assert.strictEqual(stderr.split('[DEP0205]').length - 1, 1);
+ assert.strictEqual(code, 0);
+ });
+
+ it('does not emit when --no-deprecation is set', async () => {
+ const { code, stderr } = await spawnPromisified(execPath, [
+ '--no-deprecation',
+ '--input-type=module',
+ '--eval',
+ `import { register } from 'node:module'; register(${urlToRegisterEscaped});`,
+ ]);
+
+ assert.doesNotMatch(stderr, /DEP0205/);
+ assert.strictEqual(code, 0);
+ });
+
+ it('throws when --throw-deprecation is set', async () => {
+ const { code, stderr } = await spawnPromisified(execPath, [
+ '--throw-deprecation',
+ '--input-type=module',
+ '--eval',
+ `import { register } from 'node:module'; register(${urlToRegisterEscaped});`,
+ ]);
+
+ assert.match(stderr, /DEP0205/);
+ assert.notStrictEqual(code, 0);
+ });
+});
diff --git a/test/module-hooks/test-async-loader-hooks-use-hooks-require-esm.mjs b/test/module-hooks/test-async-loader-hooks-use-hooks-require-esm.mjs
index a86b0607246fa9..1eee6a6014aa15 100644
--- a/test/module-hooks/test-async-loader-hooks-use-hooks-require-esm.mjs
+++ b/test/module-hooks/test-async-loader-hooks-use-hooks-require-esm.mjs
@@ -7,6 +7,7 @@ import { spawnSyncAndAssert } from '../common/child_process.js';
spawnSyncAndAssert(
execPath,
[
+ '--no-deprecation',
'--no-experimental-require-module',
'--import',
fixtures.fileURL('es-module-loaders/builtin-named-exports.mjs'),
diff --git a/test/parallel/test-runner-get-test-context.js b/test/parallel/test-runner-get-test-context.js
new file mode 100644
index 00000000000000..bc5be4f01cee4a
--- /dev/null
+++ b/test/parallel/test-runner-get-test-context.js
@@ -0,0 +1,54 @@
+'use strict';
+require('../common');
+const assert = require('node:assert');
+const { test, getTestContext, describe, it } = require('node:test');
+
+// Outside a test — must return undefined
+assert.strictEqual(getTestContext(), undefined);
+
+test('getTestContext returns current context inside test', async () => {
+ const ctx = getTestContext();
+ assert.ok(ctx !== undefined);
+ assert.strictEqual(ctx.name, 'getTestContext returns current context inside test');
+ assert.strictEqual(typeof ctx.signal, 'object');
+ assert.strictEqual(typeof ctx.fullName, 'string');
+});
+
+test('getTestContext works in nested test', async (t) => {
+ await t.test('child', async () => {
+ const ctx = getTestContext();
+ assert.ok(ctx !== undefined);
+ assert.strictEqual(ctx.name, 'child');
+ });
+});
+
+describe('getTestContext works in describe/it', () => {
+ it('has correct name', () => {
+ const ctx = getTestContext();
+ assert.ok(ctx !== undefined);
+ assert.strictEqual(ctx.name, 'has correct name');
+ });
+});
+
+describe('getTestContext returns SuiteContext in suite', () => {
+ it('suite context is available', () => {
+ const ctx = getTestContext();
+ assert.ok(ctx !== undefined);
+ // Suite name appears as parent in nested test context
+ assert.strictEqual(typeof ctx.signal, 'object');
+ assert.strictEqual(typeof ctx.fullName, 'string');
+ });
+});
+
+test('getTestContext works in test body during async operations', async (t) => {
+ const ctx = getTestContext();
+ assert.ok(ctx !== undefined);
+ assert.strictEqual(ctx.name, 'getTestContext works in test body during async operations');
+
+ // Also works in nested async context
+ const ctxInSetImmediate = await new Promise((resolve) => {
+ setImmediate(() => resolve(getTestContext()));
+ });
+ assert.ok(ctxInSetImmediate !== undefined);
+ assert.strictEqual(ctxInSetImmediate.name, 'getTestContext works in test body during async operations');
+});
diff --git a/test/parallel/test-runner-test-fullname.js b/test/parallel/test-runner-test-fullname.js
index 5e8ad47bddbd87..cab35a7a9355aa 100644
--- a/test/parallel/test-runner-test-fullname.js
+++ b/test/parallel/test-runner-test-fullname.js
@@ -9,6 +9,11 @@ before(common.mustCall((t) => {
suite('suite', common.mustCall((t) => {
assert.strictEqual(t.fullName, 'suite');
+ // Test new SuiteContext properties
+ assert.strictEqual(typeof t.passed, 'boolean');
+ assert.strictEqual(t.attempt, 0);
+ // diagnostic() can be called to add diagnostic output
+ t.diagnostic('Suite diagnostic message');
test('test', (t) => {
assert.strictEqual(t.fullName, 'suite > test');
@@ -26,3 +31,18 @@ suite('suite', common.mustCall((t) => {
test((t) => {
assert.strictEqual(t.fullName, '');
});
+
+// Test SuiteContext passed, attempt, and diagnostic properties
+suite('suite with context checks', common.mustCall((ctx) => {
+ assert.strictEqual(ctx.fullName, 'suite with context checks');
+ assert.strictEqual(typeof ctx.passed, 'boolean');
+ assert.strictEqual(ctx.attempt, 0);
+ // Verify diagnostic method is callable
+ ctx.diagnostic('Test diagnostic message in suite');
+
+ test('child test', () => {
+ // Verify properties are accessible in nested test
+ assert.strictEqual(typeof ctx.passed, 'boolean');
+ assert.strictEqual(ctx.attempt, 0);
+ });
+}));
|