diff options
author | 2023-06-29 08:30:21 -0700 | |
---|---|---|
committer | 2023-06-29 08:30:21 -0700 | |
commit | 853e3771595fd46bb09641c8dbdab738843a45cd (patch) | |
tree | fcebd6bed03ace8f66a9d557a90deaac0393885d | |
parent | 8984c819613b52b3cfaf1cd22fc059d0150eedfc (diff) | |
download | bun-853e3771595fd46bb09641c8dbdab738843a45cd.tar.gz bun-853e3771595fd46bb09641c8dbdab738843a45cd.tar.zst bun-853e3771595fd46bb09641c8dbdab738843a45cd.zip |
Revert "[jest] fix lifecycle hook execution order (#3447)" (#3455)
This reverts commit 182e8aa1392af9ba92beccce06f49f8e4593fe5c.
-rw-r--r-- | src/bun.js/test/jest.zig | 162 | ||||
-rw-r--r-- | test/js/bun/test/jest-hooks.test.ts | 31 | ||||
-rw-r--r-- | test/js/bun/test/test-test.test.ts | 6 |
3 files changed, 69 insertions, 130 deletions
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 5ae2337f9..d53194e00 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -493,7 +493,8 @@ pub const Jest = struct { var filepath = Fs.FileSystem.instance.filename_store.append([]const u8, slice) catch unreachable; var scope = runner_.getOrPutFile(filepath); - scope.push(); + DescribeScope.active = scope; + DescribeScope.module = scope; return Bun__Jest__testModuleObject(ctx).asObjectRef(); } @@ -750,16 +751,17 @@ pub const DescribeScope = struct { } pub fn push(new: *DescribeScope) void { - if (comptime is_bindgen) return; - std.debug.assert(DescribeScope.active != new); - if (new.parent) |scope| std.debug.assert(scope == DescribeScope.active); + if (comptime is_bindgen) return undefined; + if (new == DescribeScope.active) return; + + new.parent = DescribeScope.active; DescribeScope.active = new; } pub fn pop(this: *DescribeScope) void { - if (comptime is_bindgen) return; - std.debug.assert(DescribeScope.active == this); - DescribeScope.active = this.parent; + if (comptime is_bindgen) return undefined; + if (DescribeScope.active == this) + DescribeScope.active = this.parent orelse DescribeScope.active; } pub const LifecycleHook = enum { @@ -769,7 +771,8 @@ pub const DescribeScope = struct { afterAll, }; - pub threadlocal var active: ?*DescribeScope = null; + pub threadlocal var active: *DescribeScope = undefined; + pub threadlocal var module: *DescribeScope = undefined; const CallbackFn = *const fn ( *JSC.JSGlobalObject, @@ -778,24 +781,21 @@ pub const DescribeScope = struct { fn createCallback(comptime hook: LifecycleHook) CallbackFn { return struct { + const this_hook = hook; pub fn run( globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) callconv(.C) JSC.JSValue { - const arguments = callframe.arguments(2); - if (arguments.len < 1) { - globalThis.throwNotEnoughArguments("callback", 1, arguments.len); + const arguments_ = callframe.arguments(2); + const arguments = arguments_.ptr[0..arguments_.len]; + if (arguments.len == 0 or !arguments[0].isObject() or !arguments[0].isCallable(globalThis.vm())) { + globalThis.throwInvalidArgumentType(@tagName(this_hook), "callback", "function"); return .zero; } - const cb = arguments.ptr[0]; - if (!cb.isObject() or !cb.isCallable(globalThis.vm())) { - globalThis.throwInvalidArgumentType(@tagName(hook), "callback", "function"); - return .zero; - } - - cb.protect(); - @field(DescribeScope.active.?, @tagName(hook)).append(getAllocator(globalThis), cb) catch unreachable; + arguments[0].protect(); + const name = comptime @as(string, @tagName(this_hook)); + @field(DescribeScope.active, name).append(getAllocator(globalThis), arguments[0]) catch unreachable; return JSC.JSValue.jsBoolean(true); } }.run; @@ -829,22 +829,11 @@ pub const DescribeScope = struct { pub const beforeAll = createCallback(.beforeAll); pub const beforeEach = createCallback(.beforeEach); - pub fn execCallback(this: *DescribeScope, globalObject: *JSC.JSGlobalObject, comptime hook: LifecycleHook) ?JSValue { - var hooks = &@field(this, @tagName(hook)); - defer { - if (comptime hook == .beforeAll or hook == .afterAll) { - hooks.clearAndFree(getAllocator(globalObject)); - } - } - - for (hooks.items) |cb| { - std.debug.assert(cb.isObject()); - std.debug.assert(cb.isCallable(globalObject.vm())); - defer { - if (comptime hook == .beforeAll or hook == .afterAll) { - cb.unprotect(); - } - } + pub fn execCallback(this: *DescribeScope, globalObject: *JSC.JSGlobalObject, comptime hook: LifecycleHook) JSValue { + const name = comptime @as(string, @tagName(hook)); + var hooks: []JSC.JSValue = @field(this, name).items; + for (hooks, 0..) |cb, i| { + if (cb.isEmpty()) continue; const pending_test = Jest.runner.?.pending_test; // forbid `expect()` within hooks @@ -854,23 +843,20 @@ pub const DescribeScope = struct { Jest.runner.?.did_pending_test_fail = false; const vm = VirtualMachine.get(); - var result: JSC.JSValue = switch (cb.getLength(globalObject)) { - 0 => cb.call(globalObject, &.{}), - else => brk: { - this.done = false; - const done_func = JSC.NewFunctionWithData( - globalObject, - ZigString.static("done"), - 0, - DescribeScope.onDone, - false, - this, - ); - var result = cb.call(globalObject, &.{done_func}); - vm.waitFor(&this.done); - break :brk result; - }, - }; + var result: JSC.JSValue = if (cb.getLength(globalObject) > 0) brk: { + this.done = false; + const done_func = JSC.NewFunctionWithData( + globalObject, + ZigString.static("done"), + 0, + DescribeScope.onDone, + false, + this, + ); + var result = cb.call(globalObject, &.{done_func}); + vm.waitFor(&this.done); + break :brk result; + } else cb.call(globalObject, &.{}); if (result.asAnyPromise()) |promise| { if (promise.status(globalObject.vm()) == .Pending) { result.protect(); @@ -884,28 +870,19 @@ pub const DescribeScope = struct { Jest.runner.?.pending_test = pending_test; Jest.runner.?.did_pending_test_fail = orig_did_pending_test_fail; if (result.isAnyError()) return result; + + if (comptime hook == .beforeAll or hook == .afterAll) { + hooks[i] = JSC.JSValue.zero; + } } - return null; + return JSValue.zero; } pub fn runGlobalCallbacks(globalThis: *JSC.JSGlobalObject, comptime hook: LifecycleHook) ?JSValue { // global callbacks - var hooks = &@field(Jest.runner.?.global_callbacks, @tagName(hook)); - defer { - if (comptime hook == .beforeAll or hook == .afterAll) { - hooks.clearAndFree(getAllocator(globalThis)); - } - } - - for (hooks.items) |cb| { - std.debug.assert(cb.isObject()); - std.debug.assert(cb.isCallable(globalThis.vm())); - defer { - if (comptime hook == .beforeAll or hook == .afterAll) { - cb.unprotect(); - } - } + for (@field(Jest.runner.?.global_callbacks, @tagName(hook)).items) |cb| { + if (cb.isEmpty()) continue; const pending_test = Jest.runner.?.pending_test; // forbid `expect()` within hooks @@ -932,40 +909,28 @@ pub const DescribeScope = struct { if (result.isAnyError()) return result; } - return null; - } - - fn runBeforeCallbacks(this: *DescribeScope, globalObject: *JSC.JSGlobalObject, comptime hook: LifecycleHook) ?JSValue { - if (this.parent) |scope| { - if (scope.runBeforeCallbacks(globalObject, hook)) |err| { - return err; - } + if (comptime hook == .beforeAll or hook == .afterAll) { + @field(Jest.runner.?.global_callbacks, @tagName(hook)).items.len = 0; } - return this.execCallback(globalObject, hook); + + return null; } pub fn runCallback(this: *DescribeScope, globalObject: *JSC.JSGlobalObject, comptime hook: LifecycleHook) JSValue { - if (comptime hook == .afterAll or hook == .afterEach) { - var parent: ?*DescribeScope = this; - while (parent) |scope| { - if (scope.execCallback(globalObject, hook)) |err| { - return err; - } - parent = scope.parent; - } - } - if (runGlobalCallbacks(globalObject, hook)) |err| { return err; } - if (comptime hook == .beforeAll or hook == .beforeEach) { - if (this.runBeforeCallbacks(globalObject, hook)) |err| { - return err; + var parent = this.parent; + while (parent) |scope| { + const ret = scope.execCallback(globalObject, hook); + if (!ret.isEmpty()) { + return ret; } + parent = scope.parent; } - return .zero; + return this.execCallback(globalObject, hook); } pub fn call(globalThis: *JSGlobalObject, callframe: *CallFrame) callconv(.C) JSValue { @@ -996,8 +961,11 @@ pub const DescribeScope = struct { if (comptime is_bindgen) return undefined; callback.protect(); defer callback.unprotect(); - this.push(); - defer this.pop(); + var original_active = active; + defer active = original_active; + if (this != module) + this.parent = this.parent orelse active; + active = this; if (callback == .zero) { this.runTests(globalObject); @@ -1096,8 +1064,9 @@ pub const DescribeScope = struct { if (!this.isAllSkipped()) { // Run the afterAll callbacks, in reverse order // unless there were no tests for this scope - if (this.execCallback(globalThis, .afterAll)) |err| { - globalThis.bunVM().runErrorHandler(err, null); + const afterAll_result = this.execCallback(globalThis, .afterAll); + if (!afterAll_result.isEmpty()) { + globalThis.bunVM().runErrorHandler(afterAll_result, null); } } @@ -1177,6 +1146,7 @@ pub const TestRunnerTask = struct { // reset the global state for each test // prior to the run + DescribeScope.active = describe; expect.active_test_expectation_counter = .{}; jsc_vm.last_reported_error_for_dedupe = .zero; @@ -1447,7 +1417,7 @@ inline fn createScope( return .zero; } - const parent = DescribeScope.active.?; + const parent = DescribeScope.active; const allocator = getAllocator(globalThis); const label = if (description == .zero) "" diff --git a/test/js/bun/test/jest-hooks.test.ts b/test/js/bun/test/jest-hooks.test.ts index 618cdc4c6..c99dc7759 100644 --- a/test/js/bun/test/jest-hooks.test.ts +++ b/test/js/bun/test/jest-hooks.test.ts @@ -1,36 +1,5 @@ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "bun:test"; -let hooks_run: string[] = []; - -beforeAll(() => hooks_run.push("global beforeAll")); -beforeEach(() => hooks_run.push("global beforeEach")); -afterAll(() => hooks_run.push("global afterAll")); -afterEach(() => hooks_run.push("global afterEach")); - -describe("describe scope", () => { - beforeAll(() => hooks_run.push("describe beforeAll")); - beforeEach(() => hooks_run.push("describe beforeEach")); - afterAll(() => hooks_run.push("describe afterAll")); - afterEach(() => hooks_run.push("describe afterEach")); - - it("should run after beforeAll/beforeEach in the correct order", () => { - expect(hooks_run).toEqual(["global beforeAll", "describe beforeAll", "global beforeEach", "describe beforeEach"]); - }); - - it("should run after afterEach/afterAll in the correct order", () => { - expect(hooks_run).toEqual([ - "global beforeAll", - "describe beforeAll", - "global beforeEach", - "describe beforeEach", - "describe afterEach", - "global afterEach", - "global beforeEach", - "describe beforeEach", - ]); - }); -}); - describe("test jest hooks in bun-test", () => { describe("test beforeAll hook", () => { let animal = "tiger"; diff --git a/test/js/bun/test/test-test.test.ts b/test/js/bun/test/test-test.test.ts index 5f732bb82..7ecfdef11 100644 --- a/test/js/bun/test/test-test.test.ts +++ b/test/js/bun/test/test-test.test.ts @@ -540,18 +540,18 @@ beforeEach: #2 beforeEach: TEST-FILE beforeEach: one describe scope -- inside one describe scope -- -afterEach: one describe scope -afterEach: TEST-FILE afterEach: #1 afterEach: #2 +afterEach: TEST-FILE +afterEach: one describe scope afterAll: one describe scope beforeEach: #1 beforeEach: #2 beforeEach: TEST-FILE -- the top-level test -- -afterEach: TEST-FILE afterEach: #1 afterEach: #2 +afterEach: TEST-FILE afterAll: TEST-FILE afterAll: #1 afterAll: #2 |