Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add jest.setTimeout to bun test #10687

Merged
merged 32 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a9879b4
timeout test
dylan-conway Apr 30, 2024
d0b329a
update
dylan-conway Apr 30, 2024
17749a7
Merge branch 'main' into dylan/timeout-test
dylan-conway Apr 30, 2024
ab898b9
more time
dylan-conway Apr 30, 2024
f305fb2
Merge branch 'dylan/timeout-test' of https://github.com/oven-sh/bun i…
dylan-conway Apr 30, 2024
78304f7
Merge branch 'main' into dylan/timeout-test
dylan-conway Apr 30, 2024
724851a
another setTimeout
dylan-conway Apr 30, 2024
0e35feb
update tests
dylan-conway Apr 30, 2024
da7bbaf
use timeout correctly
dylan-conway Apr 30, 2024
1a7cf96
test
dylan-conway Apr 30, 2024
626ce8b
test hoisting
dylan-conway May 1, 2024
5082ff2
better spot
dylan-conway May 1, 2024
459928c
Merge branch 'main' into dylan/timeout-test
dylan-conway May 1, 2024
5e65975
test
dylan-conway May 2, 2024
bbaba58
Merge branch 'main' into dylan/timeout-test
dylan-conway May 2, 2024
635c91c
fix merge
dylan-conway May 2, 2024
1095cc1
Revert "test"
dylan-conway May 3, 2024
b338588
test
dylan-conway May 3, 2024
0d021a8
oops
dylan-conway May 3, 2024
a4f8c9f
Merge branch 'main' into dylan/timeout-test
dylan-conway May 3, 2024
8834425
remove catch
dylan-conway May 3, 2024
3310891
Merge branch 'main' into dylan/timeout-test
dylan-conway May 22, 2024
51db976
Apply formatting changes
dylan-conway May 22, 2024
d7edfb1
cleanup
dylan-conway May 22, 2024
dbf8325
Merge branch 'main' into dylan/timeout-test
dylan-conway May 23, 2024
52fcc20
Merge branch 'main' into dylan/timeout-test
dylan-conway May 23, 2024
cf5fc73
types
dylan-conway May 23, 2024
a13385c
`setDefaultTimeout` and remove extra field
dylan-conway May 23, 2024
fb87f25
update tests
dylan-conway May 23, 2024
d94de15
`setDefaultTestTimeout`
dylan-conway May 23, 2024
22e2c44
setDefaultTImeout
dylan-conway May 24, 2024
b9809e4
update
dylan-conway May 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/bun-types/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,13 @@ declare module "bun:test" {
* @param fn the function to run
*/
export function afterEach(fn: (() => void | Promise<unknown>) | ((done: (err?: unknown) => void) => void)): void;
/**
* Sets the default timeout for all tests in the current file. If a test specifies a timeout, it will
* override this value. The default timeout is 5000ms (5 seconds).
*
* @param milliseconds the number of milliseconds for the default timeout
*/
export function setTimeout(milliseconds: number): void;
dylan-conway marked this conversation as resolved.
Show resolved Hide resolved
export interface TestOptions {
/**
* Sets the timeout for the test in milliseconds.
Expand Down
53 changes: 46 additions & 7 deletions src/bun.js/test/jest.zig
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ pub const TestRunner = struct {

snapshots: Snapshots,

default_timeout_ms: u32 = 0,
default_timeout_ms: u32,
default_timeout_override: ?u32 = null,

test_timeout_timer: ?*bun.uws.Timer = null,
last_test_timeout_timer_duration: u32 = 0,
active_test_for_timeout: ?TestRunner.Test.ID = null,
Expand Down Expand Up @@ -315,7 +317,7 @@ pub const Jest = struct {
else
.{ TestScope, DescribeScope };

const module = JSC.JSValue.createEmptyObject(globalObject, 13);
const module = JSC.JSValue.createEmptyObject(globalObject, 14);

const test_fn = JSC.NewFunction(globalObject, ZigString.static("test"), 2, ThisTestScope.call, false);
module.put(
Expand Down Expand Up @@ -423,6 +425,12 @@ pub const Jest = struct {
function.ensureStillAlive();
}

module.put(
globalObject,
ZigString.static("setTimeout"),
JSC.NewFunction(globalObject, ZigString.static("setTimeout"), 1, jsSetTimeout, false),
);

module.put(
globalObject,
ZigString.static("expect"),
Expand Down Expand Up @@ -535,6 +543,22 @@ pub const Jest = struct {
return Bun__Jest__testModuleObject(globalObject);
}

fn jsSetTimeout(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
const arguments = callframe.arguments(1).slice();
if (arguments.len < 1 or !arguments[0].isNumber()) {
globalObject.throw("setTimeout() expects a number (milliseconds)", .{});
return .zero;
}

const timeout_ms: u32 = @intCast(@max(arguments[0].coerce(i32, globalObject), 0));

if (Jest.runner) |test_runner| {
test_runner.default_timeout_override = timeout_ms;
}

return .undefined;
}

comptime {
if (!JSC.is_bindgen) {
@export(Bun__Jest__createTestModuleObject, .{ .name = "Bun__Jest__createTestModuleObject" });
Expand All @@ -557,7 +581,14 @@ pub const TestScope = struct {
task: ?*TestRunnerTask = null,
tag: Tag = .pass,
snapshot_count: usize = 0,
timeout_millis: u32 = 0,

// null if the test does not set a timeout
timeout_millis: ?u32 = null,

// Need this because the default timeout used for the test might
// be different from the default when it times out.
actual_timeout_millis: u32 = 0,

retry_count: u32 = 0, // retry, on fail
repeat_count: u32 = 0, // retry, on pass or fail

Expand Down Expand Up @@ -675,8 +706,12 @@ pub const TestScope = struct {
task.started_at = timer.started;
}

this.actual_timeout_millis = this.timeout_millis orelse
Jest.runner.?.default_timeout_override orelse
Jest.runner.?.default_timeout_ms;

Jest.runner.?.setTimeout(
this.timeout_millis,
this.actual_timeout_millis,
task.test_id,
);

Expand Down Expand Up @@ -1338,6 +1373,10 @@ pub const TestRunnerTask = struct {

var result = TestScope.run(&test_, this);

if (this.describe.tests.items.len > test_id) {
this.describe.tests.items[test_id].actual_timeout_millis = test_.actual_timeout_millis;
}

// rejected promises should fail the test
if (result != .fail)
globalThis.handleRejectedPromises();
Expand Down Expand Up @@ -1429,7 +1468,7 @@ pub const TestRunnerTask = struct {
describe.tests.items[test_id] = test_;

if (comptime from == .timeout) {
const err = this.globalThis.createErrorInstance("Test {} timed out after {d}ms", .{ bun.fmt.quote(test_.label), test_.timeout_millis });
const err = this.globalThis.createErrorInstance("Test {} timed out after {d}ms", .{ bun.fmt.quote(test_.label), test_.actual_timeout_millis });
_ = this.globalThis.bunVM().uncaughtException(this.globalThis, err, true);
}

Expand Down Expand Up @@ -1566,7 +1605,7 @@ inline fn createScope(
}
}

var timeout_ms: u32 = Jest.runner.?.default_timeout_ms;
var timeout_ms: ?u32 = null;
if (options.isNumber()) {
timeout_ms = @as(u32, @intCast(@max(args[2].coerce(i32, globalThis), 0)));
} else if (options.isObject()) {
Expand Down Expand Up @@ -1822,7 +1861,7 @@ fn eachBind(
return .zero;
}

var timeout_ms: u32 = Jest.runner.?.default_timeout_ms;
var timeout_ms: ?u32 = null;
if (options.isNumber()) {
timeout_ms = @as(u32, @intCast(@max(args[2].coerce(i32, globalThis), 0)));
} else if (options.isObject()) {
Expand Down
1 change: 1 addition & 0 deletions src/cli/add_command.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const Command = @import("../cli.zig").Command;
const PackageManager = @import("../install/install.zig").PackageManager;
const bun = @import("root").bun;

pub const AddCommand = struct {
pub fn exec(ctx: Command.Context) !void {
Expand Down
1 change: 1 addition & 0 deletions src/cli/test_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,7 @@ pub const TestCommand = struct {
if (files.len > 1) {
for (files[0 .. files.len - 1]) |file_name| {
TestCommand.run(reporter, vm, file_name.slice(), allocator, false) catch {};
reporter.jest.default_timeout_override = null;
Global.mimalloc_cleanup(false);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/install/lockfile.zig
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ pub const Tree = struct {
if (comptime as_defined) {
if (mismatch and dep.behavior.isDev() != dependency.behavior.isDev()) {
if (builder.prefer_dev_dependencies and dep.behavior.isDev()) {
return hoisted; // 2
return hoisted; // 1
}

return dependency_loop; // 3
Expand Down
6 changes: 5 additions & 1 deletion test/cli/install/bad-workspace.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { spawnSync } from "bun";
import { beforeEach, expect, test } from "bun:test";
import { beforeEach, expect, test, beforeAll, setTimeout as jestSetTimeout } from "bun:test";
import { writeFileSync } from "fs";
import { bunExe, bunEnv, tmpdirSync } from "harness";

let cwd: string;

beforeAll(() => {
jestSetTimeout(1000 * 60 * 5);
});

beforeEach(() => {
cwd = tmpdirSync();
});
Expand Down
3 changes: 2 additions & 1 deletion test/cli/install/bun-add.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { file, spawn } from "bun";
import { afterAll, afterEach, beforeAll, beforeEach, expect, it } from "bun:test";
import { afterAll, afterEach, beforeAll, beforeEach, expect, it, setTimeout as jestSetTimeout } from "bun:test";
import { bunExe, bunEnv as env, toHaveBins, toBeValidBin, toBeWorkspaceLink, tmpdirSync } from "harness";
import { access, mkdir, readlink, rm, writeFile, copyFile, appendFile } from "fs/promises";
import { join, relative } from "path";
Expand Down Expand Up @@ -28,6 +28,7 @@ expect.extend({
let port: string;
let add_dir: string;
beforeAll(() => {
jestSetTimeout(1000 * 60 * 5);
port = new URL(root_url).port;
});

Expand Down
41 changes: 29 additions & 12 deletions test/cli/install/bun-install.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { file, listen, Socket, spawn } from "bun";
import { afterAll, afterEach, beforeAll, beforeEach, expect, it, describe, test } from "bun:test";
import {
afterAll,
afterEach,
beforeAll,
beforeEach,
expect,
it,
describe,
test,
setTimeout as jestSetTimeout,
} from "bun:test";
import { bunExe, bunEnv as env, toBeValidBin, toHaveBins, toBeWorkspaceLink, tempDirWithFiles, bunEnv } from "harness";
import { access, mkdir, readlink as readlink, realpath, rm, writeFile } from "fs/promises";
import { join, sep } from "path";
Expand Down Expand Up @@ -39,7 +49,11 @@
},
});

beforeAll(dummyBeforeAll);
beforeAll(() => {
jestSetTimeout(1000 * 60 * 5);
dummyBeforeAll();
});

afterAll(dummyAfterAll);
beforeEach(dummyBeforeEach);
afterEach(dummyAfterEach);
Expand Down Expand Up @@ -966,6 +980,7 @@
"",
"2 packages installed",
]);
expect(await exited).toBe(0);
});

it("should handle installing the same peerDependency with the same version", async () => {
Expand Down Expand Up @@ -1003,6 +1018,8 @@
"",
"1 package installed",
]);

expect(await exited).toBe(0);
});

it("should handle life-cycle scripts within workspaces", async () => {
Expand Down Expand Up @@ -3371,7 +3388,7 @@
});

const err = await new Response(stderr).text();
expect(err).toContain("Saved lockfile");

Check failure on line 3391 in test/cli/install/bun-install.test.ts

View workflow job for this annotation

GitHub Actions / Test darwin-aarch64 / Tests

error: expect(received).toContain(expected)

Expected to contain: "Saved lockfile" Received: "bun add v1.1.10-canary.1 (5132e25e)\nResolving dependencies\n\nerror: InstallFailed cloning repository for bitbucket.org:dylan-conway/public-install-test\nResolved, downloaded and extracted [1]\nerror: \"git clone\" for \"bitbucket.org:dylan-conway/public-install-test\" failed\n\nerror: \"git clone\" for \"bitbucket.org:dylan-conway/public-install-test\" failed\n" at /opt/namespace/githubrunner/work/bun/bun/test/cli/install/bun-install.test.ts:3391:5
const out = await new Response(stdout).text();
expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([
"",
Expand All @@ -3384,7 +3401,7 @@
dummyAfterEach();
dummyBeforeEach();
}
}, 20000);
});

it("should handle gitlab git dependencies", async () => {
const deps = ["gitlab:dylan-conway/public-install-test", "gitlab.com:dylan-conway/public-install-test"];
Expand Down Expand Up @@ -3459,7 +3476,7 @@
dummyAfterEach();
dummyBeforeEach();
}
}, 10000);
});

it("should handle GitHub URL in dependencies (github:user/repo#tag)", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -3987,7 +4004,7 @@
join("..", "uglify-js", "bin", "uglifyjs"),
);
await access(join(package_dir, "bun.lockb"));
}, 20000);
});

it("should consider peerDependencies during hoisting", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -4431,7 +4448,7 @@
const package_json = await file(join(package_dir, "node_modules", "uglify-js", "package.json")).json();
expect(package_json.name).toBe("uglify-js");
await access(join(package_dir, "bun.lockb"));
}, 20000);
});

it("should handle Git URL in dependencies (SCP-style)", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -4489,7 +4506,7 @@
const package_json = await file(join(package_dir, "node_modules", "uglify", "package.json")).json();
expect(package_json.name).toBe("uglify-js");
await access(join(package_dir, "bun.lockb"));
}, 20000);
});

it("should handle Git URL with committish in dependencies", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -4549,7 +4566,7 @@
expect(package_json.name).toBe("uglify-js");
expect(package_json.version).toBe("3.14.1");
await access(join(package_dir, "bun.lockb"));
}, 20000);
});

it("should fail on invalid Git URL", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -4623,7 +4640,7 @@
} catch (err: any) {
expect(err.code).toBe("ENOENT");
}
}, 20000);
});

it("should de-duplicate committish in Git URLs", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -4709,7 +4726,7 @@
expect(ver_json.name).toBe("uglify-js");
expect(ver_json.version).toBe("3.14.1");
await access(join(package_dir, "bun.lockb"));
}, 20000);
});

it("should handle Git URL with existing lockfile", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -4913,7 +4930,7 @@
join("..", "uglify-js", "bin", "uglifyjs"),
);
await access(join(package_dir, "bun.lockb"));
}, 20000);
});

it("should prefer optionalDependencies over dependencies of the same name", async () => {
const urls: string[] = [];
Expand Down Expand Up @@ -6164,7 +6181,7 @@
expect(await readdirSorted(package_dir)).toEqual(["bun.lockb", "bunfig.toml", "node_modules", "package.json"]);
expect(await file(join(package_dir, "package.json")).text()).toEqual(foo_package);
expect(await readdirSorted(join(package_dir, "node_modules"))).toBeEmpty();
}, 20000);
});

it("should handle trustedDependencies", async () => {
function getScripts(name: string) {
Expand Down
6 changes: 5 additions & 1 deletion test/cli/install/bun-upgrade.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { spawn, spawnSync } from "bun";
import { beforeEach, expect, it } from "bun:test";
import { beforeEach, expect, it, setTimeout as jestSetTimeout, beforeAll } from "bun:test";
import { bunExe, bunEnv as env, tls, tmpdirSync } from "harness";
import { join } from "path";
import { copyFileSync } from "js/node/fs/export-star-from";
Expand All @@ -9,6 +9,10 @@ const { openTempDirWithoutSharingDelete, closeTempDirHandle } = upgrade_test_hel
let run_dir: string;
let exe_name: string = "bun-debug" + (process.platform === "win32" ? ".exe" : "");

beforeAll(() => {
jestSetTimeout(1000 * 60 * 5);
});

beforeEach(async () => {
run_dir = tmpdirSync();
copyFileSync(bunExe(), join(run_dir, exe_name));
Expand Down
6 changes: 5 additions & 1 deletion test/cli/install/bunx.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { spawn } from "bun";
import { afterEach, beforeEach, expect, it } from "bun:test";
import { beforeEach, expect, it, beforeAll, setTimeout as jestSetTimeout } from "bun:test";
import { bunExe, bunEnv, isWindows, tmpdirSync } from "harness";
import { writeFile, rm } from "fs/promises";
import { tmpdir } from "os";
Expand All @@ -12,6 +12,10 @@ let current_tmpdir: string;
let install_cache_dir: string;
let env = { ...bunEnv };

beforeAll(() => {
jestSetTimeout(1000 * 60 * 5);
});

beforeEach(async () => {
const waiting: Promise<void>[] = [];
if (current_tmpdir) {
Expand Down
5 changes: 3 additions & 2 deletions test/cli/install/migration/complex-workspace.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fs from "fs";
import path from "path";
import { test, expect, describe, beforeAll } from "bun:test";
import { test, expect, beforeAll, setTimeout as jestSetTimeout } from "bun:test";
import { bunEnv, bunExe, tmpdirSync } from "harness";

let cwd = tmpdirSync();
Expand Down Expand Up @@ -35,6 +35,7 @@ function mustNotExist(filePath: string) {
}

beforeAll(() => {
jestSetTimeout(1000 * 60 * 5);
fs.cpSync(path.join(import.meta.dir, "complex-workspace"), cwd, { recursive: true });
});

Expand All @@ -61,7 +62,7 @@ test("the install succeeds", async () => {
cwd = false as any;
throw new Error("Failed to install");
}
}, 10000);
});

// bun-types
validate("node_modules/bun-types", "1.0.0");
Expand Down