mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
Rereun-each fix (#23168)
### What does this PR do? Fix --rerun-each. Fixes #21409 ### How did you verify your code works? Test case --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1828,6 +1828,13 @@ pub const TestCommand = struct {
|
||||
vm.onUnhandledRejection = jest.on_unhandled_rejection.onUnhandledRejection;
|
||||
|
||||
while (repeat_index < repeat_count) : (repeat_index += 1) {
|
||||
// Clear the module cache before re-running (except for the first run)
|
||||
if (repeat_index > 0) {
|
||||
try vm.clearEntryPoint();
|
||||
var entry = jsc.ZigString.init(file_path);
|
||||
try vm.global.deleteModuleRegistryEntry(&entry);
|
||||
}
|
||||
|
||||
var bun_test_root = &jest.Jest.runner.?.bun_test_root;
|
||||
// Determine if this file should run tests concurrently based on glob pattern
|
||||
const should_run_concurrent = reporter.jest.shouldFileRunConcurrently(file_id);
|
||||
@@ -1838,7 +1845,10 @@ pub const TestCommand = struct {
|
||||
|
||||
bun.jsc.Jest.bun_test.debug.group.log("loadEntryPointForTestRunner(\"{}\")", .{std.zig.fmtEscapes(file_path)});
|
||||
var promise = try vm.loadEntryPointForTestRunner(file_path);
|
||||
reporter.summary().files += 1;
|
||||
// Only count the file once, not once per repeat
|
||||
if (repeat_index == 0) {
|
||||
reporter.summary().files += 1;
|
||||
}
|
||||
|
||||
switch (promise.status(vm.global.vm())) {
|
||||
.rejected => {
|
||||
@@ -1905,11 +1915,6 @@ pub const TestCommand = struct {
|
||||
}
|
||||
|
||||
vm.global.handleRejectedPromises();
|
||||
if (repeat_index > 0) {
|
||||
try vm.clearEntryPoint();
|
||||
var entry = jsc.ZigString.init(file_path);
|
||||
try vm.global.deleteModuleRegistryEntry(&entry);
|
||||
}
|
||||
|
||||
if (Output.is_github_action) {
|
||||
Output.prettyErrorln("<r>\n::endgroup::\n", .{});
|
||||
|
||||
132
test/cli/test/rerun-each.test.ts
Normal file
132
test/cli/test/rerun-each.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, tempDir } from "harness";
|
||||
|
||||
test("--rerun-each should run tests exactly N times", async () => {
|
||||
using dir = tempDir("test-rerun-each", {
|
||||
"counter.test.ts": `
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
// Use a global counter that persists across module reloads
|
||||
if (!globalThis.testRunCounter) {
|
||||
globalThis.testRunCounter = 0;
|
||||
}
|
||||
|
||||
test("should increment counter", () => {
|
||||
globalThis.testRunCounter++;
|
||||
console.log(\`Run #\${globalThis.testRunCounter}\`);
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
`,
|
||||
});
|
||||
|
||||
// Test with --rerun-each=3
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "test", "counter.test.ts", "--rerun-each=3"],
|
||||
env: bunEnv,
|
||||
cwd: String(dir),
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Should see "Run #1", "Run #2", "Run #3" in the output
|
||||
expect(stdout).toContain("Run #1");
|
||||
expect(stdout).toContain("Run #2");
|
||||
expect(stdout).toContain("Run #3");
|
||||
|
||||
// Should NOT see "Run #4"
|
||||
expect(stdout).not.toContain("Run #4");
|
||||
|
||||
// Should run exactly 3 tests - check stderr for test summary
|
||||
const combined = stdout + stderr;
|
||||
expect(combined).toMatch(/3 pass/);
|
||||
|
||||
// Test with --rerun-each=1 (should run once)
|
||||
await using proc2 = Bun.spawn({
|
||||
cmd: [bunExe(), "test", "counter.test.ts", "--rerun-each=1"],
|
||||
env: bunEnv,
|
||||
cwd: String(dir),
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const [stdout2, stderr2, exitCode2] = await Promise.all([proc2.stdout.text(), proc2.stderr.text(), proc2.exited]);
|
||||
|
||||
expect(exitCode2).toBe(0);
|
||||
const combined2 = stdout2 + stderr2;
|
||||
expect(combined2).toMatch(/1 pass/);
|
||||
});
|
||||
|
||||
test("--rerun-each should report correct file count", async () => {
|
||||
using dir = tempDir("test-rerun-each-file-count", {
|
||||
"test1.test.ts": `
|
||||
import { test, expect } from "bun:test";
|
||||
test("test in file 1", () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
`,
|
||||
});
|
||||
|
||||
// Run with --rerun-each=3
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "test", "test1.test.ts", "--rerun-each=3"],
|
||||
env: bunEnv,
|
||||
cwd: String(dir),
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Should report "Ran 3 tests across 1 file" not "across 3 files"
|
||||
const combined = stdout + stderr;
|
||||
expect(combined).toContain("Ran 3 tests across 1 file");
|
||||
expect(combined).not.toContain("across 3 files");
|
||||
});
|
||||
|
||||
test("--rerun-each should handle test failures correctly", async () => {
|
||||
using dir = tempDir("test-rerun-each-fail", {
|
||||
"fail.test.ts": `
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
if (!globalThis.failCounter) {
|
||||
globalThis.failCounter = 0;
|
||||
}
|
||||
|
||||
test("fails on second run", () => {
|
||||
globalThis.failCounter++;
|
||||
console.log(\`Attempt #\${globalThis.failCounter}\`);
|
||||
// Fail on the second run
|
||||
expect(globalThis.failCounter).not.toBe(2);
|
||||
});
|
||||
`,
|
||||
});
|
||||
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "test", "fail.test.ts", "--rerun-each=3"],
|
||||
env: bunEnv,
|
||||
cwd: String(dir),
|
||||
stderr: "pipe",
|
||||
stdout: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
// Should have non-zero exit code due to failure
|
||||
expect(exitCode).not.toBe(0);
|
||||
|
||||
// Should see all three attempts
|
||||
expect(stdout).toContain("Attempt #1");
|
||||
expect(stdout).toContain("Attempt #2");
|
||||
expect(stdout).toContain("Attempt #3");
|
||||
|
||||
// Should report 2 passes and 1 failure - check both stdout and stderr
|
||||
const combined = stdout + stderr;
|
||||
expect(combined).toMatch(/2 pass/);
|
||||
expect(combined).toMatch(/1 fail/);
|
||||
});
|
||||
Reference in New Issue
Block a user