Skip to content

Enable run-detect-module-type test and fix its import.cjs fixtures - #37182

Open
robobun wants to merge 6 commits into
mainfrom
farm/ff6be295/fix-detect-module-type-test
Open

Enable run-detect-module-type test and fix its import.cjs fixtures#37182
robobun wants to merge 6 commits into
mainfrom
farm/ff6be295/fix-detect-module-type-test

Conversation

@robobun

@robobun robobun commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Problem

test/cli/run/run-detect-module-type.ts (added in #18562, re-landed in #18686) uses bun:test but its filename lacks .test., so the test runner never collects it and it has never run in CI.

Running it explicitly fails on every Bun version, including current main:

bun test ./test/cli/run/run-detect-module-type.ts
error: Failed to run cjs import.cjs: ...
3 | +fs;
    ^
TypeError: No default value

Cause

Both module-type-fixture/{cjs,esm}/import.cjs end with +fs;, where fs is a module namespace object. ToPrimitive on a namespace object throws, because it has a null prototype and no Symbol.toPrimitive/valueOf/toString. Node 26 throws the same way on that line (TypeError: Cannot convert object to primitive value), so Bun's runtime behavior is correct and the fixture line is the bug. The line only exists to reference the import; the detection result (the console.log) prints before the throw.

Fix

  • Replace +fs; with fs.constants; in both fixtures, keeping the binding referenced without coercing it.
  • Rename the test file to run-detect-module-type.test.ts so CI actually runs it.
  • Spawn the fixtures concurrently instead of via sequential spawnSync, assert stdout is exactly true/false, and reject any stderr on a zero exit.

Review follow-ups folded in:

  • Swept the rest of test/ for the same class of bug (a bun:test file whose name the runner never collects). The only other instance was test/cli/run/run-importmetamain.ts (added in feat(bundler): inlining/dead-code-elimination for import.meta.main (and --compile) #12867, same directory, uncollected since then); its tests pass as-is, so it is renamed here too.
  • The table only exercised marker-free files plus the ESM-syntax-beats-.cjs rows, leaving the opposite direction of the sniff untested. Added exports.js/exports.mjs fixtures with a module.exports marker under both package types: Bun detects these as CommonJS, beating both package.json "type" and the file extension, which is the mirror image of the existing import.cjs -> module rows.

The pre-existing expectation rows are unchanged; the detection they pin already behaves as expected (verified identical output on current main and 1.4.0-canary.1+45ee9556a).

Verification

  • Before: bun test ./test/cli/run/run-detect-module-type.ts fails with the TypeError above on main.
  • After: both files pass with the release binary and a debug build (bun bd test test/cli/run/run-detect-module-type.test.ts test/cli/run/run-importmetamain.test.ts, 3 tests, 22 spawned fixtures).

This is a test-only change: the bugs were in the test infrastructure itself (never collected, broken fixture), not in Bun.


[stamp-90s] gate passed · iteration 1 · 10 files touched

passes on PR (with fix)
Test-only change.

Debug/ASAN (expected pass):
$ bun bd test 'test/cli/run/run-detect-module-type.test.ts' 'test/cli/run/run-importmetamain.test.ts'
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test test/cli/run/run-detect-module-type.test.ts test/cli/run/run-importmetamain.test.ts
bun test v1.4.0 (952b67703)

test/cli/run/run-importmetamain.test.ts:
(pass) import.meta.main in a common.js file [295.95ms]
(pass) import.meta.main [1217.16ms]

test/cli/run/run-detect-module-type.test.ts:
(pass) detect module type [2157.67ms]

 3 pass
 0 fail
 7 expect() calls
Ran 3 tests across 2 files. [5.83s]
Exit: 0
diff hotspot
test/cli/run/module-type-fixture/cjs/exports.js  |  2 +
 test/cli/run/module-type-fixture/cjs/exports.mjs |  2 +
 test/cli/run/module-type-fixture/cjs/import.cjs  |  2 +-
 test/cli/run/module-type-fixture/esm/exports.js  |  2 +
 test/cli/run/module-type-fixture/esm/exports.mjs |  2 +
 test/cli/run/module-type-fixture/esm/import.cjs  |  2 +-
 test/cli/run/run-detect-module-type.test.ts      | 72 ++++++++++++++++++++++++
 test/cli/run/run-detect-module-type.ts           | 54 ------------------
 test/cli/run/run-importmetamain.test.ts          | 38 +++++++++++++
 test/cli/run/run-importmetamain.ts               | 38 -------------
 10 files changed, 120 insertions(+), 94 deletions(-)

gate history · 3 passed · 0 rejected · iteration 1

evidence per changed file
file                                              reads  edits  tests
test/cli/run/module-type-fixture/cjs/exports.js       0      0      0
test/cli/run/module-type-fixture/cjs/exports.mjs      0      0      0
test/cli/run/module-type-fixture/cjs/import.cjs       1      2      0
test/cli/run/module-type-fixture/esm/exports.js       0      0      0
test/cli/run/module-type-fixture/esm/exports.mjs      0      0      0
test/cli/run/module-type-fixture/esm/import.cjs       1      2      0
test/cli/run/run-detect-module-type.test.ts           2      7      0
test/cli/run/run-detect-module-type.ts                1      0      0
test/cli/run/run-importmetamain.test.ts               1      2      0
test/cli/run/run-importmetamain.ts                    1      0      0

The file lacked .test. in its name, so the test runner never collected
it. Its two import.cjs fixtures also ended with +fs; on a module
namespace object, which throws TypeError (ToPrimitive on a namespace
has no default value, same as Node), so the test failed whenever it was
run explicitly. Replace the coercion with a plain property access,
rename the file so CI runs it, and run the 18 fixtures concurrently.
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Module type and main-module tests

Layer / File(s) Summary
Module environment fixtures
test/cli/run/module-type-fixture/*
Fixtures log CommonJS module availability, assign module.exports, and reference fs.constants.
Module type detection assertions
test/cli/run/run-detect-module-type.test.ts
The test runs fixtures with Bun across package types, extensions, and syntax patterns. It validates exit status, stderr, detected module types, and expected mappings.
import.meta.main CLI assertions
test/cli/run/run-importmetamain.test.ts
The tests execute temporary ESM and CommonJS files and verify import.meta.main and CommonJS main-module values.

Possibly related PRs

  • oven-sh/bun#35656: Covers related module-type detection behavior through different code paths and functions.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main changes: enabling the module-type test and fixing its import fixtures.
Description check ✅ Passed The description explains the problem, cause, fixes, and verification results, with information that covers the template requirements.

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the claude label Aug 8, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — test-only change that renames a never-collected test file so CI runs it, fixes a broken fixture line, and swaps spawnSync for concurrent async spawns. The inline nit about the === "false" ternary is minor and carried over from the original file; fine to address or leave.

Extended reasoning...

Overview

This PR touches four files under test/cli/run/: it deletes run-detect-module-type.ts (which used bun:test but was never collected because it lacked .test. in its name), adds run-detect-module-type.test.ts with the same expectation table, and changes +fs;fs.constants; in two import.cjs fixtures. The new test file also converts 18 sequential spawnSync calls into concurrent Bun.spawn + Promise.all, following the harness convention of draining stdout/stderr/exited together.

Security risks

None. This is test-only; no runtime code, no auth/crypto/permissions, no untrusted input handling.

Level of scrutiny

Low. The expectation table is byte-for-byte identical to what was already committed (just reformatted with double quotes and as const). The fixture fix is well-justified: +fs on a module namespace object throws TypeError in both Bun and Node because namespace objects have no ToPrimitive path; fs.constants; keeps the import referenced without coercion. All 18 fixture files referenced in the table exist on disk, and the two package.json files have the expected type fields. The concurrent-spawn rewrite follows the CLAUDE.md pattern (await using proc, Promise.all([stdout.text(), stderr.text(), proc.exited])).

Other factors

  • The one finding is a nit about the lossy stdout.trim() === "false" ? "commonjs" : "module" mapping. This is real but low-impact: the fixtures are controlled one-liners that can only print "true" or "false", the exit-code check catches crashes, and the identical ternary existed in the deleted original — it was carried over, not introduced. Not a blocker.
  • The USE_SYSTEM_BUN=1 must-fail rule does not apply here: there is no accompanying runtime fix; this PR is enabling a pre-existing behavior-pinning test that was silently never running.
  • No prior human or bot reviews to reconcile with; no outstanding comments.

Comment thread test/cli/run/run-detect-module-type.test.ts Outdated
@robobun

robobun commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the review nit in 0bb1e9a: the stdout mapping is now exact, "true" -> module, "false" -> commonjs, and anything else surfaces the raw output in the toEqual diff instead of silently counting as module.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/cli/run/run-detect-module-type.test.ts`:
- Around line 47-50: Update the subprocess result handling around proc.stdout,
proc.stderr, and proc.exited so successful fixtures also fail when stderr
contains unexpected output. Assert the combined result according to the existing
bunEnv fixture subprocess convention, while preserving the current nonzero-exit
error reporting.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6d69975d-3f92-4759-8858-2b7824a7c865

📥 Commits

Reviewing files that changed from the base of the PR and between f972c28 and 0bb1e9a.

📒 Files selected for processing (4)
  • test/cli/run/module-type-fixture/cjs/import.cjs
  • test/cli/run/module-type-fixture/esm/import.cjs
  • test/cli/run/run-detect-module-type.test.ts
  • test/cli/run/run-detect-module-type.ts
💤 Files with no reviewable changes (1)
  • test/cli/run/run-detect-module-type.ts

Comment thread test/cli/run/run-detect-module-type.test.ts

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — test-only change enabling a previously uncollected test; both earlier review nits (exact stdout mapping, stderr rejection) are addressed.

What was reviewed:

  • Fixture change +fs;fs.constants; keeps the import binding referenced without ToPrimitive coercion; no other +fs sites remain in the fixture tree.
  • Expectation table is byte-identical to the deleted file; all 18 fixture filenames exist on disk.
  • Subprocess handling drains stdout/stderr/exited concurrently, uses bunEnv/bunExe, and now rejects both non-"true"/"false" stdout and any stderr.
Extended reasoning...

Overview

This PR touches only test infrastructure: it renames test/cli/run/run-detect-module-type.ts to .test.ts so the runner collects it, replaces +fs; with fs.constants; in the two import.cjs fixtures (unary-plus on a module namespace object throws in both Bun and Node, so the fixture itself was broken), and rewrites the test body to spawn the 18 fixtures concurrently via Bun.spawn + Promise.all instead of sequential spawnSync. The expectation table pinning module-type detection is unchanged from the deleted file.

Security risks

None. No runtime, native, or built-in module code is touched — only a test file and two three-line fixture scripts under test/cli/run/.

Level of scrutiny

Low. This is a self-contained test-enablement change with no production code paths involved. The interesting question is whether the newly-enabled test is sound, and the two prior review rounds already tightened it: stdout is now mapped exactly ("true"→module, "false"→commonjs, anything else surfaces raw in the toEqual diff) and any non-empty stderr on a zero-exit run throws. The fixture directory listing confirms all 18 referenced files exist and no sibling +fs sites were missed.

Other factors

Both prior review threads (my stdout-mapping nit and CodeRabbit's stderr check) are marked resolved and the diff reflects the fixes. Harness conventions are followed: bunEnv/bunExe, await using for the subprocess, concurrent pipe draining, no sleeps or hardcoded ports, no network. The stderr check is ordered after the exit-code check rather than before, but the exit-code branch already includes stderr in its message so diagnostics are preserved either way.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — test-only change enabling two previously-uncollected test files and fixing a broken fixture; earlier review nits are addressed.

What was reviewed:

  • +fs;fs.constants; fixture fix — namespace ToPrimitive does throw in both Bun and Node, so the fixture was the bug.
  • Rewritten test: concurrent Bun.spawn with await using, pipes drained via Promise.all, exact tri-valued stdout mapping, stderr rejected on success — matches harness conventions.
  • New exports.{js,mjs} rows and the run-importmetamain rename (100% content-identical) — fixture set matches the 22-row table; no runtime code touched.
Extended reasoning...

Overview

This PR is entirely under test/cli/run/. It renames two test files that used bun:test but lacked .test. in their names (so CI never collected them), fixes a broken fixture line (+fs; on a module namespace object, which throws in both Bun and Node), rewrites run-detect-module-type to spawn fixtures concurrently with proper pipe draining and exact assertions, and adds four exports.{js,mjs} fixtures pinning the CommonJS-marker side of Bun's module-type sniff. No source code under src/ is touched.

Security risks

None. Test-only; spawns local fixtures with bunExe()/bunEnv, no network, no filesystem writes outside the fixture tree, no untrusted input.

Level of scrutiny

Low. The original test never ran, so enabling it cannot regress anything already covered. The fixture fix is a one-token change whose rationale (namespace ToPrimitive) is spec-correct and verified against Node. The rewrite follows the repo's documented subprocess-test patterns (await using, Promise.all on stdout/stderr/exited, bunEnv). The run-importmetamain rename is a git similarity 100% move with no content change.

Other factors

Two prior review threads (my stdout-mapping nit and CodeRabbit's stderr check) are both addressed and resolved in the current diff — stdout is now mapped tri-valued so garbage output fails visibly, and non-empty stderr on a zero exit throws. The 22-row table matches the on-disk fixture set exactly (11 files × 2 package types). The added exports.mjs → commonjs rows pin Bun-specific detection behavior that the PR description states was verified against current main and a recent canary, so they document existing behavior rather than assert new semantics.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/cli/run/run-importmetamain.test.ts`:
- Around line 2-3: Replace tmpdirSync-based fixture setup with disposable
tempDir usage at both setup sites: import tempDir, remove the mkdirSync and
tmpdirSync imports, and declare each directory as using dir = tempDir("...",
{}). Ensure the fixtures rely on tempDir’s automatic creation and disposal.
- Around line 13-20: Update both Bun.spawnSync calls in the import-meta tests to
destructure exitCode, and assert each exitCode equals 0 alongside its
corresponding stdout assertion, including the CommonJS fixture test.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d428e4ee-1ac7-455a-9274-94732a399445

📥 Commits

Reviewing files that changed from the base of the PR and between 0bb1e9a and 86a9669.

📒 Files selected for processing (6)
  • test/cli/run/module-type-fixture/cjs/exports.js
  • test/cli/run/module-type-fixture/cjs/exports.mjs
  • test/cli/run/module-type-fixture/esm/exports.js
  • test/cli/run/module-type-fixture/esm/exports.mjs
  • test/cli/run/run-detect-module-type.test.ts
  • test/cli/run/run-importmetamain.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/cli/run/run-importmetamain.test.ts`:
- Around line 2-3: Replace tmpdirSync-based fixture setup with disposable
tempDir usage at both setup sites: import tempDir, remove the mkdirSync and
tmpdirSync imports, and declare each directory as using dir = tempDir("...",
{}). Ensure the fixtures rely on tempDir’s automatic creation and disposal.
- Around line 13-20: Update both Bun.spawnSync calls in the import-meta tests to
destructure exitCode, and assert each exitCode equals 0 alongside its
corresponding stdout assertion, including the CommonJS fixture test.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d428e4ee-1ac7-455a-9274-94732a399445

📥 Commits

Reviewing files that changed from the base of the PR and between 0bb1e9a and 86a9669.

📒 Files selected for processing (6)
  • test/cli/run/module-type-fixture/cjs/exports.js
  • test/cli/run/module-type-fixture/cjs/exports.mjs
  • test/cli/run/module-type-fixture/esm/exports.js
  • test/cli/run/module-type-fixture/esm/exports.mjs
  • test/cli/run/run-detect-module-type.test.ts
  • test/cli/run/run-importmetamain.test.ts
🛑 Comments failed to post (2)
test/cli/run/run-importmetamain.test.ts (2)

2-3: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
repo_root="$(pwd)"
rg -n -C 3 'tempDir\(|tmpdirSync\(' \
  "$repo_root/test/harness.ts" "$repo_root/test" --glob '*.test.ts'

Repository: oven-sh/bun

Length of output: 2031


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '%s\n' '--- target file ---'
sed -n '1,120p' test/cli/run/run-importmetamain.test.ts
printf '%s\n' '--- tempDir definitions and nearby usage ---'
rg -n -C 4 'function tempDir|const tempDir|tempDir\(|tmpdirSync\(' test/harness.ts test/cli/run --glob '*.test.ts' | head -240

Repository: oven-sh/bun

Length of output: 2002


🌐 Web query:

oven-sh/bun test/harness.ts tempDir("run-importmetamain

💡 Result:

In the context of the oven-sh/bun repository, the components mentioned relate to testing infrastructure for ensuring correct bundler and runtime behavior regarding import.meta.main and require.main [1]. 1. tempDir: This is a utility function exported from test/harness.ts [2][3]. It creates a temporary directory for test isolation and returns a path that also acts as a disposable resource (supporting Symbol.dispose and Symbol.asyncDispose) to automatically clean up the directory after the test completes [2][3]. It is frequently used in conjunction with tempDirWithFiles to set up fixture files [4]. 2. run-importmetamain: This refers to a test file, specifically test/cli/run/run-importmetamain.test.ts (originally named run-importmetamain.ts but renamed to be collected by the test runner) [1]. This test suite was created to verify how Bun handles import.meta.main and require.main === module across different execution contexts (CJS, ESM, and bundled code) [1]. It specifically addresses precedence issues in code generation [1] and ensures that these properties behave consistently when code is run directly versus when it is bundled [1][5]. These components are part of Bun's standard testing practices, where developers use harness.ts to manage temporary test environments and create specific test cases (like run-importmetamain.test.ts) to ensure that Bun's transpiler and bundler correctly maintain the semantics of Node.js-compatible features [1][6][4].

Citations:


🌐 Web query:

site:github.com/oven-sh/bun/blob test/harness.ts "export function tempDir" "Symbol.dispose"

💡 Result:

In the Bun test harness (test/harness.ts), the tempDir function is designed to return a string representing a temporary directory path that also implements the Disposable and AsyncDisposable interfaces [1][2]. This allows the directory to be automatically cleaned up when using the using keyword in TypeScript [3]. The implementation achieves this by wrapping the temporary directory path in a class called DisposableString, which extends String [1][2]. This class implements: 1. [Symbol.dispose]: Uses fs.rmSync to synchronously remove the directory and its contents recursively [1][2]. 2. [Symbol.asyncDispose]: Uses fs.promises.rm to asynchronously remove the directory and its contents recursively [1][2]. Because the returned object is an instance of DisposableString (which behaves like a string) and implements these disposal methods, developers can write code such as: using dir = tempDir("my-test", { "file.txt": "content" }); // The directory is automatically deleted when 'dir' goes out of scope.

Citations:


Replace tmpdirSync() with disposable tempDir().

At both fixture setup sites, import tempDir, remove mkdirSync, and use using dir = tempDir("...", {});. tempDir() creates and disposes the directory; tmpdirSync() is prohibited in test files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/cli/run/run-importmetamain.test.ts` around lines 2 - 3, Replace
tmpdirSync-based fixture setup with disposable tempDir usage at both setup
sites: import tempDir, remove the mkdirSync and tmpdirSync imports, and declare
each directory as using dir = tempDir("...", {}). Ensure the fixtures rely on
tempDir’s automatic creation and disposal.

Sources: Coding guidelines, Learnings


13-20: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
repo_root="$(pwd)"
rg -n -C 4 'Bun\.spawnSync\(|\bexitCode\b' \
  "$repo_root/test" --glob '*.test.ts'

Repository: oven-sh/bun

Length of output: 2031


🏁 Script executed:

#!/bin/bash
set -euo pipefail

target="test/cli/run/run-importmetamain.test.ts"
if [ -f "$target" ]; then
  printf '%s\n' '--- target ---'
  cat -n "$target"
else
  printf 'missing target: %s\n' "$target" >&2
  exit 1
fi

printf '%s\n' '--- focused spawnSync conventions ---'
rg -n -C 5 'Bun\.spawnSync\(' test --glob '*.test.ts' | head -n 500

printf '%s\n' '--- focused exitCode assertions ---'
rg -n -C 3 'exitCode' test/cli test --glob '*.test.ts' | head -n 500

Repository: oven-sh/bun

Length of output: 2002


🌐 Web query:

oven-sh/bun test/cli/run/run-importmetamain.test.ts Bun.spawnSync exitCode

💡 Result:

The file test/cli/run/run-importmetamain.test.ts in the oven-sh/bun repository is a test file designed to verify the behavior of import.meta.main and require.main === module across different execution contexts [1]. It was renamed to include the .test.ts suffix to ensure it is correctly collected and executed by the Bun test runner [1]. In this test file, Bun.spawnSync is used to execute Bun processes synchronously [2][3]. The exitCode property returned by Bun.spawnSync is then used to verify that the executed process finished with the expected status code (e.g., 0 for success) [2][4]. While specific usage within run-importmetamain.test.ts focuses on validating the logic of module main-entry detection, the general pattern for checking exit codes with Bun.spawnSync is [2][5]: const { exitCode } = Bun.spawnSync({ cmd: ["bun", "run", "some-file.ts"], }); expect(exitCode).toBe(0); The SyncSubprocess object returned by Bun.spawnSync also includes a success boolean property, which is a shorthand for checking if exitCode === 0 [3][4].

Citations:


🌐 Web query:

site:github.com/oven-sh/bun/blob test/cli/run/run-importmetamain.test.ts "const { stdout"

💡 Result:

The file test/cli/run/run-importmetamain.test.ts appears to be part of the Bun runtime test suite. It is designed to verify the behavior of the import.meta.main property [1][2]. In Bun, import.meta.main is a boolean property used to determine if the current module is the entry point of the application [1][2]. When a script is executed directly (e.g., bun run script.ts), import.meta.main evaluates to true [1][2]. While the specific content of test/cli/run/run-importmetamain.test.ts is not fully detailed in the provided search results, related test files within the Bun repository—such as test/bundler/bundler_compile.test.ts—demonstrate how this property is tested [1][2]. These tests typically spawn a Bun process and capture the stdout to assert that import.meta.main behaves as expected: const { stdout } = Bun.spawnSync({... }); // Example logic used in tests: // console.log(( => import.meta.main).toString.includes('true')); The code snippet in your query, const { stdout }, is a common pattern in these tests for extracting the output from a spawned Bun process, allowing the test to assert that the runtime's internal checks for the entry point are correct [3][4][5].

Citations:


🌐 Web query:

raw.githubusercontent.com oven-sh bun test/cli/run/run-importmetamain.test.ts

💡 Result:

The file test/cli/run/run-importmetamain.test.ts is a test file within the Bun runtime repository [1]. It was created by renaming a previously existing file (run-importmetamain.ts) to ensure it would be correctly collected and executed by the Bun test runner, which specifically looks for files containing .test in their filename [1]. The primary purpose of this test file is to verify the behavior of import.meta.main and require.main === module across different module systems (CommonJS and ESM) [1]. It was specifically used to ensure that these expressions are handled correctly by the runtime, including fixing precedence bugs in the transpiler/printer that could incorrectly affect these checks [1]. In essence, the file contains tests that cover: * CommonJS entry points [1]. * Required non-main CommonJS modules [1]. * ESM inverted form [1]. * Syntax error handling for specific patterns [1]. This file is part of the broader test suite in the oven-sh/bun repository, helping ensure consistency in how Bun handles module entry points and environment variables [1][2].

Citations:


Assert each subprocess exit status.

Destructure exitCode from both Bun.spawnSync results and assert exitCode is 0 after each stdout assertion, including the CommonJS test. Otherwise, a fixture can print the expected JSON and still exit non-zero while the test passes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/cli/run/run-importmetamain.test.ts` around lines 13 - 20, Update both
Bun.spawnSync calls in the import-meta tests to destructure exitCode, and assert
each exitCode equals 0 alongside its corresponding stdout assertion, including
the CommonJS fixture test.

Sources: Coding guidelines, Learnings

@robobun

robobun commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Both review findings on run-importmetamain.test.ts are addressed in d3e5b9e: fixture setup now uses the disposable tempDir helper from harness, and both tests assert empty stderr, exact stdout, and a zero exit code. Verified passing with the release binary and a debug build.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/cli/run/run-importmetamain.test.ts`:
- Line 4: Extend the run-importmetamain test beyond the entry-module probe by
adding an imported ESM child and a required CommonJS child, each reporting and
asserting import.meta.main === false. Update the test setup and expectations to
cover both child-module paths while preserving the existing entry-module checks.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ec544e89-842e-4350-98f2-f892998a8ed8

📥 Commits

Reviewing files that changed from the base of the PR and between 86a9669 and d3e5b9e.

📒 Files selected for processing (1)
  • test/cli/run/run-importmetamain.test.ts

Comment thread test/cli/run/run-importmetamain.test.ts

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — test-only change that enables two previously-uncollected test files and fixes their fixtures. My earlier nit and the CodeRabbit findings are all addressed.

What was reviewed:

  • Confirmed all 22 table entries have matching fixture files on disk; the +fs;fs.constants; fix is correct (ToPrimitive on a module namespace throws in both Bun and Node).
  • Checked the tri-valued stdout mapping and stderr guard land the earlier review feedback; run-importmetamain.test.ts now uses tempDir, drains pipes concurrently, and asserts stderr/stdout/exitCode in order.
  • No production code touched; the new exports.{js,mjs} rows pin existing detection behavior verified against main.
Extended reasoning...

Overview

This PR renames two bun:test files under test/cli/run/ that lacked the .test. infix and were therefore never collected by CI: run-detect-module-type.ts and run-importmetamain.ts. It fixes the import.cjs fixtures (which threw TypeError: No default value on +fs; because module namespace objects have no ToPrimitive), adds four exports.{js,mjs} fixtures to pin the CommonJS-marker-beats-extension direction of detection, and rewrites both test files to use concurrent Bun.spawn, tempDir, and exact stdout/stderr/exit assertions. Ten files changed, all under test/.

Security risks

None. No production code, no network, no external input — the tests spawn local fixture files with bunEnv and compare stdout to a fixed table.

Level of scrutiny

Low-to-moderate. Test-only, mechanical rename plus fixture repair. The main thing to check is that enabling a never-run test doesn't introduce CI flakiness or pin wrong behavior. The assertions are deterministic (no sleeps, no ports, no timing), pipes are drained concurrently per REVIEW.md, and the PR description confirms the pinned detection results match both current main and a prior canary. The new exports.mjs -> commonjs rows codify Bun's existing marker-sniffing behavior rather than changing it.

Other factors

All three prior review findings on this PR are resolved: my nit on the lossy === "false" ternary (now tri-valued so garbage stdout fails visibly), CodeRabbit's stderr-on-zero-exit check (now throws), and the run-importmetamain cleanup (now tempDir + full {stderr, stdout, exitCode} assertions). The evidence block shows 3 tests / 22 fixtures passing under debug+ASAN. No outstanding reviewer comments remain.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — test-only change enabling two previously-uncollected test files; the earlier nit on the lossy stdout mapping and the stderr/tempDir follow-ups are all addressed.

What was reviewed:

  • +fs;fs.constants; fixture fix — confirmed the original line throws identically in Node, so the fixture was the bug, not the runtime.
  • New exports.{js,mjs} rows pin existing CommonJS-marker detection; pre-existing table rows are unchanged.
  • Both test files now drain stdout/stderr/exited concurrently, reject non-empty stderr, and assert exact output before exit code.
  • Checked that all 22 fixture filenames referenced in the table exist on disk under both cjs/ and esm/.
Extended reasoning...

Overview

This PR renames two test files under test/cli/run/ that used bun:test but lacked .test. in their filenames, so CI never collected them. run-detect-module-type.ts (from #18562/#18686) and run-importmetamain.ts (from #12867) become .test.ts files. Along the way it fixes the import.cjs fixtures whose trailing +fs; line threw TypeError: No default value (ToPrimitive on a module namespace object — same behavior in Node), replaces spawnSync with concurrent Bun.spawn + Promise.all pipe draining, and adds four exports.{js,mjs} fixtures pinning the mirror case where a module.exports marker beats package.json type and file extension. run-importmetamain is rewritten to use the disposable tempDir helper with full stderr/stdout/exitCode assertions. No production code is touched.

Security risks

None. All changes are confined to test/, spawn only the local bunExe() against local fixture files under bunEnv, and touch no network, auth, crypto, or permission surface.

Level of scrutiny

Low-to-medium. It's a pure test-infrastructure fix: enabling dormant tests, repairing a broken fixture line, and modernizing harness usage per test/CLAUDE.md conventions (tempDir, concurrent pipe draining, test.concurrent, exit-code-last assertions). The pre-existing expectation rows are unchanged, and the four new rows pin behavior the PR author verified identical on main and 1.4.0-canary — they document current detection semantics rather than change them.

Other factors

All prior review feedback is resolved: my earlier nit about the lossy === "false" ternary was fixed in 0bb1e9a (now tri-valued so unexpected stdout surfaces in the toEqual diff); CodeRabbit's stderr-rejection request was applied in 3612059; the tempDir/exit-status follow-up on run-importmetamain landed in d3e5b9e; and the child-module-coverage suggestion was withdrawn after confirming test/js/bun/resolve/import-meta.test.js already covers it. I confirmed all 22 fixture files referenced in the table exist under both module-type-fixture/cjs/ and module-type-fixture/esm/. The PR description shows both files passing under bun bd test (3 tests, 22 spawned fixtures).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant