diff --git a/scripts/runner.node.mjs b/scripts/runner.node.mjs index a04e0c5148d1..b6e5bddf8b2e 100755 --- a/scripts/runner.node.mjs +++ b/scripts/runner.node.mjs @@ -1784,6 +1784,7 @@ async function spawnBun(execPath, { args, cwd, timeout, gracefulTimeout, idleTim FORCE_COLOR: "1", BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "1", BUN_DEBUG_QUIET_LOGS: "1", + BUN_DISABLE_SLOW_FILESYSTEM_WARNING: "1", BUN_GARBAGE_COLLECTOR_LEVEL: "1", BUN_JSC_randomIntegrityAuditRate: "1.0", BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0", diff --git a/src/bun_core/env_var.rs b/src/bun_core/env_var.rs index bf8e49fb2e5a..9d0cfef32b36 100644 --- a/src/bun_core/env_var.rs +++ b/src/bun_core/env_var.rs @@ -234,6 +234,8 @@ pub mod feature_flag { // Fall back to the scalar byte-at-a-time VLQ decode in // bun_sourcemap::mapping::parse (skips the Highway-dispatched path). new_feature_flag!(pub BUN_FEATURE_FLAG_DISABLE_SIMD_SOURCEMAP, "BUN_FEATURE_FLAG_DISABLE_SIMD_SOURCEMAP", {}); + // Set by the test harness so stderr assertions don't flake on slow CI filesystems. + new_feature_flag!(pub BUN_DISABLE_SLOW_FILESYSTEM_WARNING, "BUN_DISABLE_SLOW_FILESYSTEM_WARNING", {}); new_feature_flag!(pub BUN_DISABLE_SLOW_LIFECYCLE_SCRIPT_LOGGING, "BUN_DISABLE_SLOW_LIFECYCLE_SCRIPT_LOGGING", {}); new_feature_flag!(pub BUN_DISABLE_SOURCE_CODE_PREVIEW, "BUN_DISABLE_SOURCE_CODE_PREVIEW", {}); new_feature_flag!(pub BUN_FEATURE_FLAG_DISABLE_SOURCE_MAPS, "BUN_FEATURE_FLAG_DISABLE_SOURCE_MAPS", {}); diff --git a/src/install/PackageManager/PackageManagerDirectories.rs b/src/install/PackageManager/PackageManagerDirectories.rs index 3e075528d548..950f3ef74b54 100644 --- a/src/install/PackageManager/PackageManagerDirectories.rs +++ b/src/install/PackageManager/PackageManagerDirectories.rs @@ -183,7 +183,11 @@ fn get_temporary_directory_run(manager: &mut PackageManager) -> TemporaryDirecto let tmpname = FileSystem::tmpname(b"hm", &mut tmpbuf, bun_core::fast_random()).expect("unreachable"); - let mut timer = if manager.options.log_level != LogLevel::Silent { + let mut timer = if manager.options.log_level != LogLevel::Silent + && !bun_core::env_var::feature_flag::BUN_DISABLE_SLOW_FILESYSTEM_WARNING + .get() + .unwrap_or(false) + { Some(bun_core::time::Timer::start()) } else { None @@ -272,8 +276,8 @@ fn get_temporary_directory_run(manager: &mut PackageManager) -> TemporaryDirecto break; } - if manager.options.log_level != LogLevel::Silent { - let elapsed = timer.as_mut().unwrap().read(); + if let Some(timer) = timer.as_mut() { + let elapsed = timer.read(); if elapsed > bun_core::time::NS_PER_MS * 100 { let mut path_buf = PathBuffer::uninit(); let cache_dir_path: &[u8] = match sys::get_fd_path(cache_directory_fd, &mut path_buf) { diff --git a/test/cli/install/bun-install-lifecycle-scripts.test.ts b/test/cli/install/bun-install-lifecycle-scripts.test.ts index 8123acc24bdf..73b280bdb58c 100644 --- a/test/cli/install/bun-install-lifecycle-scripts.test.ts +++ b/test/cli/install/bun-install-lifecycle-scripts.test.ts @@ -10,7 +10,6 @@ import { isWindows, readdirSorted, runBunInstall, - stderrForInstall, } from "harness"; import { join, sep } from "path"; @@ -1716,7 +1715,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -2025,7 +2024,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -2294,7 +2293,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3184,7 +3183,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3217,7 +3216,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).not.toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3253,7 +3252,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - const err = stderrForInstall(await stderr.text()); + const err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3295,7 +3294,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3384,7 +3383,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3419,7 +3418,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).not.toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3459,7 +3458,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3506,7 +3505,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3553,7 +3552,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3602,7 +3601,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3650,7 +3649,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env.PATH = originalPath; - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("No packages! Deleted empty lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3691,7 +3690,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env.PATH = originalPath; - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("No packages! Deleted empty lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3723,7 +3722,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); @@ -3753,7 +3752,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("bun pm untrusted"); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); @@ -3806,7 +3805,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3836,7 +3835,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); out = await stdout.text(); @@ -3863,7 +3862,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3891,7 +3890,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3926,7 +3925,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -3954,7 +3953,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); out = await stdout.text(); @@ -4072,7 +4071,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - const err = stderrForInstall(await stderr.text()); + const err = await stderr.text(); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); expect(splitErrLines(err)).toEqual([ @@ -4127,7 +4126,7 @@ for (const forceWaiterThread of isLinux ? [false, true] : [false]) { env: testEnv, }); - const err = stderrForInstall(await stderr.text()); + const err = await stderr.text(); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); expect(splitErrLines(err)).toEqual([ diff --git a/test/cli/install/bun-install-registry.test.ts b/test/cli/install/bun-install-registry.test.ts index 5b0bdeecf241..b82c40ff48bd 100644 --- a/test/cli/install/bun-install-registry.test.ts +++ b/test/cli/install/bun-install-registry.test.ts @@ -14,7 +14,6 @@ import { readdirSorted, runBunInstall, runBunUpdate, - stderrForInstall, tempDir, tls, tmpdirSync, @@ -212,7 +211,7 @@ describe("certificate authority", () => { env, }); let out = await stdout.text(); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("DEPTH_ZERO_SELF_SIGNED_CERT"); expect(await exited).toBe(1); @@ -6239,7 +6238,7 @@ describe("pm trust", async () => { env, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).not.toContain("Saved lockfile"); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); @@ -6266,7 +6265,7 @@ describe("pm trust", async () => { env, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).toContain("error: Lockfile not found"); let out = await stdout.text(); expect(out).toBeEmpty(); @@ -6292,7 +6291,7 @@ describe("pm trust", async () => { env, }); - let err = stderrForInstall(await stderr.text()); + let err = await stderr.text(); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); @@ -6319,7 +6318,7 @@ describe("pm trust", async () => { env, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(err).not.toContain("warn:"); diff --git a/test/cli/install/bun-link.test.ts b/test/cli/install/bun-link.test.ts index 76438f8dadf1..8a937dad63fd 100644 --- a/test/cli/install/bun-link.test.ts +++ b/test/cli/install/bun-link.test.ts @@ -7,7 +7,6 @@ import { isWindows, readdirSorted, runBunInstall, - stderrForInstall, tmpdirSync, toBeValidBin, toHaveBins, @@ -75,7 +74,7 @@ it("should link and unlink workspace package", async () => { env, }); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err.split(/\r?\n/)).toEqual([""]); expect(await stdout.text()).toContain(`Success! Registered "moo"`); expect(await exited).toBe(0); @@ -89,7 +88,7 @@ it("should link and unlink workspace package", async () => { env, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err.split(/\r?\n/)).toEqual([""]); expect((await stdout.text()).replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([ expect.stringContaining("bun link v1."), @@ -113,7 +112,7 @@ it("should link and unlink workspace package", async () => { env, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err.split(/\r?\n/)).toEqual([""]); expect(await stdout.text()).toContain(`success: unlinked package "moo"`); expect(await exited).toBe(0); @@ -128,7 +127,7 @@ it("should link and unlink workspace package", async () => { env, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err.split(/\r?\n/)).toEqual([""]); expect(await stdout.text()).toContain(`Success! Registered "foo"`); expect(await exited).toBe(0); @@ -142,7 +141,7 @@ it("should link and unlink workspace package", async () => { env, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err.split(/\r?\n/)).toEqual([""]); expect((await stdout.text()).replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([ expect.stringContaining("bun link v1."), @@ -167,7 +166,7 @@ it("should link and unlink workspace package", async () => { env, })); - err = stderrForInstall(await stderr.text()); + err = await stderr.text(); expect(err.split(/\r?\n/)).toEqual([""]); expect(await stdout.text()).toContain(`success: unlinked package "foo"`); expect(await exited).toBe(0); @@ -202,7 +201,7 @@ it("should link package", async () => { stderr: "pipe", env, }); - const err1 = stderrForInstall(await new Response(stderr1).text()); + const err1 = await new Response(stderr1).text(); expect(err1.split(/\r?\n/)).toEqual([""]); expect(await new Response(stdout1).text()).toContain(`Success! Registered "${link_name}"`); expect(await exited1).toBe(0); @@ -219,7 +218,7 @@ it("should link package", async () => { stderr: "pipe", env, }); - const err2 = stderrForInstall(await new Response(stderr2).text()); + const err2 = await new Response(stderr2).text(); expect(err2.split(/\r?\n/)).toEqual([""]); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([ @@ -243,7 +242,7 @@ it("should link package", async () => { stderr: "pipe", env, }); - const err3 = stderrForInstall(await new Response(stderr3).text()); + const err3 = await new Response(stderr3).text(); expect(err3.split(/\r?\n/)).toEqual([""]); expect(await new Response(stdout3).text()).toContain(`success: unlinked package "${link_name}"`); expect(await exited3).toBe(0); @@ -260,7 +259,7 @@ it("should link package", async () => { stderr: "pipe", env, }); - const err4 = stderrForInstall(await new Response(stderr4).text()); + const err4 = await new Response(stderr4).text(); expect(err4).toContain(`error: Package "${link_name}" is not linked`); expect(await new Response(stdout4).text()).toEqual(expect.stringContaining("bun link v1.")); expect(await exited4).toBe(1); @@ -295,7 +294,7 @@ it("should link scoped package", async () => { stderr: "pipe", env, }); - const err1 = stderrForInstall(await new Response(stderr1).text()); + const err1 = await new Response(stderr1).text(); expect(err1.split(/\r?\n/)).toEqual([""]); expect(await new Response(stdout1).text()).toContain(`Success! Registered "${link_name}"`); expect(await exited1).toBe(0); @@ -312,7 +311,7 @@ it("should link scoped package", async () => { stderr: "pipe", env, }); - const err2 = stderrForInstall(await new Response(stderr2).text()); + const err2 = await new Response(stderr2).text(); expect(err2.split(/\r?\n/)).toEqual([""]); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([ @@ -336,7 +335,7 @@ it("should link scoped package", async () => { stderr: "pipe", env, }); - const err3 = stderrForInstall(await new Response(stderr3).text()); + const err3 = await new Response(stderr3).text(); expect(err3.split(/\r?\n/)).toEqual([""]); expect(await new Response(stdout3).text()).toContain(`success: unlinked package "${link_name}"`); expect(await exited3).toBe(0); @@ -353,7 +352,7 @@ it("should link scoped package", async () => { stderr: "pipe", env, }); - const err4 = stderrForInstall(await new Response(stderr4).text()); + const err4 = await new Response(stderr4).text(); expect(err4).toContain(`error: Package "${link_name}" is not linked`); expect((await new Response(stdout4).text()).split(/\r?\n/)).toEqual([expect.stringContaining("bun link v1."), ""]); expect(await exited4).toBe(1); @@ -396,13 +395,13 @@ it("should link dependency without crashing", async () => { stderr: "pipe", env, }); - const err1 = stderrForInstall(await new Response(stderr1).text()); + const err1 = await new Response(stderr1).text(); expect(err1.split(/\r?\n/)).toEqual([""]); expect(await new Response(stdout1).text()).toContain(`Success! Registered "${link_name}"`); expect(await exited1).toBe(0); const { out: stdout2, err: stderr2, exited: exited2 } = await runBunInstall(env, package_dir); - const err2 = stderrForInstall(await new Response(stderr2).text()); + const err2 = await new Response(stderr2).text(); expect(err2.split(/\r?\n/).slice(-2)).toEqual(["Saved lockfile", ""]); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([ @@ -441,7 +440,7 @@ it("should link dependency without crashing", async () => { stderr: "pipe", env, }); - const err3 = stderrForInstall(await new Response(stderr3).text()); + const err3 = await new Response(stderr3).text(); expect(err3.split(/\r?\n/)).toEqual([""]); expect(await new Response(stdout3).text()).toContain(`success: unlinked package "${link_name}"`); expect(await exited3).toBe(0); @@ -458,7 +457,7 @@ it("should link dependency without crashing", async () => { stderr: "pipe", env, }); - const err4 = stderrForInstall(await new Response(stderr4).text()); + const err4 = await new Response(stderr4).text(); expect(err4).toContain(`FileNotFound: failed linking dependency/workspace to node_modules for package ${link_name}`); const out4 = await new Response(stdout4).text(); expect(out4.replace(/\[[0-9\.]+m?s\]/, "[]").split(/\r?\n/)).toEqual([ diff --git a/test/cli/install/bun-lockb.test.ts b/test/cli/install/bun-lockb.test.ts index 60a59f10a057..b7515bf04663 100644 --- a/test/cli/install/bun-lockb.test.ts +++ b/test/cli/install/bun-lockb.test.ts @@ -1,7 +1,7 @@ import { file, spawn, write } from "bun"; import { afterAll, beforeAll, expect, it } from "bun:test"; import { copyFile, exists, open, rm, writeFile } from "fs/promises"; -import { bunExe, bunEnv as env, isWindows, runBunInstall, stderrForInstall, VerdaccioRegistry } from "harness"; +import { bunExe, bunEnv as env, isWindows, runBunInstall, VerdaccioRegistry } from "harness"; import { join } from "path"; const registry = new VerdaccioRegistry(); @@ -161,8 +161,7 @@ it("recovers from a corrupted binary lockfile instead of panicking", async () => stderr: "pipe", env, }); - const [out, rawErr, code] = await Promise.all([stdout.text(), stderr.text(), exited]); - const err = stderrForInstall(rawErr); + const [out, err, code] = await Promise.all([stdout.text(), stderr.text(), exited]); // The garbage `meta.id` deserialized from the corrupt lockfile used to // panic_bounds_check in Package::clone. Released Bun tolerates it: it @@ -247,8 +246,7 @@ index d156130662798530e852e1afaec5b1c03d429cdc..b4ddf35975a952fdaed99f2b14236519 stderr: "pipe", env, }); - const [out, rawErr, code] = await Promise.all([stdout.text(), stderr.text(), exited]); - const err = stderrForInstall(rawErr); + const [out, err, code] = await Promise.all([stdout.text(), stderr.text(), exited]); // The out-of-range flag byte must fail lockfile parsing so the install // falls back to a fresh resolve instead of consuming the bad byte. @@ -306,8 +304,7 @@ it("rejects a binary lockfile whose package scripts flag byte is out of range", stderr: "pipe", env, }); - const [out, rawErr, code] = await Promise.all([stdout.text(), stderr.text(), exited]); - const err = stderrForInstall(rawErr); + const [out, err, code] = await Promise.all([stdout.text(), stderr.text(), exited]); expect(err).toContain("invalid package scripts"); expect(err).toContain("Ignoring lockfile"); @@ -362,8 +359,7 @@ it("rejects a binary lockfile whose git resolved tag contains path separators", stderr: "pipe", env: installEnv, }); - const [out, rawErr, code] = await Promise.all([stdout.text(), stderr.text(), exited]); - const err = stderrForInstall(rawErr); + const [out, err, code] = await Promise.all([stdout.text(), stderr.text(), exited]); expect(err).toContain("Saved lockfile"); expect(err).not.toContain("error:"); expect(out).toBeDefined(); @@ -384,8 +380,7 @@ it("rejects a binary lockfile whose git resolved tag contains path separators", stderr: "pipe", env: installEnv, }); - const [out, rawErr, code] = await Promise.all([stdout.text(), stderr.text(), exited]); - const err = stderrForInstall(rawErr); + const [out, err, code] = await Promise.all([stdout.text(), stderr.text(), exited]); expect(err).not.toContain("Invalid git dependency tag"); expect(err).not.toContain("error:"); expect(out).toBeDefined(); @@ -412,8 +407,7 @@ it("rejects a binary lockfile whose git resolved tag contains path separators", stderr: "pipe", env: installEnv, }); - const [out, rawErr, code] = await Promise.all([stdout.text(), stderr.text(), exited]); - const err = stderrForInstall(rawErr); + const [out, err, code] = await Promise.all([stdout.text(), stderr.text(), exited]); // The tampered resolved value must fail binary lockfile loading (the same // fail-closed rule the text lockfile parser applies) instead of flowing into diff --git a/test/cli/install/bun-publish.test.ts b/test/cli/install/bun-publish.test.ts index 1306b9e93e2d..1bd43061a922 100644 --- a/test/cli/install/bun-publish.test.ts +++ b/test/cli/install/bun-publish.test.ts @@ -1,16 +1,7 @@ import { file, spawn, write } from "bun"; import { afterAll, beforeAll, describe, expect, it, test } from "bun:test"; import { exists, rm } from "fs/promises"; -import { - VerdaccioRegistry, - bunExe, - bunEnv as env, - isWindows, - pack, - runBunInstall, - stderrForInstall, - tmpdirSync, -} from "harness"; +import { VerdaccioRegistry, bunExe, bunEnv as env, isWindows, pack, runBunInstall, tmpdirSync } from "harness"; import { join } from "path"; const registry = new VerdaccioRegistry(); @@ -36,9 +27,7 @@ export async function publish( env, }); - const out = await stdout.text(); - const err = stderrForInstall(await stderr.text()); - const exitCode = await exited; + const [out, err, exitCode] = await Promise.all([stdout.text(), stderr.text(), exited]); return { out, err, exitCode }; } diff --git a/test/cli/install/bun-run-dir.test.ts b/test/cli/install/bun-run-dir.test.ts index d4b6b81ae830..e2a259cda2ac 100644 --- a/test/cli/install/bun-run-dir.test.ts +++ b/test/cli/install/bun-run-dir.test.ts @@ -1,7 +1,7 @@ import { file, spawn } from "bun"; import { expect, it } from "bun:test"; import { exists, writeFile } from "fs/promises"; -import { bunExe, bunEnv as env, readdirSorted, stderrForInstall, tmpdirSync } from "harness"; +import { bunExe, bunEnv as env, readdirSorted, tmpdirSync } from "harness"; import { join } from "path"; it.concurrent("should download dependency to run local file", async () => { @@ -29,7 +29,7 @@ console.log(minify("print(6 * 7)").code); BUN_INSTALL_CACHE_DIR: join(run_dir, ".cache"), }, }); - const err1 = stderrForInstall(await new Response(stderr1).text()); + const err1 = await new Response(stderr1).text(); expect(err1).toBe(""); expect(await readdirSorted(run_dir)).toEqual([".cache", "test.js"]); expect(await readdirSorted(join(run_dir, ".cache"))).toContain("uglify-js"); @@ -54,7 +54,7 @@ console.log(minify("print(6 * 7)").code); BUN_INSTALL_CACHE_DIR: join(run_dir, ".cache"), }, }); - const err2 = stderrForInstall(await new Response(stderr2).text()); + const err2 = await new Response(stderr2).text(); expect(err2).toBe(""); expect(await readdirSorted(run_dir)).toEqual([".cache", "test.js"]); expect(await readdirSorted(join(run_dir, ".cache"))).toContain("uglify-js"); @@ -94,7 +94,7 @@ for (const entry of await decompress(Buffer.from(buffer))) { BUN_INSTALL_CACHE_DIR: join(run_dir, ".cache"), }, }); - const err1 = stderrForInstall(await new Response(stderr1).text()); + const err1 = await new Response(stderr1).text(); expect(err1).toBe(""); expect(await readdirSorted(run_dir)).toEqual([".cache", "test.js"]); expect(await readdirSorted(join(run_dir, ".cache"))).toContain("decompress"); @@ -128,7 +128,7 @@ for (const entry of await decompress(Buffer.from(buffer))) { }, }); const err2 = await new Response(stderr2).text(); - if (err2) throw new Error(err2); + expect(err2).toBe(""); expect(await readdirSorted(run_dir)).toEqual([".cache", "test.js"]); expect(await readdirSorted(join(run_dir, ".cache"))).toContain("decompress"); expect(await readdirSorted(join(run_dir, ".cache", "decompress"))).toEqual(["4.2.1@@@1"]); diff --git a/test/cli/install/catalogs.test.ts b/test/cli/install/catalogs.test.ts index 1169bbf81b7b..08cc2b4044db 100644 --- a/test/cli/install/catalogs.test.ts +++ b/test/cli/install/catalogs.test.ts @@ -1,7 +1,7 @@ import { file, spawn, write } from "bun"; import { afterAll, beforeAll, describe, expect, test } from "bun:test"; import { exists } from "fs/promises"; -import { VerdaccioRegistry, bunEnv, bunExe, runBunInstall, stderrForInstall } from "harness"; +import { VerdaccioRegistry, bunEnv, bunExe, runBunInstall } from "harness"; import { join } from "path"; var registry = new VerdaccioRegistry(); @@ -222,7 +222,7 @@ describe("update", () => { }); const [out, err, exitCode] = await Promise.all([stdout.text(), stderr.text(), exited]); - return { out, err: stderrForInstall(err), exitCode }; + return { out, err, exitCode }; } // https://github.com/oven-sh/bun/issues/23739 @@ -279,8 +279,7 @@ describe("update", () => { stderr: "pipe", env: bunEnv, }); - const [, errText, exitCode] = await Promise.all([stdout.text(), stderr.text(), exited]); - const err = stderrForInstall(errText); + const [, err, exitCode] = await Promise.all([stdout.text(), stderr.text(), exited]); expect(err).not.toContain("lockfile had changes"); expect(err).not.toContain("error:"); expect(exitCode).toBe(0); @@ -545,7 +544,7 @@ describe("errors", () => { }); const out = await stdout.text(); - const err = stderrForInstall(await stderr.text()); + const err = await stderr.text(); expect(err).toContain("no-deps@catalog: failed to resolve"); expect(err).toContain("a-dep@catalog:aaaaaaaaaaaaaaaaa failed to resolve"); @@ -577,7 +576,7 @@ describe("errors", () => { }); const out = await stdout.text(); - const err = stderrForInstall(await stderr.text()); + const err = await stderr.text(); expect(err).toContain("no-deps@catalog: failed to resolve"); }); diff --git a/test/cli/install/config-version.test.ts b/test/cli/install/config-version.test.ts index 40924857f4ff..3a37dec5b2a7 100644 --- a/test/cli/install/config-version.test.ts +++ b/test/cli/install/config-version.test.ts @@ -1,7 +1,7 @@ import { file, spawn } from "bun"; import { describe, expect, test } from "bun:test"; import { exists } from "fs/promises"; -import { bunEnv, bunExe, normalizeBunSnapshot, stderrForInstall, tempDir } from "harness"; +import { bunEnv, bunExe, normalizeBunSnapshot, tempDir } from "harness"; import { join } from "path"; // These tests cover the `configVersion` field in bun.lock and the linker @@ -18,7 +18,7 @@ async function install(cwd: string) { stderr: "pipe", }); const [out, err, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); - return { out, err: stderrForInstall(err), exitCode }; + return { out, err, exitCode }; } describe.concurrent("configVersion", () => { diff --git a/test/cli/install/npmrc.test.ts b/test/cli/install/npmrc.test.ts index 2100be7ce978..8a3793c19019 100644 --- a/test/cli/install/npmrc.test.ts +++ b/test/cli/install/npmrc.test.ts @@ -1,7 +1,7 @@ import { write } from "bun"; import { afterAll, beforeAll, describe, expect, it, test } from "bun:test"; import { rm } from "fs/promises"; -import { VerdaccioRegistry, bunExe, bunEnv as env, stderrForInstall, tempDir } from "harness"; +import { VerdaccioRegistry, bunExe, bunEnv as env, tempDir } from "harness"; import { join } from "path"; const { iniInternals } = require("bun:internal-for-testing"); const { loadNpmrc } = iniInternals; @@ -40,7 +40,7 @@ describe("npmrc", async () => { env.BUN_INSTALL_CACHE_DIR = originalCacheDir; const out = await stdout.text(); - const err = stderrForInstall(await stderr.text()); + const err = await stderr.text(); console.log({ out, err }); expect(err).toBeEmpty(); expect(out.endsWith("hi!")).toBeTrue(); diff --git a/test/harness.ts b/test/harness.ts index ae197e7bbba2..ae512f9a5ba7 100644 --- a/test/harness.ts +++ b/test/harness.ts @@ -74,6 +74,9 @@ export const bunEnv: NodeJS.Dict = { CI: "1", BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0", BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "1", + // The `bun install` "Slow filesystem detected" warning is timing-dependent + // and flakes stderr assertions on slow CI filesystems. + BUN_DISABLE_SLOW_FILESYSTEM_WARNING: "1", // Tests drive `bun update --interactive` by writing keystrokes to a pipe; // the real command refuses on non-TTY stdin. Bypass that gate under test. BUN_INTERNAL_INTERACTIVE_ASSUME_TTY: "1", @@ -1495,7 +1498,7 @@ export async function runBunInstall( }); expect(stdout).toBeDefined(); expect(stderr).toBeDefined(); - let err: string = stderrForInstall(await stderr.text()); + const [err, out, exitCode] = await Promise.all([stderr.text(), stdout.text(), exited]); expect(err).not.toContain("panic:"); if (!options?.allowErrors) { expect(err).not.toContain("error:"); @@ -1506,16 +1509,10 @@ export async function runBunInstall( if ((options?.savesLockfile ?? true) && !production && !options?.frozenLockfile) { expect(err).toContain("Saved lockfile"); } - let out: string = await stdout.text(); - expect(await exited).toBe(options?.expectedExitCode ?? 0); + expect(exitCode).toBe(options?.expectedExitCode ?? 0); return { out, err, exited }; } -// stderr with `slow filesystem` warning removed -export function stderrForInstall(err: string) { - return err.replace(/warn: Slow filesystem.*/g, ""); -} - export async function runBunUpdate( env: NodeJS.ProcessEnv, cwd: string,