Compare commits

...

8 Commits

Author SHA1 Message Date
Claude Bot
41baa507d6 Use decl literals and string names in createTestFlags
Simplify createTestFlags by using:
- Decl literals for JSValue construction (.jsNumber, .jsBoolean)
- Plain string literals for property names instead of ZigString.static

This makes the code more concise and readable.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 03:02:18 +00:00
Claude Bot
009ca5a86e Pass test_runner as parameter to createTestFlags
Refactor createTestFlags to accept test_runner as a parameter instead
of accessing Jest.runner directly. This makes the function dependency
more explicit and easier to understand.

Changes:
- createTestFlags now takes test_runner: *TestRunner parameter
- Simplified defaultTimeout logic by removing Jest.runner check
- Simplified randomize/seed logic by using test_runner directly
- Updated createTestModule to pass test_runner to createTestFlags

No functional changes, just cleaner code structure.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 02:52:54 +00:00
Claude Bot
4a9c3eb4bf Use resolved seed and randomize values in testFlags
The testFlags object now exposes the actual resolved values for
randomize and seed, rather than just the CLI options.

When --randomize is used without an explicit --seed, Bun generates
a random seed internally. This change ensures testFlags.seed contains
that generated seed value, so users can see which seed was actually
used for their test run.

Changes:
- Added seed field to TestRunner struct to store resolved seed
- Pass the resolved seed when creating TestRunner
- Update createTestFlags to use TestRunner.randomize and TestRunner.seed
  for the actual runtime values
- Added tests to verify seed is resolved correctly with --randomize

This makes testFlags.seed useful for reproducing test runs when using
--randomize without an explicit seed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 02:45:00 +00:00
Claude Bot
8fb8461f66 Expose test flags via testFlags object on bun:test import
Changed the implementation from adding test flags to process.argv to
exposing them as a testFlags object on the bun:test import. This
provides a cleaner API and better type safety.

The testFlags object includes:
- defaultTimeout: number - current default timeout in ms
- updateSnapshots: boolean - whether snapshot updates are enabled
- rerunEach?: number - number of times to rerun each test
- runTodo: boolean - whether to run todo tests
- only: boolean - whether to run only .only tests
- passWithNoTests: boolean - whether to pass when no tests found
- concurrent: boolean - whether tests run concurrently
- randomize: boolean - whether to randomize test order
- seed?: number - random seed for test order
- bail?: number - number of failures before stopping
- testFilterPattern?: string - pattern to filter tests
- maxConcurrency: number - max concurrent tests

Updated tests to use testFlags from bun:test instead of checking
process.argv for test flags.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 02:34:53 +00:00
Claude Bot
c3122383ec Merge remote-tracking branch 'origin/main' into claude/test-flags-in-process-argv 2025-10-16 02:13:01 +00:00
pfg
ca17a2e764 Merge branch 'main' into claude/test-flags-in-process-argv 2025-10-14 14:19:58 -07:00
Claude Bot
f35505fa2e Update tests to expect normalized --update-snapshots flag
Since the implementation normalizes `-u` to `--update-snapshots`,
the tests now:
- Explicitly check for `--update-snapshots` in process.argv
- Verify that `-u` is NOT present (it gets normalized)
- Remove console.log statements that were used for debugging

This makes the test expectations more precise and documents the
normalization behavior.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-10 01:15:47 +00:00
Claude Bot
7285f2962f Include test flags in process.argv when running bun test
When running `bun test` with flags like `--update-snapshots` or `-u`,
these flags are now included in `process.argv` so they can be accessed
by tests and test utilities.

Previously, test runner flags were consumed by the argument parser and
not passed through to the test process's argv array, making it
impossible for tests to check if certain flags were enabled.

This change builds an argv array that includes the parsed test flags
before passing it to the VM, ensuring flags like --update-snapshots,
--only, --todo, --concurrent, and --randomize are visible to test code.

Fixes the issue where test utilities couldn't detect if snapshot
updates were requested via CLI flags.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-10 01:05:17 +00:00
3 changed files with 410 additions and 0 deletions

View File

@@ -69,6 +69,7 @@ pub const TestRunner = struct {
run_todo: bool = false,
concurrent: bool = false,
randomize: ?std.Random = null,
seed: u32 = 0,
concurrent_test_glob: ?[]const []const u8 = null,
last_file: u64 = 0,
bail: u32 = 0,
@@ -162,6 +163,69 @@ pub const Jest = struct {
return createTestModule(globalObject) catch return .zero;
}
fn createTestFlags(globalObject: *JSGlobalObject, test_runner: *TestRunner) JSValue {
const test_options = test_runner.test_options;
const flags = JSValue.createEmptyObject(globalObject, 11);
// defaultTimeout
const timeout = if (test_runner.default_timeout_override != std.math.maxInt(u32))
test_runner.default_timeout_override
else
test_options.default_timeout_ms;
flags.put(globalObject, "defaultTimeout", .jsNumber(timeout));
// updateSnapshots
flags.put(globalObject, "updateSnapshots", .jsBoolean(test_options.update_snapshots));
// rerunEach
if (test_options.repeat_count > 0) {
flags.put(globalObject, "rerunEach", .jsNumber(test_options.repeat_count));
} else {
flags.put(globalObject, "rerunEach", .js_undefined);
}
// runTodo
flags.put(globalObject, "runTodo", .jsBoolean(test_options.run_todo));
// only
flags.put(globalObject, "only", .jsBoolean(test_options.only));
// passWithNoTests
flags.put(globalObject, "passWithNoTests", .jsBoolean(test_options.pass_with_no_tests));
// concurrent
flags.put(globalObject, "concurrent", .jsBoolean(test_options.concurrent));
// randomize and seed - use resolved values from TestRunner
flags.put(globalObject, "randomize", .jsBoolean(test_runner.randomize != null));
if (test_runner.randomize != null) {
flags.put(globalObject, "seed", .jsNumber(test_runner.seed));
} else {
flags.put(globalObject, "seed", .js_undefined);
}
// bail
if (test_options.bail > 0) {
flags.put(globalObject, "bail", .jsNumber(test_options.bail));
} else {
flags.put(globalObject, "bail", .js_undefined);
}
// testFilterPattern
if (test_options.test_filter_pattern) |filter| {
const filter_str = bun.String.fromBytes(filter);
defer filter_str.deref();
flags.put(globalObject, "testFilterPattern", filter_str.toJS(globalObject));
} else {
flags.put(globalObject, "testFilterPattern", .js_undefined);
}
// maxConcurrency
flags.put(globalObject, "maxConcurrency", .jsNumber(test_options.max_concurrency));
return flags;
}
pub fn createTestModule(globalObject: *JSGlobalObject) bun.JSError!JSValue {
const module = JSValue.createEmptyObject(globalObject, 19);
@@ -189,6 +253,12 @@ pub const Jest = struct {
createMockObjects(globalObject, module);
// Add testFlags object
if (Jest.runner) |test_runner| {
const test_flags = createTestFlags(globalObject, test_runner);
module.put(globalObject, ZigString.static("testFlags"), test_flags);
}
return module;
}

View File

@@ -1335,6 +1335,7 @@ pub const TestCommand = struct {
.default_timeout_ms = ctx.test_options.default_timeout_ms,
.concurrent = ctx.test_options.concurrent,
.randomize = random,
.seed = seed,
.concurrent_test_glob = ctx.test_options.concurrent_test_glob,
.run_todo = ctx.test_options.run_todo,
.only = ctx.test_options.only,

View File

@@ -0,0 +1,339 @@
// Test that test runner flags are available via testFlags from bun:test
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";
test("testFlags.updateSnapshots is true when --update-snapshots is passed", async () => {
using dir = tempDir("test-flags-update-snapshots", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.updateSnapshots).toBe(true);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--update-snapshots"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags.updateSnapshots is true when -u is passed", async () => {
using dir = tempDir("test-flags-u-flag", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.updateSnapshots).toBe(true);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "-u"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags.updateSnapshots is false when not passed", async () => {
using dir = tempDir("test-flags-no-update", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.updateSnapshots).toBe(false);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags.only is true when --only is passed", async () => {
using dir = tempDir("test-flags-only", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.only).toBe(true);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--only"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags.runTodo is true when --todo is passed", async () => {
using dir = tempDir("test-flags-todo", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.runTodo).toBe(true);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--todo"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags has multiple boolean flags", async () => {
using dir = tempDir("test-flags-multiple", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.concurrent).toBe(true);
expect(testFlags.randomize).toBe(true);
expect(testFlags.only).toBe(false);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--concurrent", "--randomize"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags.bail is set when --bail is passed", async () => {
using dir = tempDir("test-flags-bail", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.bail).toBe(5);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--bail=5"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags.rerunEach is set when --rerun-each is passed", async () => {
using dir = tempDir("test-flags-rerun-each", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags", () => {
expect(testFlags.rerunEach).toBe(3);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--rerun-each=3"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags.testFilterPattern is set when --test-name-pattern is passed", async () => {
using dir = tempDir("test-flags-pattern", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags for mypattern", () => {
expect(testFlags.testFilterPattern).toBe("mypattern");
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--test-name-pattern", "mypattern"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
if (exitCode !== 0) {
console.log("stdout:", stdout);
console.log("stderr:", stderr);
}
expect(exitCode).toBe(0);
});
test("testFlags.randomize is true and seed is set when --randomize is passed", async () => {
using dir = tempDir("test-flags-randomize", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check randomize and seed", () => {
expect(testFlags.randomize).toBe(true);
expect(typeof testFlags.seed).toBe("number");
expect(testFlags.seed).toBeGreaterThan(0);
console.log("Resolved seed:", testFlags.seed);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--randomize"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
expect(stdout).toMatch(/Resolved seed: \d+/);
});
test("testFlags.seed is the specified value when --seed is passed", async () => {
using dir = tempDir("test-flags-explicit-seed", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check explicit seed", () => {
expect(testFlags.randomize).toBe(true);
expect(testFlags.seed).toBe(12345);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test", "--randomize", "--seed", "12345"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});
test("testFlags has all expected properties", async () => {
using dir = tempDir("test-flags-properties", {
"test.test.ts": `
import { test, expect, testFlags } from "bun:test";
test("check testFlags has all properties", () => {
expect(typeof testFlags.defaultTimeout).toBe("number");
expect(typeof testFlags.updateSnapshots).toBe("boolean");
expect(typeof testFlags.runTodo).toBe("boolean");
expect(typeof testFlags.only).toBe("boolean");
expect(typeof testFlags.passWithNoTests).toBe("boolean");
expect(typeof testFlags.concurrent).toBe("boolean");
expect(typeof testFlags.randomize).toBe("boolean");
expect(typeof testFlags.maxConcurrency).toBe("number");
// These can be undefined
expect(testFlags.rerunEach === undefined || typeof testFlags.rerunEach === "number").toBe(true);
expect(testFlags.seed === undefined || typeof testFlags.seed === "number").toBe(true);
expect(testFlags.bail === undefined || typeof testFlags.bail === "number").toBe(true);
expect(testFlags.testFilterPattern === undefined || typeof testFlags.testFilterPattern === "string").toBe(true);
});
`,
});
const result = await Bun.spawn({
cmd: [bunExe(), "test"],
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
const exitCode = await result.exited;
const stdout = await result.stdout.text();
const stderr = await result.stderr.text();
expect(exitCode).toBe(0);
});