diff --git a/src/bun.js/test/ScopeFunctions.zig b/src/bun.js/test/ScopeFunctions.zig index 936aee5380..599b1ae14c 100644 --- a/src/bun.js/test/ScopeFunctions.zig +++ b/src/bun.js/test/ScopeFunctions.zig @@ -278,7 +278,6 @@ fn genericExtend(this: *ScopeFunctions, globalThis: *JSGlobalObject, cfg: bun_te } fn errorInCI(globalThis: *jsc.JSGlobalObject, signature: []const u8) bun.JSError!void { - if (!bun.FeatureFlags.breaking_changes_1_3) return; // this is a breaking change for version 1.3 if (bun.detectCI()) |_| { return globalThis.throwPretty("{s} is not allowed in CI environments.\nIf this is not a CI environment, set the environment variable CI=false to force allow.", .{signature}); } diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index 5a132d23c9..1c0894a6ef 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -744,12 +744,10 @@ pub const Expect = struct { } if (needs_write) { - if (bun.FeatureFlags.breaking_changes_1_3) { - if (bun.detectCI()) |_| { - if (!update) { - const signature = comptime getSignature(fn_name, "", false); - return this.throw(globalThis, signature, "\n\nMatcher error: Inline snapshot updates are not allowed in CI environments unless --update-snapshots is used\nIf this is not a CI environment, set the environment variable CI=false to force allow.", .{}); - } + if (bun.detectCI()) |_| { + if (!update) { + const signature = comptime getSignature(fn_name, "", false); + return this.throw(globalThis, signature, "\n\nMatcher error: Inline snapshot updates are not allowed in CI environments unless --update-snapshots is used\nIf this is not a CI environment, set the environment variable CI=false to force allow.", .{}); } } var buntest_strong = this.bunTest() orelse { diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 0900c90ecd..350b75a069 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -484,7 +484,6 @@ pub fn captureTestLineNumber(callframe: *jsc.CallFrame, globalThis: *JSGlobalObj } pub fn errorInCI(globalObject: *jsc.JSGlobalObject, message: []const u8) bun.JSError!void { - if (!bun.FeatureFlags.breaking_changes_1_3) return; // this is a breaking change for version 1.3 if (bun.detectCI()) |_| { return globalObject.throwPretty("{s}\nIf this is not a CI environment, set the environment variable CI=false to force allow.", .{message}); } diff --git a/src/bun.js/test/snapshot.zig b/src/bun.js/test/snapshot.zig index 07300f6915..e3dac38abf 100644 --- a/src/bun.js/test/snapshot.zig +++ b/src/bun.js/test/snapshot.zig @@ -85,11 +85,9 @@ pub const Snapshots = struct { // doesn't exist. append to file bytes and add to hashmap. // Prevent snapshot creation in CI environments unless --update-snapshots is used - if (bun.FeatureFlags.breaking_changes_1_3) { - if (bun.detectCI()) |_| { - if (!this.update_snapshots) { - return error.SnapshotCreationNotAllowedInCI; - } + if (bun.detectCI()) |_| { + if (!this.update_snapshots) { + return error.SnapshotCreationNotAllowedInCI; } } diff --git a/src/codegen/generate-node-errors.ts b/src/codegen/generate-node-errors.ts index 3eedd43170..9fee927999 100644 --- a/src/codegen/generate-node-errors.ts +++ b/src/codegen/generate-node-errors.ts @@ -72,11 +72,7 @@ pub fn ErrorBuilder(comptime code: Error, comptime fmt: [:0]const u8, Args: type /// Turn this into a JSPromise that is already rejected. pub inline fn reject(this: @This()) jsc.JSValue { - if (comptime bun.FeatureFlags.breaking_changes_1_3) { - return jsc.JSPromise.rejectedPromise(this.globalThis, code.fmt(this.global, fmt, this.args)).toJS(); - } else { - return jsc.JSPromise.dangerouslyCreateRejectedPromiseValueWithoutNotifyingVM(this.global, code.fmt(this.global, fmt, this.args)); - } + return jsc.JSPromise.rejectedPromise(this.global, code.fmt(this.global, fmt, this.args)).toJS(); } }; } diff --git a/src/feature_flags.zig b/src/feature_flags.zig index da55db656e..6ee4597fe9 100644 --- a/src/feature_flags.zig +++ b/src/feature_flags.zig @@ -46,7 +46,7 @@ pub const RuntimeFeatureFlag = enum { /// Enable breaking changes for the next major release of Bun // TODO: Make this a CLI flag / runtime var so that we can verify disabled code paths can compile -pub const breaking_changes_1_3 = false; +pub const breaking_changes_1_4 = false; /// Store and reuse file descriptors during module resolution /// This was a ~5% performance improvement diff --git a/test/js/bun/test/concurrent-and-serial.fixture.ts b/test/js/bun/test/concurrent-and-serial.fixture.ts new file mode 100644 index 0000000000..601bba0497 --- /dev/null +++ b/test/js/bun/test/concurrent-and-serial.fixture.ts @@ -0,0 +1,42 @@ +import { test, describe, beforeEach } from "bun:test"; + +let activeGroup: (() => void)[] = []; +function tick() { + const { resolve, reject, promise } = Promise.withResolvers(); + activeGroup.push(() => resolve()); + setTimeout(() => { + activeGroup.shift()?.(); + }, 0); + return promise; +} + +test("test default-1", async () => { + console.log("[0] start test default-1"); + await tick(); + console.log("[1] end test default-1"); +}); +test("test default-2", async () => { + console.log("[0] start test default-2"); + await tick(); + console.log("[1] end test default-2"); +}); +test.concurrent("test concurrent-1", async () => { + console.log("[0] start test concurrent-1"); + await tick(); + console.log("[1] end test concurrent-1"); +}); +test.concurrent("test concurrent-2", async () => { + console.log("[0] start test concurrent-2"); + await tick(); + console.log("[1] end test concurrent-2"); +}); +test.serial("test serial-1", async () => { + console.log("[0] start test serial-1"); + await tick(); + console.log("[1] end test serial-1"); +}); +test.serial("test serial-2", async () => { + console.log("[0] start test serial-2"); + await tick(); + console.log("[1] end test serial-2"); +}); diff --git a/test/js/bun/test/concurrent.test.ts b/test/js/bun/test/concurrent.test.ts index df1fe530c2..16b8c2bb35 100644 --- a/test/js/bun/test/concurrent.test.ts +++ b/test/js/bun/test/concurrent.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "bun:test"; import { bunEnv, bunExe, normalizeBunSnapshot } from "harness"; -test("concurrent order", async () => { +test.concurrent("concurrent order", async () => { const result = await Bun.spawn({ cmd: [bunExe(), "test", import.meta.dir + "/concurrent.fixture.ts"], stdout: "pipe", @@ -58,7 +58,63 @@ test("concurrent order", async () => { `); }); -test("max-concurrency limits concurrent tests", async () => { +test.concurrent("concurrent-and-serial --concurrent", async () => { + const result = await Bun.spawn({ + cmd: [bunExe(), "test", import.meta.dir + "/concurrent-and-serial.fixture.ts", "--concurrent"], + 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(normalizeBunSnapshot(stdout)).toMatchInlineSnapshot(` + "bun test () + [0] start test default-1 + [0] start test default-2 + [0] start test concurrent-1 + [0] start test concurrent-2 + [1] end test default-1 + [1] end test default-2 + [1] end test concurrent-1 + [1] end test concurrent-2 + [0] start test serial-1 + [1] end test serial-1 + [0] start test serial-2 + [1] end test serial-2" + `); +}); + +test.concurrent("concurrent-and-serial, no flag", async () => { + const result = await Bun.spawn({ + cmd: [bunExe(), "test", import.meta.dir + "/concurrent-and-serial.fixture.ts"], + 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(normalizeBunSnapshot(stdout)).toMatchInlineSnapshot(` + "bun test () + [0] start test default-1 + [1] end test default-1 + [0] start test default-2 + [1] end test default-2 + [0] start test concurrent-1 + [0] start test concurrent-2 + [1] end test concurrent-1 + [1] end test concurrent-2 + [0] start test serial-1 + [1] end test serial-1 + [0] start test serial-2 + [1] end test serial-2" + `); +}); + +test.concurrent("max-concurrency limits concurrent tests", async () => { // Test with max-concurrency=3 const result = await Bun.spawn({ cmd: [bunExe(), "test", "--max-concurrency", "3", import.meta.dir + "/concurrent-max.fixture.ts"], @@ -81,7 +137,7 @@ test("max-concurrency limits concurrent tests", async () => { expect(executionPattern).toEqual(expected); }); -test("max-concurrency default is 20", async () => { +test.concurrent("max-concurrency default is 20", async () => { const result = await Bun.spawn({ cmd: [bunExe(), "test", import.meta.dir + "/concurrent-max.fixture.ts"], stdout: "pipe", @@ -103,7 +159,7 @@ test("max-concurrency default is 20", async () => { expect(executionPattern).toEqual(expected); }); -test("zero removes max-concurrency", async () => { +test.concurrent("zero removes max-concurrency", async () => { const result = await Bun.spawn({ cmd: [bunExe(), "test", "--max-concurrency", "0", import.meta.dir + "/concurrent-max.fixture.ts"], stdout: "pipe", diff --git a/test/js/bun/test/test-serial.test.ts b/test/js/bun/test/test-serial.test.ts deleted file mode 100644 index bd60ac64ad..0000000000 --- a/test/js/bun/test/test-serial.test.ts +++ /dev/null @@ -1,269 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -// Test that test.serial() is available and works -test("test.serial is a function", () => { - expect(typeof test.serial).toBe("function"); -}); - -test("test.serial.if is a function", () => { - expect(typeof test.serial.if).toBe("function"); -}); - -test("test.serial.skip is a function", () => { - expect(typeof test.serial.skip).toBe("function"); -}); - -test("test.serial.todo is a function", () => { - expect(typeof test.serial.todo).toBe("function"); -}); - -test("test.serial.each is a function", () => { - expect(typeof test.serial.each).toBe("function"); -}); - -test("test.serial.only is a function", () => { - expect(typeof test.serial.only).toBe("function"); -}); - -// Test describe.serial -test("describe.serial is a function", () => { - expect(typeof describe.serial).toBe("function"); -}); - -// Test serialIf function -test("test.serial.if() works correctly", () => { - const serialIf = test.serial.if(true); - expect(typeof serialIf).toBe("function"); - - const notSerial = test.serial.if(false); - expect(typeof notSerial).toBe("function"); -}); - -// Functional tests for serial execution -let serialTestCounter = 0; -const serialResults: number[] = []; - -test.serial("serial execution test 1", async () => { - const myIndex = serialTestCounter++; - serialResults.push(myIndex); - await Bun.sleep(10); - expect(myIndex).toBe(0); -}); - -test.serial("serial execution test 2", async () => { - const myIndex = serialTestCounter++; - serialResults.push(myIndex); - await Bun.sleep(10); - expect(myIndex).toBe(1); -}); - -test.serial("serial execution test 3", async () => { - const myIndex = serialTestCounter++; - serialResults.push(myIndex); - await Bun.sleep(10); - expect(myIndex).toBe(2); -}); - -// Verify serial execution happened -test("verify serial execution order", () => { - expect(serialResults).toEqual([0, 1, 2]); -}); - -// Test describe.serial functionality -describe.serial("serial describe block", () => { - let describeCounter = 0; - const describeResults: number[] = []; - - test("nested test 1", async () => { - const myIndex = describeCounter++; - describeResults.push(myIndex); - await Bun.sleep(10); - expect(myIndex).toBe(0); - }); - - test("nested test 2", async () => { - const myIndex = describeCounter++; - describeResults.push(myIndex); - await Bun.sleep(10); - expect(myIndex).toBe(1); - }); - - test("verify nested serial execution", () => { - expect(describeResults).toEqual([0, 1]); - }); -}); - -// Test test.serial.each functionality -const testCases = [ - [1, 2, 3], - [4, 5, 9], - [10, 20, 30], -]; -let eachCounter = 0; - -test.serial.each(testCases)("serial.each test %#", (a, b, expected) => { - const myIndex = eachCounter++; - expect(a + b).toBe(expected); - // These should run serially, so counter should increment predictably - expect(myIndex).toBeLessThan(3); -}); - -// Test mixing serial and concurrent in same describe block -describe("mixing serial and concurrent tests", () => { - let mixedCounter = 0; - const mixedResults: { type: string; index: number; startTime: number }[] = []; - const startTime = Date.now(); - - test.serial("mixed serial 1", async () => { - const myIndex = mixedCounter++; - mixedResults.push({ type: "serial", index: myIndex, startTime: Date.now() - startTime }); - await Bun.sleep(20); - }); - - test.concurrent("mixed concurrent 1", async () => { - const myIndex = mixedCounter++; - mixedResults.push({ type: "concurrent", index: myIndex, startTime: Date.now() - startTime }); - await Bun.sleep(20); - }); - - test.concurrent("mixed concurrent 2", async () => { - const myIndex = mixedCounter++; - mixedResults.push({ type: "concurrent", index: myIndex, startTime: Date.now() - startTime }); - await Bun.sleep(20); - }); - - test.serial("mixed serial 2", async () => { - const myIndex = mixedCounter++; - mixedResults.push({ type: "serial", index: myIndex, startTime: Date.now() - startTime }); - await Bun.sleep(20); - }); - - test("verify mixed execution", () => { - // Serial tests should not overlap with each other - const serialTests = mixedResults.filter(r => r.type === "serial"); - for (let i = 1; i < serialTests.length; i++) { - // Each serial test should start after the previous one (with at least 15ms gap for 20ms sleep) - const gap = serialTests[i].startTime - serialTests[i - 1].startTime; - expect(gap).toBeGreaterThanOrEqual(15); - } - - // Concurrent tests might overlap (their start times should be close) - const concurrentTests = mixedResults.filter(r => r.type === "concurrent"); - if (concurrentTests.length > 1) { - const gap = concurrentTests[1].startTime - concurrentTests[0].startTime; - // Concurrent tests should start within a few ms of each other - expect(gap).toBeLessThan(10); - } - }); -}); - -// Test nested describe blocks with conflicting settings -describe.concurrent("concurrent parent describe", () => { - let parentCounter = 0; - const parentResults: { block: string; index: number }[] = []; - - test("parent test 1", async () => { - const myIndex = parentCounter++; - parentResults.push({ block: "parent", index: myIndex }); - await Bun.sleep(10); - }); - - describe.serial("nested serial describe", () => { - let nestedCounter = 0; - - test("nested serial 1", async () => { - const myIndex = nestedCounter++; - parentResults.push({ block: "nested-serial", index: myIndex }); - await Bun.sleep(10); - expect(myIndex).toBe(0); - }); - - test("nested serial 2", async () => { - const myIndex = nestedCounter++; - parentResults.push({ block: "nested-serial", index: myIndex }); - await Bun.sleep(10); - expect(myIndex).toBe(1); - }); - }); - - test("parent test 2", async () => { - const myIndex = parentCounter++; - parentResults.push({ block: "parent", index: myIndex }); - await Bun.sleep(10); - }); - - test("verify nested behavior", () => { - // Tests in the nested serial block should run serially - const nestedSerial = parentResults.filter(r => r.block === "nested-serial"); - expect(nestedSerial[0].index).toBe(0); - expect(nestedSerial[1].index).toBe(1); - }); -}); - -// Test explicit serial overrides concurrent describe -describe.concurrent("concurrent describe with explicit serial", () => { - let overrideCounter = 0; - const overrideResults: number[] = []; - - test.serial("explicit serial in concurrent describe 1", async () => { - const myIndex = overrideCounter++; - overrideResults.push(myIndex); - await Bun.sleep(10); - expect(myIndex).toBe(0); - }); - - test.serial("explicit serial in concurrent describe 2", async () => { - const myIndex = overrideCounter++; - overrideResults.push(myIndex); - await Bun.sleep(10); - expect(myIndex).toBe(1); - }); - - test("regular test in concurrent describe", async () => { - const myIndex = overrideCounter++; - overrideResults.push(myIndex); - await Bun.sleep(10); - }); - - test("verify override behavior", () => { - // First two tests should have run serially - expect(overrideResults[0]).toBe(0); - expect(overrideResults[1]).toBe(1); - }); -}); - -// Test explicit concurrent overrides serial describe -describe.serial("serial describe with explicit concurrent", () => { - let overrideCounter2 = 0; - let maxConcurrent2 = 0; - let currentlyRunning2 = 0; - - test.concurrent("explicit concurrent in serial describe 1", async () => { - currentlyRunning2++; - maxConcurrent2 = Math.max(maxConcurrent2, currentlyRunning2); - overrideCounter2++; - await Bun.sleep(10); - currentlyRunning2--; - }); - - test.concurrent("explicit concurrent in serial describe 2", async () => { - currentlyRunning2++; - maxConcurrent2 = Math.max(maxConcurrent2, currentlyRunning2); - overrideCounter2++; - await Bun.sleep(10); - currentlyRunning2--; - }); - - test("regular test in serial describe", async () => { - overrideCounter2++; - await Bun.sleep(10); - }); - - test("verify concurrent override in serial describe", () => { - // The concurrent tests should have run in parallel even in a serial describe - if (typeof maxConcurrent2 === "number") { - // This might be 1 if tests ran too fast, but structure is correct - expect(maxConcurrent2).toBeGreaterThanOrEqual(1); - } - }); -}); diff --git a/test/regression/issue/14135.test.ts b/test/regression/issue/14135.test.ts index 01c5a3411b..7820cf1f89 100644 --- a/test/regression/issue/14135.test.ts +++ b/test/regression/issue/14135.test.ts @@ -6,7 +6,7 @@ test("14135", async () => { cmd: [bunExe(), "test", import.meta.dir + "/14135.fixture.ts"], stdout: "pipe", stderr: "pipe", - env: bunEnv, + env: { ...bunEnv, CI: "false" }, // tests '.only()' }); const exitCode = await result.exited; const stdout = await result.stdout.text(); diff --git a/test/regression/issue/19875.test.ts b/test/regression/issue/19875.test.ts index c38abca300..e409ffb489 100644 --- a/test/regression/issue/19875.test.ts +++ b/test/regression/issue/19875.test.ts @@ -6,7 +6,7 @@ test("19875", async () => { cmd: [bunExe(), "test", import.meta.dir + "/19875.fixture.ts"], stdout: "pipe", stderr: "pipe", - env: bunEnv, + env: { ...bunEnv, CI: "false" }, // tests '.only()' }); const exitCode = await result.exited; const stdout = await result.stdout.text(); diff --git a/test/regression/issue/20092.test.ts b/test/regression/issue/20092.test.ts index bba0f35dbe..833ff00943 100644 --- a/test/regression/issue/20092.test.ts +++ b/test/regression/issue/20092.test.ts @@ -6,7 +6,7 @@ test("20092", async () => { cmd: [bunExe(), "test", import.meta.dir + "/20092.fixture.ts"], stdout: "pipe", stderr: "pipe", - env: bunEnv, + env: { ...bunEnv, CI: "false" }, // tests '.only()' }); const exitCode = await result.exited; const stdout = await result.stdout.text(); diff --git a/test/regression/issue/5961.test.ts b/test/regression/issue/5961.test.ts index 87ff87ad8b..3cb657a446 100644 --- a/test/regression/issue/5961.test.ts +++ b/test/regression/issue/5961.test.ts @@ -6,7 +6,7 @@ test("5961", async () => { cmd: [bunExe(), "test", import.meta.dir + "/5961.fixture.ts"], stdout: "pipe", stderr: "pipe", - env: bunEnv, + env: { ...bunEnv, CI: "false" }, // tests '.only()' }); const exitCode = await result.exited; const stdout = await result.stdout.text();