node icon indicating copy to clipboard operation
node copied to clipboard

--allow-natives-syntax --test not propagating natives syntax support to child processes

Open jdmarshall opened this issue 2 weeks ago • 9 comments

Version

v24.11.1

Platform

Darwin MacBook-Pro 23.6.0 Darwin Kernel Version 23.6.0: Wed May 14 13:51:39 PDT 2025; root:xnu-10063.141.1.705.2~2/RELEASE_ARM64_T6020 arm64

Subsystem

test runner

What steps will reproduce the bug?

This worked in Node 24.6.0, fails in anything later

I'm trying to write some integration tests for code that uses the bench-node library, and all of the tests run fine in node 22, but in node 24 they are getting errors,

bench-node module must be run with --allow-natives-syntax argument

I believe this is due to the test runner not running the tests with the same configuration the parent process was handed.

And since it's not legal to add the natives syntax as a NODE_OPTIONS flag, I have no workaround for this at present.

(You don't actually document how to run the tests without child processes from the CLI, only from a direct run() call)

How often does it reproduce? Is there a required condition?

download bench-node and try to run its tests with node 24.6.0, node 24.11.1

node --test --allow-natives-syntax --expose-gc

What is the expected behavior? Why is that the expected behavior?

The tests should run fine.

What do you see instead?

test at test/basic.js:194:1
✖ simple usage (0.032667ms)
  Error: bench-node module must be run with --allow-natives-syntax argument
      at throwIfNoNativesSyntax (/Users/jasonmarshall/Projects/cobbler/bench-node/lib/index.js:96:9)
      at Suite.run (/Users/jasonmarshall/Projects/cobbler/bench-node/lib/index.js:198:3)
      at SuiteContext.<anonymous> (/Users/jasonmarshall/Projects/cobbler/bench-node/test/basic.js:204:39)
      at Suite.runInAsyncScope (node:async_hooks:214:14)
      at Suite.createBuild (node:internal/test_runner/test:1476:13)
      at new Suite (node:internal/test_runner/test:1467:28)
      at Test.createSubtest (node:internal/test_runner/test:865:18)
      at run (node:internal/test_runner/harness:364:28)
      at test (node:internal/test_runner/harness:378:12)
      at Object.<anonymous> (/Users/jasonmarshall/Projects/cobbler/bench-node/test/basic.js:194:1)

Additional information

No response

jdmarshall avatar Dec 08 '25 07:12 jdmarshall

There's a workaround that works in node 24, --test-isolation none, but this flag doesn't exist in node 20, which means that the common github pattern of running your module on different node versions doesn't work.

jdmarshall avatar Dec 08 '25 07:12 jdmarshall

I was about to file a new issue, but this ticket issue seems similar, so I'll piggy back.

Given the following test file:

import assert from "node:assert/strict";
import { describe, it } from "node:test";

describe("test", () => {
    it("calls gc", () => {
        globalThis.gc();
    });
});

With Node v22.21.1, executed with node --expose-gc --test test.js:

▶ test
  ✔ calls gc (4.070436ms)
✔ test (4.664495ms)
ℹ tests 1
ℹ suites 1
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 68.254075

With Node v24.11.1, executed with node --expose-gc --test test.js:

▶ test
  ✖ calls gc (0.444639ms)
✖ test (1.022694ms)
ℹ tests 1
ℹ suites 1
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 48.219594

✖ failing tests:

test at test.js:5:5
✖ calls gc (0.444639ms)
  TypeError: globalThis.gc is not a function
      at TestContext.<anonymous> (file:///.../test.js:6:20)
      at Test.runInAsyncScope (node:async_hooks:214:14)
      at Test.run (node:internal/test_runner/test:1106:25)
      at Test.start (node:internal/test_runner/test:1003:17)
      at node:internal/test_runner/test:1516:71
      at node:internal/per_context/primordials:464:82
      at new Promise (<anonymous>)
      at new SafePromise (node:internal/per_context/primordials:433:3)
      at node:internal/per_context/primordials:464:9
      at Array.map (<anonymous>)

I would have expected that the --expose-gc flag passed on the command line to be propagated to the child test process in Node 24.

With Node v24.11.1, executed with node --test-isolation none --expose-gc --test test.js:

▶ test
  ✔ calls gc (3.431862ms)
✔ test (3.976803ms)
ℹ tests 1
ℹ suites 1
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 16.376009

u873838 avatar Dec 08 '25 13:12 u873838

I'm bisecting it.

RafaelGSS avatar Dec 08 '25 16:12 RafaelGSS

Coincidentally my test case also uses —expose-gc but it didn’t get far enough to fail. It’s in one of Rafael’s projects so 🤞

@u873838 can you verify the last good version? I got 24.6.0

jdmarshall avatar Dec 08 '25 18:12 jdmarshall

This is the offending PR https://github.com/nodejs/node/pull/59138. I'm almost sure this is not the intended behaviour - if so, it should have been done in a semver-major PR.

cc: @nodejs/test_runner @pmarchini - any objections in reverting it?

RafaelGSS avatar Dec 08 '25 21:12 RafaelGSS

Hey @RafaelGSS, you're right! no breaking changes were intended! Reverting it, unfortunately, will reintroduce other bugs related to the configuration file. I would suggest trying a fix-forward instead of reverting it!

pmarchini avatar Dec 08 '25 21:12 pmarchini

@pmarchini A fix for it would be great. In any case, I won't include that PR in the upcoming v25 release. Is there a chance to have a fix for it in the next v24 release?

RafaelGSS avatar Dec 08 '25 21:12 RafaelGSS

I'll try to come up with a fix in the next couple of days!

pmarchini avatar Dec 08 '25 21:12 pmarchini

For now I set my gh actions to use 24.6, which won't bother anyone for a few weeks.

Since it only happens to me in tests I'm debating whether I even need to do anything with package.json 'engines' or let it be.

jdmarshall avatar Dec 08 '25 21:12 jdmarshall