Compare commits

...

2 Commits

Author SHA1 Message Date
pfg
b3a85ce01d Merge branch 'main' into claude/fix-snapshot-rerun-each-23705 2025-10-30 14:52:04 -07:00
Claude Bot
bacc77cdf7 Fix snapshot keys being inconsistent with --rerun-each
When using --rerun-each, snapshot counters were not being reset between
test reruns. This caused the second run to generate snapshot keys like
"test name 2" instead of reusing "test name 1", triggering CI errors
when snapshot creation is blocked.

The fix unconditionally calls writeSnapshotFile() after each test file
execution, which writes the snapshot file, closes it, clears all state
(including counts), and sets _current_file to null. This ensures the
next rerun starts fresh and generates consistent snapshot keys.

This also simplifies getSnapshotFile() by removing the file_id check
(no longer needed since _current_file is always null when entering that
branch) and the redundant writeSnapshotFile() call (which would be a
no-op since _current_file is null).

Fixes #23705

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 00:01:34 +00:00
3 changed files with 106 additions and 3 deletions

View File

@@ -207,6 +207,8 @@ pub const Snapshots = struct {
this.allocator.free(key.*);
}
this.counts.clearAndFree();
this._current_file = null;
}
}
@@ -482,9 +484,7 @@ pub const Snapshots = struct {
}
fn getSnapshotFile(this: *Snapshots, file_id: TestRunner.File.ID) !bun.sys.Maybe(void) {
if (this._current_file == null or this._current_file.?.id != file_id) {
try this.writeSnapshotFile();
if (this._current_file == null) {
const test_file = Jest.runner.?.files.get(file_id);
const test_filename = test_file.source.path.name.filename;
const dir_path = test_file.source.path.name.dirWithTrailingSlash();

View File

@@ -1969,6 +1969,9 @@ pub const TestCommand = struct {
// Ensure these never linger across files.
vm.auto_killer.clear();
vm.auto_killer.disable();
// Write and reset snapshot state after each test run for --rerun-each consistency
try reporter.jest.snapshots.writeSnapshotFile();
}
}
};

View File

@@ -0,0 +1,100 @@
// https://github.com/oven-sh/bun/issues/23705
// Snapshots should use the same key on each rerun when --rerun-each is used
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";
import { join } from "path";
test("snapshots should use consistent keys with --rerun-each", async () => {
using dir = tempDir("issue-23705", {
"snapshot.test.ts": `
import { test, expect } from "bun:test";
test("simple snapshot test", () => {
expect("hello world").toMatchInlineSnapshot();
});
`,
});
// First run: create the snapshot (disable CI to allow snapshot creation)
await using proc1 = Bun.spawn({
cmd: [bunExe(), "test", "snapshot.test.ts", "--update-snapshots"],
env: { ...bunEnv, CI: "false" },
cwd: String(dir),
stderr: "pipe",
stdout: "pipe",
});
const [stdout1, stderr1, exitCode1] = await Promise.all([proc1.stdout.text(), proc1.stderr.text(), proc1.exited]);
expect(exitCode1).toBe(0);
// Second run: verify with --rerun-each=2 in CI mode
await using proc2 = Bun.spawn({
cmd: [bunExe(), "test", "snapshot.test.ts", "--rerun-each=2"],
env: { ...bunEnv, CI: "true", GITHUB_ACTIONS: "true" },
cwd: String(dir),
stderr: "pipe",
stdout: "pipe",
});
const [stdout2, stderr2, exitCode2] = await Promise.all([proc2.stdout.text(), proc2.stderr.text(), proc2.exited]);
// Should pass both runs
expect(exitCode2).toBe(0);
// Should not try to create new snapshots
const combined = stdout2 + stderr2;
expect(combined).not.toContain("Snapshot creation is not allowed in CI");
expect(combined).not.toContain("error");
expect(combined).toMatch(/2 pass/);
});
test("file snapshots should use consistent keys with --rerun-each", async () => {
using dir = tempDir("issue-23705-file", {
"file-snapshot.test.ts": `
import { test, expect } from "bun:test";
test("snapshot to file", () => {
expect({ foo: "bar", baz: 42 }).toMatchSnapshot();
});
`,
});
// First run: create the snapshot file (disable CI to allow snapshot creation)
await using proc1 = Bun.spawn({
cmd: [bunExe(), "test", "file-snapshot.test.ts", "--update-snapshots"],
env: { ...bunEnv, CI: "false" },
cwd: String(dir),
stderr: "pipe",
stdout: "pipe",
});
const [stdout1, stderr1, exitCode1] = await Promise.all([proc1.stdout.text(), proc1.stderr.text(), proc1.exited]);
expect(exitCode1).toBe(0);
// Verify snapshot file was created
const snapshotFile = join(String(dir), "__snapshots__", "file-snapshot.test.ts.snap");
const snapshotExists = await Bun.file(snapshotFile).exists();
expect(snapshotExists).toBe(true);
// Second run: verify with --rerun-each=2 in CI mode
await using proc2 = Bun.spawn({
cmd: [bunExe(), "test", "file-snapshot.test.ts", "--rerun-each=2"],
env: { ...bunEnv, CI: "true", GITHUB_ACTIONS: "true" },
cwd: String(dir),
stderr: "pipe",
stdout: "pipe",
});
const [stdout2, stderr2, exitCode2] = await Promise.all([proc2.stdout.text(), proc2.stderr.text(), proc2.exited]);
// Should pass both runs
expect(exitCode2).toBe(0);
// Should not try to create new snapshots
const combined = stdout2 + stderr2;
expect(combined).not.toContain("Snapshot creation is not allowed in CI");
expect(combined).not.toContain("error");
expect(combined).toMatch(/2 pass/);
});