Skip to content

Commit

Permalink
feat: support default test timeout in bunfig.toml
Browse files Browse the repository at this point in the history
  • Loading branch information
treyturner committed Sep 27, 2024
1 parent 05afe42 commit 2b4c342
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 7 deletions.
9 changes: 9 additions & 0 deletions docs/runtime/bunfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@ Same as the top-level `smol` field, but only applies to `bun test`.
smol = true
```

### `test.timeout`

A default timeout for each test in milliseconds. Default `5000`. Use `--timeout` to override.

```toml
[test]
timeout = 15000
```

### `test.coverage`

Enables coverage reporting. Default `false`. Use `--coverage` to override.
Expand Down
5 changes: 5 additions & 0 deletions src/bunfig.zig
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ pub const Bunfig = struct {
this.ctx.runtime_options.smol = expr.data.e_boolean.value;
}

if (test_.get("timeout")) |expr| {
try this.expect(expr, .e_number);
this.ctx.test_options.default_timeout_ms = expr.data.e_number.toU32();
}

if (test_.get("coverage")) |expr| {
try this.expect(expr, .e_boolean);
this.ctx.test_options.coverage.enabled = expr.data.e_boolean.value;
Expand Down
14 changes: 7 additions & 7 deletions src/cli.zig
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,13 @@ pub const Arguments = struct {
ctx.filters = args.options("--filter");
}

ctx.args.absolute_working_dir = cwd;
ctx.positionals = args.positionals();

if (comptime Command.Tag.loads_config.get(cmd)) {
try loadConfigWithCmdArgs(cmd, allocator, args, ctx);
}

if (cmd == .TestCommand) {
if (args.option("--timeout")) |timeout_ms| {
if (timeout_ms.len > 0) {
Expand Down Expand Up @@ -527,13 +534,6 @@ pub const Arguments = struct {
ctx.test_options.only = args.flag("--only");
}

ctx.args.absolute_working_dir = cwd;
ctx.positionals = args.positionals();

if (comptime Command.Tag.loads_config.get(cmd)) {
try loadConfigWithCmdArgs(cmd, allocator, args, ctx);
}

var opts: Api.TransformOptions = ctx.args;

const defines_tuple = try DefineColonList.resolve(allocator, args.options("--define"));
Expand Down
80 changes: 80 additions & 0 deletions test/cli/test/bun-test-bunfig.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { spawnSync } from "bun";
import { afterEach, describe, expect, test } from "bun:test";
import { bunEnv, bunExe, tempDirWithFiles } from "harness";
import { rmSync } from "node:fs";

describe("bunfig test options", () => {
describe("timeout", () => {
const getBunfigWithTimeout = (ms: number) => `[test]\ntimeout = ${ms}\n`;

const getTestWithDuration = (ms: number) => {
return `
import { test } from "bun:test";
test(\`takes ${ms} ms\`, async () => await Bun.sleep(${ms}));
`;
};

const errorPtn = /timed out after (\d+)ms/;
const durationPtn = /\(fail\) .* \[(\d+)(?:\.\d+)?ms\]/;
let cwd: string;

afterEach(() => {
if (cwd) rmSync(cwd, { recursive: true });
});

test("bunfig timeout overrides default", () => {
const bunfigTimeout = 500;
cwd = tempDirWithFiles("test.bunfig.timeout", {
"bunfig.toml": getBunfigWithTimeout(bunfigTimeout),
"bun-test-bunfig-timeout.test.ts": getTestWithDuration(2000),
});

const result = spawnSync({
cmd: [bunExe(), "-c=bunfig.toml", "test"],
env: bunEnv,
stderr: "pipe",
cwd,
});
const stderr = result.stderr.toString().trim();

const errorMatch = stderr.match(errorPtn);
expect(errorMatch, "test didn't report timeout error to stderr").not.toBeNull();
const errorTimeout = parseInt(errorMatch!.at(1)!);
expect(errorTimeout, "test timeout error doesn't reflect bunfig value").toEqual(bunfigTimeout);

const durationMatch = stderr.match(durationPtn);
expect(durationMatch, "test didn't output failing result with actual duration to stderr").not.toBeNull();
const duration = parseInt(durationMatch!.at(1)!);
expect(duration, "test timed out before bunfig timeout value").toBeGreaterThanOrEqual(bunfigTimeout);
expect(duration, "test didn't honor bunfig timeout value").toBeLessThanOrEqual(5000);
});

test("cli timeout overrides bunfig", () => {
const cliTimeout = 500;
const bunfigTimeout = 1000;
cwd = tempDirWithFiles("test.cli.timeout.wins", {
"bunfig.toml": getBunfigWithTimeout(bunfigTimeout),
"bun-test-cli-timeout-wins.test.ts": getTestWithDuration(2000),
});

const result = spawnSync({
cmd: [bunExe(), "-c=bunfig.toml", "test", "--timeout", `${cliTimeout}`],
env: bunEnv,
stderr: "pipe",
cwd,
});
const stderr = result.stderr.toString().trim();

const errorMatch = stderr.match(errorPtn);
expect(errorMatch, "test didn't report timeout error to stderr").not.toBeNull();
const errorTimeout = parseInt(errorMatch!.at(1)!);
expect(errorTimeout, "test timeout error doesn't reflect cli value").toEqual(cliTimeout);

const durationMatch = stderr.match(durationPtn);
expect(durationMatch, "test didn't output failing result with actual duration to stderr").not.toBeNull();
const duration = parseInt(durationMatch!.at(1)!);
expect(duration, "test timed out before cli value").toBeGreaterThanOrEqual(cliTimeout);
expect(duration, "test honored bunfig timeout instead of cli").toBeLessThan(bunfigTimeout);
});
});
});

0 comments on commit 2b4c342

Please sign in to comment.