Skip to content

bun test: honor --pass-with-no-tests when a single path argument does not exist - #41924

Closed
robobun wants to merge 1 commit into
mainfrom
robobun/6fcb5e49/pass-with-no-tests-path
Closed

robobun wants to merge 1 commit into
mainfrom
robobun/6fcb5e49/pass-with-no-tests-path

Conversation

@robobun

@robobun robobun commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • bun test ./does-not-exist --pass-with-no-tests prints Test filter "./does-not-exist" had no matches and exits 1. The same flag already gives exit 0 for two missing paths, for a directory with no test files, for -t with no match, and for an empty project. A monorepo step like bun test ./packages/$P --pass-with-no-tests fails for a package that has no tests yet, which is the main use of jest's --passWithNoTests.
  • The cause is the single-path ScanError::DoesNotExist branch in src/runtime/cli/test_command.rs:2044. It sets exit code 1 and calls global_exit() before anything reads ctx.test_options.pass_with_no_tests.

Fix

  • Take the early exit only when --pass-with-no-tests is not set. With the flag, the single missing path falls through to the shared "The following filters did not match any test files:" report, which already honors the flag at test_command.rs:2662 and exits 0.
  • Correct because every other no-tests shape goes through that shared path. The single-path branch only exists to print a shorter message and skip the scan summary. Without the flag its output and exit code are unchanged.
  • Verified: test/cli/test/pass-with-no-tests.test.ts (three new test.each rows, stock bun fails the single-path row). Also ran the scanner path cases in test/cli/test/bun-test.test.ts.

Background

  • bun test treats a positional that starts with ./ or ../, or is absolute, as a path to scan. Any other positional is a substring filter over discovered test file paths. Only the path form can hit DoesNotExist.
  • --pass-with-no-tests maps to ctx.test_options.pass_with_no_tests. It only flips the final exit code when no test ran. It does not suppress the report of what was searched.

… not exist

bun test ./missing --pass-with-no-tests printed 'Test filter "./missing"
had no matches' and exited 1. The single-path DoesNotExist branch exits
before the flag is consulted, while two missing paths, an empty
directory, and -t with no match all reach the shared no-tests path and
exit 0 with the flag. Skip the early exit when the flag is set so the
single-path case takes the same path.
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

On-demand reviews are free for the next 13 days. After that, they cost $0.25 per reviewed file.

Or wait 21 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: ab430204-e4ab-4c32-a131-f9266972b724

📥 Commits

Reviewing files that changed from the base of the PR and between b52d3e5 and fe00457.

📒 Files selected for processing (2)
  • src/runtime/cli/test_command.rs
  • test/cli/test/pass-with-no-tests.test.ts

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

@robobun

robobun commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 9:54 PM PT - Sep 7th, 2026

@robobun, your commit fe00457 is building: #112639

@robobun

robobun commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status: ready for review.

Reproduced on bun 1.4.3 in a project with t/x.test.ts and an empty e/ directory:

bun test ./does-not-exist --pass-with-no-tests                 -> rc 1  (Test filter "./does-not-exist" had no matches)
bun test ./does-not-exist ./also-missing --pass-with-no-tests  -> rc 0
bun test ./e --pass-with-no-tests                              -> rc 0

With this change the first row is rc 0 and prints the same "The following filters did not match any test files:" report as the other two. Without the flag all three rows stay rc 1.

CI (build 112639): every lane that runs this diff is green. The one red job is test/js/node/test/parallel/test-crypto-dh-leak.js on debian x64-asan, which fails the same way on main and does not touch this change.

@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 — one-clause guard change that makes the single-missing-path branch consistent with the multi-path fall-through it already sits next to.

What was reviewed:

  • Traced the fall-through: with the flag set and scan() returning DoesNotExist, test_files stays empty, hits the shared "did not match any test files" report at ~2450, and should_fail_on_no_tests at 2664 evaluates false → exit 0.
  • Confirmed no behavior change without the flag: the original error message and global_exit() still fire when pass_with_no_tests is false.
  • Tests cover both flag states across single missing path / multiple missing paths / empty dir, assert stderr before exit code, and live in the existing pass-with-no-tests.test.ts.
Extended reasoning...

Overview

The PR touches two files: a one-line condition change in src/runtime/cli/test_command.rs (adding && !ctx.test_options.pass_with_no_tests to the guard on the single-path DoesNotExist early-exit branch), and three new test.each rows in the existing test/cli/test/pass-with-no-tests.test.ts. The fix aligns the single-missing-path case with the multi-path case, which already fell through to the shared "did not match any test files" reporting path that honors --pass-with-no-tests at line 2664.

Security risks

None. This is CLI exit-code behavior for the test runner when a user-supplied path does not exist. No parsing of untrusted data, no auth/crypto/permissions surface, no memory management changes. The only effect is that a run which previously exited 1 now exits 0 when the user explicitly opted into --pass-with-no-tests.

Level of scrutiny

Low. The change is a single boolean clause appended to an existing if guard, and the fall-through target is code that already handles this exact scenario for the len() > 1 case. I traced the control flow: when the guard is skipped, test_files is empty, pass_with_no_tests_from_filter is false, so failed_to_find_any_tests becomes true (printing the filter report), and should_fail_on_no_tests = !pass_with_no_tests && ... evaluates to false, yielding exit 0. Without the flag, the original branch is unchanged — same error message, same global_exit() with code 1.

Other factors

Tests are well-structured per repo conventions: added to the existing feature test file, use tempDir/bunExe/bunEnv, await using on spawned processes, assert stderr content before exit code, and cover the variant matrix (single path — the actual fix; multiple paths and empty dir — regression guards for already-working siblings) in both flag states. The new tests only drain stderr (not stdout) in Promise.all, but this matches every existing test in the file and bun test writes negligible stdout on the no-tests path, so there is no deadlock risk. No CODEOWNERS entry covers these paths. Exit reason was dry_streak with no findings and no outstanding reviewer objections.

@robobun

robobun commented Sep 26, 2026

Copy link
Copy Markdown
Collaborator Author

#44017 covers this case through the shared exit gate: every path argument with no matches is reported, the run exits 1, and --pass-with-no-tests exits 0. Its tests include the rows from this PR. If #44017 lands, this PR can close.

@robobun

robobun commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator Author

Closing in favor of #44017. That PR removes the single-path early exit that this PR gates, so --pass-with-no-tests applies to a single missing path through the shared exit gate.

I built #44017 at d1b2306 and ran the three cases that this PR tests:

command without the flag with --pass-with-no-tests
bun test ./does-not-exist exit 1 exit 0
bun test ./does-not-exist ./also-missing exit 1 exit 0
bun test ./empty exit 1 exit 0

Each run names the path on stderr and runs no test. The exit codes are the same as with this PR. The message differs: #44017 prints one had no matches line for each argument and the naming hint.

The tests of #44017 already have these three rows, with and without the flag (every path argument unmatched in test/cli/test/bun-test.test.ts). They pass on that build. Nothing from this PR needs to move.

Main still has the bug: src/runtime/cli/test_command.rs:2047 exits before it reads the flag.

If #44017 does not land, reopen this PR. It is a four-line change against main and it does not depend on #43361.

@robobun robobun closed this Sep 27, 2026
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.

2 participants