diff options
author | 2023-05-23 22:33:32 -0700 | |
---|---|---|
committer | 2023-05-23 22:33:32 -0700 | |
commit | c3d402ce47e273b60e3a37164a6ba2be6e1eee5d (patch) | |
tree | 5e780162de9c723aba5126fd3276df51d9048c18 | |
parent | d9bdfcf1317f0ea14453cb2023daa07830d446d8 (diff) | |
download | bun-c3d402ce47e273b60e3a37164a6ba2be6e1eee5d.tar.gz bun-c3d402ce47e273b60e3a37164a6ba2be6e1eee5d.tar.zst bun-c3d402ce47e273b60e3a37164a6ba2be6e1eee5d.zip |
Implement `bun test --timeout` (#3040)
You can change the default per-test timeout in `bun test`:
> bun test --timeout 10
The default timeout is 5000.
-rw-r--r-- | src/bun.js/test/jest.zig | 9 | ||||
-rw-r--r-- | src/cli.zig | 10 | ||||
-rw-r--r-- | src/cli/test_command.zig | 1 | ||||
-rw-r--r-- | test/cli/test/bun-test.test.ts | 66 |
4 files changed, 80 insertions, 6 deletions
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 8b06caa0f..dcc7a8149 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -35,8 +35,6 @@ const getAllocator = @import("../base.zig").getAllocator; const JSPrivateDataPtr = @import("../base.zig").JSPrivateDataPtr; const GetJSPrivateData = @import("../base.zig").GetJSPrivateData; -const default_timeout = std.time.ms_per_min * 5; - const ZigString = JSC.ZigString; const JSInternalPromise = JSC.JSInternalPromise; const JSPromise = JSC.JSPromise; @@ -360,8 +358,6 @@ pub const TestRunner = struct { only: bool = false, last_file: u64 = 0, - timeout_seconds: f64 = 5.0, - allocator: std.mem.Allocator, callback: *Callback = undefined, @@ -376,6 +372,7 @@ pub const TestRunner = struct { snapshots: Snapshots, + default_timeout_ms: u32 = 0, test_timeout_timer: ?*bun.uws.Timer = null, last_test_timeout_timer_duration: u32 = 0, active_test_for_timeout: ?TestRunner.Test.ID = null, @@ -3243,7 +3240,7 @@ pub const TestScope = struct { skipped: bool = false, is_todo: bool = false, snapshot_count: usize = 0, - timeout_millis: u32 = default_timeout, + timeout_millis: u32 = 0, pub const Class = NewClass( void, @@ -3382,7 +3379,7 @@ pub const TestScope = struct { .label = label, .callback = function.asObjectRef(), .parent = DescribeScope.active, - .timeout_millis = if (arguments.len > 2) @intCast(u32, @max(args[2].coerce(i32, ctx), 0)) else default_timeout, + .timeout_millis = if (arguments.len > 2) @intCast(u32, @max(args[2].coerce(i32, ctx), 0)) else Jest.runner.?.default_timeout_ms, }) catch unreachable; if (test_elapsed_timer == null) create_tiemr: { diff --git a/src/cli.zig b/src/cli.zig index be8f9fe76..606e0a3cc 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -211,6 +211,7 @@ pub const Arguments = struct { // TODO: update test completions const test_only_params = [_]ParamType{ + clap.parseParam("--timeout <NUMBER> Set the per-test timeout in milliseconds, default is 5000.") catch unreachable, clap.parseParam("--update-snapshots Update snapshot files") catch unreachable, clap.parseParam("--rerun-each <NUMBER> Re-run each test file <NUMBER> times, helps catch certain bugs") catch unreachable, }; @@ -371,6 +372,14 @@ pub const Arguments = struct { } if (cmd == .TestCommand) { + if (args.option("--timeout")) |timeout_ms| { + if (timeout_ms.len > 0) { + ctx.test_options.default_timeout_ms = std.fmt.parseInt(u32, timeout_ms, 10) catch { + Output.prettyErrorln("<r><red>error<r>: Invalid timeout: \"{s}\"", .{timeout_ms}); + Global.exit(1); + }; + } + } ctx.test_options.update_snapshots = args.flag("--update-snapshots"); if (args.option("--rerun-each")) |repeat_count| { if (repeat_count.len > 0) { @@ -904,6 +913,7 @@ pub const Command = struct { }; pub const TestOptions = struct { + default_timeout_ms: u32 = 5 * std.time.ms_per_s, update_snapshots: bool = false, repeat_count: u32 = 0, }; diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig index 3fdce584a..cf5c4fc49 100644 --- a/src/cli/test_command.zig +++ b/src/cli/test_command.zig @@ -414,6 +414,7 @@ pub const TestCommand = struct { .allocator = ctx.allocator, .log = ctx.log, .callback = undefined, + .default_timeout_ms = ctx.test_options.default_timeout_ms, .snapshots = Snapshots{ .allocator = ctx.allocator, .update_snapshots = ctx.test_options.update_snapshots, diff --git a/test/cli/test/bun-test.test.ts b/test/cli/test/bun-test.test.ts new file mode 100644 index 000000000..e1a5fdd60 --- /dev/null +++ b/test/cli/test/bun-test.test.ts @@ -0,0 +1,66 @@ +import { join } from "node:path"; +import { tmpdir } from "node:os"; +import { mkdtempSync, writeFileSync, rmSync } from "node:fs"; +import { spawnSync } from "bun"; +import { describe, test, expect } from "bun:test"; +import { bunExe, bunEnv } from "harness"; + +describe("bun test", () => { + describe("--timeout", () => { + test("must provide a number timeout", () => { + const stderr = runTest({ + args: ["--timeout", "foo"], + }); + expect(stderr).toContain("Invalid timeout"); + }); + test("must provide non-negative timeout", () => { + const stderr = runTest({ + args: ["--timeout", "-1"], + }); + expect(stderr).toContain("Invalid timeout"); + }); + test("timeout can be set to 1ms", () => { + const stderr = runTest({ + args: ["--timeout", "1"], + code: ` + import { test, expect } from "bun:test"; + import { sleep } from "bun"; + test("timeout", async () => { + await sleep(2); + }); + `, + }); + expect(stderr).toContain("timed out after 1ms"); + }); + test("timeout should default to 5000ms", () => { + const stderr = runTest({ + code: ` + import { test, expect } from "bun:test"; + import { sleep } from "bun"; + test("timeout", async () => { + await sleep(5001); + }); + `, + }); + expect(stderr).toContain("timed out after 5000ms"); + }); + }); +}); + +function runTest({ code = "", args = [] }: { code?: string; args?: string[] }): string { + const dir = mkdtempSync(join(tmpdir(), "bun-test-")); + const path = join(dir, `bun-test-${Date.now()}.test.ts`); + writeFileSync(path, code); + try { + const { stderr } = spawnSync({ + cwd: dir, + cmd: [bunExe(), "test", path, ...args], + env: bunEnv, + stderr: "pipe", + stdout: "ignore", + }); + return stderr.toString(); + } finally { + rmSync(path); + } +} |