nodejs / nodejs/node

Test runner with isolation=none does not work in child process

Open
#60,020 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

child_process test_runner
Dominant language
JavaScript
Stars
122k
Forks
37.3k
Avg merge
4d 2h
Merged PRs (30d)
283

Description

Version

v24.9.0

Platform
Linux home 5.15.0-153-generic #163-Ubuntu SMP Thu Aug 7 16:37:18 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
Subsystem

No response

What steps will reproduce the bug?

runner.js

import cluster from 'node:cluster';
import { run } from "node:test";

if (cluster.isPrimary) {
  cluster.fork();
} else {
  const stream = run({
    isolation: "none",
  });

  stream.on("data", (data) => {
    console.log("on data", data.type);
  });

  stream.on("end", () => {
    console.log("on end")
    process.exit(0);
  });

  stream.on("error", (err) => {
    console.log("on error", err);
  });
}

dummy.test.js

import { describe, it } from "node:test";
import * as assert from "node:assert";

describe("suite", () => {
  it("works", ()  => {
    assert.ok(true);
  });
});

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

Always. No.

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

With isolation: "process" (the default), here's the output:

on data test:enqueue
on data test:dequeue
on data test:enqueue
on data test:dequeue
on data test:enqueue
on data test:dequeue
on data test:complete
on data test:start
on data test:start
on data test:pass
on data test:complete
on data test:plan
on data test:pass
on data test:summary
on data test:complete
on data test:plan
on data test:diagnostic
on data test:diagnostic
on data test:diagnostic
on data test:diagnostic
on data test:diagnostic
on data test:diagnostic
on data test:diagnostic
on data test:diagnostic
on data test:summary
on end

Process finished with exit code 0

The process cleanly exits at the end of the tests.

What do you see instead?

With isolation: "none", here's the output:

on data test:enqueue
on data test:dequeue
on data test:enqueue
on data test:dequeue
on data test:complete
on data test:start
on data test:start
on data test:pass
on data test:complete
on data test:plan
on data test:pass

And the process hangs.

Additional information

The goal was to use the "cluster" module to run the tests in parallel with the shard option:

import { run } from "node:test";
import { spec } from "node:test/reporters";
import { PassThrough } from "node:stream";
import { availableParallelism } from "node:os";
import cluster from 'node:cluster';

const concurrency = availableParallelism();
let completed = 0;

if (cluster.isPrimary) {
  const mergedStream = new PassThrough({
    objectMode: true
  });

  cluster.on("message", (_worker, message) => {
    mergedStream.emit("data", message);
  });

  mergedStream
    .compose(spec)
    .pipe(process.stdout);

  for (let i = 1; i <= concurrency; i++) {
    cluster.fork({
      SHARD_INDEX: i,
      SHARD_TOTAL: concurrency,
    });
  }

  cluster.on("exit", (worker, code, signal) => {
    if (++completed === concurrency) {
      mergedStream.end();
    }
  });
} else {
  const stream = run({
    isolation: "none",
    shard: {
      index: parseInt(process.env.SHARD_INDEX, 10),
      total: parseInt(process.env.SHARD_TOTAL, 10),
    },
  });

  stream.on("data", (chunk) => {
    process.send(chunk);
  });
}

Related: https://github.com/nodejs/node/issues/55939

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproduction in runner.js and dummy.test.js, then trace the node:test run() entry point with isolation set to "none" when invoked from a cluster child process. Compare its stream lifecycle with the default "process" isolation and the related issue 55939. Done means the child-process stream emits the remaining events, ends, and exits cleanly while retaining shard support.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.