diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index dc1fc60037..dcc1cf9fa8 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -2592,7 +2592,7 @@ pub const Subprocess = struct { .err => |err| { std.debug.print("waitpid error: {s}\n", .{@tagName(err.getErrno())}); Output.prettyErrorln("error: Failed to run {s} script from \"{s}\" due to error {d} {s}", .{ - lifecycle_script_subprocess.script_name, + lifecycle_script_subprocess.scriptName(), lifecycle_script_subprocess.package_name, err.errno, @tagName(err.getErrno()), diff --git a/src/bun.zig b/src/bun.zig index 7db95f80c8..87af417bf9 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -769,6 +769,69 @@ pub const fmt = struct { const Formatter = HexIntFormatter(@TypeOf(value), false); return Formatter{ .value = value }; } + + const FormatDurationData = struct { + ns: u64, + negative: bool = false, + }; + + /// This is copied from std.fmt.formatDuration, except it will only print one decimal instead of three + fn formatDurationOneDecimal(data: FormatDurationData, comptime _: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24 + var buf: [24]u8 = undefined; + var fbs = std.io.fixedBufferStream(&buf); + var buf_writer = fbs.writer(); + if (data.negative) { + buf_writer.writeByte('-') catch unreachable; + } + + var ns_remaining = data.ns; + inline for (.{ + .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' }, + .{ .ns = std.time.ns_per_week, .sep = 'w' }, + .{ .ns = std.time.ns_per_day, .sep = 'd' }, + .{ .ns = std.time.ns_per_hour, .sep = 'h' }, + .{ .ns = std.time.ns_per_min, .sep = 'm' }, + }) |unit| { + if (ns_remaining >= unit.ns) { + const units = ns_remaining / unit.ns; + std.fmt.formatInt(units, 10, .lower, .{}, buf_writer) catch unreachable; + buf_writer.writeByte(unit.sep) catch unreachable; + ns_remaining -= units * unit.ns; + if (ns_remaining == 0) + return std.fmt.formatBuf(fbs.getWritten(), opts, writer); + } + } + + inline for (.{ + .{ .ns = std.time.ns_per_s, .sep = "s" }, + .{ .ns = std.time.ns_per_ms, .sep = "ms" }, + .{ .ns = std.time.ns_per_us, .sep = "us" }, + }) |unit| { + const kunits = ns_remaining * 1000 / unit.ns; + if (kunits >= 1000) { + std.fmt.formatInt(kunits / 1000, 10, .lower, .{}, buf_writer) catch unreachable; + const frac = @divFloor(kunits % 1000, 100); + if (frac > 0) { + var decimal_buf = [_]u8{ '.', 0 }; + _ = std.fmt.formatIntBuf(decimal_buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 1 }); + buf_writer.writeAll(&decimal_buf) catch unreachable; + } + buf_writer.writeAll(unit.sep) catch unreachable; + return std.fmt.formatBuf(fbs.getWritten(), opts, writer); + } + } + + std.fmt.formatInt(ns_remaining, 10, .lower, .{}, buf_writer) catch unreachable; + buf_writer.writeAll("ns") catch unreachable; + return std.fmt.formatBuf(fbs.getWritten(), opts, writer); + } + + /// Return a Formatter for number of nanoseconds according to its magnitude: + /// [#y][#w][#d][#h][#m]#[.###][n|u|m]s + pub fn fmtDurationOneDecimal(ns: u64) std.fmt.Formatter(formatDurationOneDecimal) { + return .{ .data = FormatDurationData{ .ns = ns } }; + } }; pub const Output = @import("./output.zig"); diff --git a/src/cli/run_command.zig b/src/cli/run_command.zig index 327dd4daae..c1a9e7f67f 100644 --- a/src/cli/run_command.zig +++ b/src/cli/run_command.zig @@ -263,26 +263,6 @@ pub const RunCommand = struct { const log = Output.scoped(.RUN, false); - pub fn spawnPackageScripts( - manager: *PackageManager, - list: Lockfile.Package.Scripts.List, - envp: [:null]?[*:0]u8, - ) !void { - var lifecycle_subprocess = try manager.allocator.create(LifecycleScriptSubprocess); - lifecycle_subprocess.scripts = list.items; - lifecycle_subprocess.manager = manager; - lifecycle_subprocess.envp = envp; - - lifecycle_subprocess.spawnNextScript(list.first_index) catch |err| { - Output.prettyErrorln("error: Failed to run script {s} due to error {s}", .{ - Lockfile.Scripts.names[list.first_index], - @errorName(err), - }); - }; - - _ = manager.pending_lifecycle_script_tasks.fetchAdd(1, .Monotonic); - } - pub fn runPackageScriptForeground( allocator: std.mem.Allocator, original_script: string, diff --git a/src/install/install.zig b/src/install/install.zig index eb2a309d59..131096f029 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1889,9 +1889,12 @@ pub const PackageManager = struct { preallocated_network_tasks: PreallocatedNetworkTasks = .{ .buffer = undefined, .len = 0 }, pending_tasks: u32 = 0, total_tasks: u32 = 0, + + /// items are only inserted into this if they took more than 500ms + lifecycle_script_time_log: LifecycleScriptTimeLog = .{}, + pending_lifecycle_script_tasks: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), finished_installing: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), - total_scripts: usize = 0, root_lifecycle_scripts: ?Package.Scripts.List = null, @@ -1943,6 +1946,56 @@ pub const PackageManager = struct { pub var last_time: c_longlong = -1; }; + pub const LifecycleScriptTimeLog = struct { + const Entry = struct { + package_name: []const u8, + script_id: u8, + + // nanosecond duration + duration: u64, + }; + + mutex: std.Thread.Mutex = .{}, + list: std.ArrayListUnmanaged(Entry) = .{}, + + pub fn appendConcurrent(log: *LifecycleScriptTimeLog, allocator: std.mem.Allocator, entry: Entry) void { + log.mutex.lock(); + defer log.mutex.unlock(); + log.list.append(allocator, entry) catch bun.outOfMemory(); + } + + /// this can be called if .start was never called + pub fn printAndDeinit(log: *LifecycleScriptTimeLog, allocator: std.mem.Allocator) void { + if (Environment.isDebug) { + if (!log.mutex.tryLock()) @panic("LifecycleScriptTimeLog.print is not intended to be thread-safe"); + log.mutex.unlock(); + } + + if (log.list.items.len > 0) { + const longest: Entry = longest: { + var i: usize = 0; + var longest: u64 = log.list.items[0].duration; + for (log.list.items[1..], 1..) |item, j| { + if (item.duration > longest) { + i = j; + longest = item.duration; + } + } + break :longest log.list.items[i]; + }; + + // extra \n will print a blank line after this one + Output.warn("{s}'s {s} script took {}\n\n", .{ + longest.package_name, + Lockfile.Scripts.names[longest.script_id], + bun.fmt.fmtDurationOneDecimal(longest.duration), + }); + Output.flush(); + } + log.list.deinit(allocator); + } + }; + pub fn hasEnoughTimePassedBetweenWaitingMessages() bool { const iter = instance.uws_event_loop.iterationNumber(); if (TimePasser.last_time < iter) { @@ -9276,6 +9329,8 @@ pub const PackageManager = struct { }, } + manager.lifecycle_script_time_log.printAndDeinit(manager.lockfile.allocator); + if (!did_meta_hash_change) { manager.summary.remove = 0; manager.summary.add = 0; @@ -9291,7 +9346,7 @@ pub const PackageManager = struct { @truncate(manager.package_json_updates.len), ), ); - Output.pretty("\n {d} package{s} installed ", .{ pkgs_installed, if (pkgs_installed == 1) "" else "s" }); + Output.pretty(" {d} package{s} installed ", .{ pkgs_installed, if (pkgs_installed == 1) "" else "s" }); Output.printStartEndStdout(ctx.start_time, std.time.nanoTimestamp()); printed_timestamp = true; Output.pretty("\n", .{}); @@ -9306,13 +9361,11 @@ pub const PackageManager = struct { } } - Output.pretty("\n {d} package{s} removed ", .{ manager.summary.remove, if (manager.summary.remove == 1) "" else "s" }); + Output.pretty(" {d} package{s} removed ", .{ manager.summary.remove, if (manager.summary.remove == 1) "" else "s" }); Output.printStartEndStdout(ctx.start_time, std.time.nanoTimestamp()); printed_timestamp = true; Output.pretty("\n", .{}); } else if (install_summary.skipped > 0 and install_summary.fail == 0 and manager.package_json_updates.len == 0) { - Output.pretty("\n", .{}); - const count = @as(PackageID, @truncate(manager.lockfile.packages.len)); if (count != install_summary.skipped) { Output.pretty("Checked {d} install{s} across {d} package{s} (no changes) ", .{ @@ -9363,8 +9416,8 @@ pub const PackageManager = struct { ) !void { var uses_node_gyp = false; var any_scripts = false; - for (list.items) |_item| { - if (_item) |item| { + for (list.items) |maybe_item| { + if (maybe_item) |item| { any_scripts = true; // to be safe, add the temporary script for any usage // of the string `node-gyp`. @@ -9377,7 +9430,6 @@ pub const PackageManager = struct { if (!any_scripts) { return; } - if (uses_node_gyp) { try this.ensureTempNodeGypScript(); } diff --git a/src/install/lifecycle_script_runner.zig b/src/install/lifecycle_script_runner.zig index 93b893a763..6af3686601 100644 --- a/src/install/lifecycle_script_runner.zig +++ b/src/install/lifecycle_script_runner.zig @@ -9,13 +9,13 @@ const Output = bun.Output; const Global = bun.Global; const JSC = bun.JSC; const WaiterThread = JSC.Subprocess.WaiterThread; +const Timer = std.time.Timer; pub const LifecycleScriptSubprocess = struct { - script_name: []const u8, package_name: []const u8, scripts: [6]?Lockfile.Scripts.Entry, - current_script_index: usize = 0, + current_script_index: u8 = 0, finished_fds: u8 = 0, @@ -28,6 +28,10 @@ pub const LifecycleScriptSubprocess = struct { manager: *PackageManager, envp: [:null]?[*:0]u8, + timer: ?Timer = null, + + pub const min_milliseconds_to_log = 500; + pub var alive_count: std.atomic.Value(usize) = std.atomic.Value(usize).init(0); /// A "nothing" struct that lets us reuse the same pointer @@ -81,7 +85,7 @@ pub const LifecycleScriptSubprocess = struct { switch (this.poll.register(this.subprocess().manager.uws_event_loop, .readable, true)) { .err => |err| { Output.prettyErrorln("error: Failed to register poll for {s} script output from \"{s}\" due to error {d} {s}", .{ - this.subprocess().script_name, + this.subprocess().scriptName(), this.subprocess().package_name, err.errno, @tagName(err.getErrno()), @@ -109,6 +113,11 @@ pub const LifecycleScriptSubprocess = struct { } }; + pub fn scriptName(this: *const LifecycleScriptSubprocess) []const u8 { + std.debug.assert(this.current_script_index < Lockfile.Scripts.names.len); + return Lockfile.Scripts.names[this.current_script_index]; + } + pub fn onOutputDone(this: *LifecycleScriptSubprocess) void { std.debug.assert(this.finished_fds < 2); this.finished_fds += 1; @@ -126,7 +135,7 @@ pub const LifecycleScriptSubprocess = struct { this.finished_fds += 1; Output.prettyErrorln("error: Failed to read {s} script output from \"{s}\" due to error {d} {s}", .{ - this.script_name, + this.scriptName(), this.package_name, err.errno, @tagName(err.getErrno()), @@ -140,7 +149,7 @@ pub const LifecycleScriptSubprocess = struct { } } - pub fn spawnNextScript(this: *LifecycleScriptSubprocess, next_script_index: usize) !void { + pub fn spawnNextScript(this: *LifecycleScriptSubprocess, next_script_index: u8) !void { if (Environment.isWindows) { @panic("TODO"); } @@ -152,7 +161,6 @@ pub const LifecycleScriptSubprocess = struct { const original_script = this.scripts[next_script_index].?; const cwd = original_script.cwd; const env = manager.env; - const name = Lockfile.Scripts.names[next_script_index]; if (manager.scripts_node) |scripts_node| { if (manager.finished_installing.load(.Monotonic)) { @@ -167,7 +175,6 @@ pub const LifecycleScriptSubprocess = struct { } } - this.script_name = name; this.package_name = original_script.package_name; this.current_script_index = next_script_index; this.waitpid_result = null; @@ -184,7 +191,7 @@ pub const LifecycleScriptSubprocess = struct { var argv = [_]?[*:0]const u8{ shell_bin, - "-c", + if (Environment.isWindows) "/c" else "-c", combined_script, null, }; @@ -215,6 +222,9 @@ pub const LifecycleScriptSubprocess = struct { _ = bun.sys.close(fdsOut[1]); _ = bun.sys.close(fdsErr[1]); } + + this.timer = Timer.start() catch null; + switch (PosixSpawn.spawnZ( argv[0].?, actions, @@ -224,7 +234,7 @@ pub const LifecycleScriptSubprocess = struct { )) { .err => |err| { Output.prettyErrorln("error: Failed to spawn script {s} due to error {d} {s}", .{ - name, + this.scriptName(), err.errno, @tagName(err.getErrno()), }); @@ -281,7 +291,7 @@ pub const LifecycleScriptSubprocess = struct { _ = std.os.linux.waitpid(pid, &status, 0); Output.prettyErrorln("error: Failed to spawn script {s} due to error {d} {s}", .{ - name, + this.scriptName(), err, @tagName(err), }); @@ -360,7 +370,7 @@ pub const LifecycleScriptSubprocess = struct { switch (PosixSpawn.waitpid(this.pid, std.os.W.NOHANG)) { .err => |err| { Output.prettyErrorln("error: Failed to run {s} script from \"{s}\" due to error {d} {s}", .{ - this.script_name, + this.scriptName(), this.package_name, err.errno, @tagName(err.getErrno()), @@ -386,7 +396,7 @@ pub const LifecycleScriptSubprocess = struct { _ = alive_count.fetchSub(1, .Monotonic); if (result.pid == 0) { Output.prettyErrorln("error: Failed to run {s} script from \"{s}\" due to error {d} {s}", .{ - this.script_name, + this.scriptName(), this.package_name, 0, "Unknown", @@ -398,6 +408,8 @@ pub const LifecycleScriptSubprocess = struct { } if (std.os.W.IFEXITED(result.status)) { std.debug.assert(this.finished_fds <= 2); + const maybe_duration = if (this.timer) |*t| t.read() else null; + if (this.finished_fds < 2) { this.waitpid_result = result; return; @@ -406,8 +418,8 @@ pub const LifecycleScriptSubprocess = struct { const code = std.os.W.EXITSTATUS(result.status); if (code > 0) { this.printOutput(); - Output.errGeneric("{s} script from \"{s}\" exited with code {d}", .{ - this.script_name, + Output.prettyErrorln("error: {s} script from \"{s}\" exited with {any}", .{ + this.scriptName(), this.package_name, code, }); @@ -424,11 +436,24 @@ pub const LifecycleScriptSubprocess = struct { } } + if (maybe_duration) |nanos| { + if (nanos > min_milliseconds_to_log * std.time.ns_per_ms) { + this.manager.lifecycle_script_time_log.appendConcurrent( + this.manager.lockfile.allocator, + .{ + .package_name = this.package_name, + .script_id = this.current_script_index, + .duration = nanos, + }, + ); + } + } + for (this.current_script_index + 1..Lockfile.Scripts.names.len) |new_script_index| { if (this.scripts[new_script_index] != null) { this.resetPolls(); - this.spawnNextScript(new_script_index) catch |err| { - Output.prettyErrorln("error: Failed to run script {s} due to error {s}", .{ + this.spawnNextScript(@intCast(new_script_index)) catch |err| { + Output.errGeneric("Failed to run script {s} due to error {s}", .{ Lockfile.Scripts.names[new_script_index], @errorName(err), }); @@ -444,6 +469,7 @@ pub const LifecycleScriptSubprocess = struct { if (this.finished_fds == 2) { this.deinit(); } + return; } if (std.os.W.IFSIGNALED(result.status)) { @@ -455,7 +481,7 @@ pub const LifecycleScriptSubprocess = struct { } this.printOutput(); Output.prettyErrorln("error: {s} script from \"{s}\" terminated by {}", .{ - this.script_name, + this.scriptName(), this.package_name, bun.SignalCode.from(signal).fmt(Output.enable_ansi_colors_stderr), }); @@ -470,14 +496,19 @@ pub const LifecycleScriptSubprocess = struct { } this.printOutput(); Output.prettyErrorln("error: {s} script from \"{s}\" was stopped by {}", .{ - this.script_name, + this.scriptName(), this.package_name, bun.SignalCode.from(signal).fmt(Output.enable_ansi_colors_stderr), }); Global.raiseIgnoringPanicHandler(signal); } - std.debug.panic("{s} script from \"{s}\" hit unexpected state {{ .pid = {d}, .status = {d} }}", .{ this.script_name, this.package_name, result.pid, result.status }); + std.debug.panic("{s} script from \"{s}\" hit unexpected state {{ .pid = {d}, .status = {d} }}", .{ + this.scriptName(), + this.package_name, + result.pid, + result.status, + }); } pub fn resetPolls(this: *LifecycleScriptSubprocess) void { diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index 125206b6b5..2fbe5660b1 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -1128,6 +1128,8 @@ pub const Printer = struct { } pub const Tree = struct { + /// - Prints an empty newline with no diffs + /// - Prints a leading and trailing blank newline with diffs pub fn print( this: *Printer, comptime Writer: type, @@ -1154,6 +1156,9 @@ pub const Printer = struct { visited.set(0); const end = @as(PackageID, @truncate(resolved.len)); + try writer.writeAll("\n"); + + var had_printed_new_install = false; if (this.successfully_installed) |installed| { var dep_id = resolutions_list[0].off; const dep_end = dep_id + resolutions_list[0].len; @@ -1179,6 +1184,10 @@ pub const Printer = struct { if (!installed.isSet(package_id)) continue; + if (!had_printed_new_install) { + had_printed_new_install = true; + } + if (PackageManager.instance.formatLaterVersionInCache(package_name, dependency.name_hash, resolved[package_id])) |later_version_fmt| { const fmt = comptime brk: { if (enable_ansi_colors) { @@ -1242,12 +1251,16 @@ pub const Printer = struct { } } - if (this.updates.len > 0) { + if (had_printed_new_install) { try writer.writeAll("\n"); } + if (bun.Environment.allow_assert) had_printed_new_install = false; + for (id_map) |dependency_id| { if (dependency_id == invalid_package_id) continue; + if (bun.Environment.allow_assert) had_printed_new_install = true; + const name = dependencies_buffer[dependency_id].name; const package_id = resolutions_buffer[dependency_id]; const bin = bins[package_id]; @@ -1256,16 +1269,10 @@ pub const Printer = struct { switch (bin.tag) { .none, .dir => { - const fmt = comptime brk: { - if (enable_ansi_colors) { - break :brk Output.prettyFmt(" installed {s}@{}\n", enable_ansi_colors); - } else { - break :brk Output.prettyFmt(" installed {s}@{}\n", enable_ansi_colors); - } - }; + const fmt = comptime Output.prettyFmt(" installed {s}@{}\n", enable_ansi_colors); try writer.print( - comptime Output.prettyFmt(fmt, enable_ansi_colors), + fmt, .{ package_name, resolved[package_id].fmt(string_buf), @@ -1280,16 +1287,10 @@ pub const Printer = struct { .extern_string_buf = this.lockfile.buffers.extern_strings.items, }; - const fmt = comptime brk: { - if (enable_ansi_colors) { - break :brk Output.prettyFmt(" installed {s}@{} with binaries:\n", enable_ansi_colors); - } else { - break :brk Output.prettyFmt(" installed {s}@{} with binaries:\n", enable_ansi_colors); - } - }; + const fmt = comptime Output.prettyFmt(" installed {s}@{} with binaries:\n", enable_ansi_colors); try writer.print( - comptime Output.prettyFmt(fmt, enable_ansi_colors), + fmt, .{ package_name, resolved[package_id].fmt(string_buf), @@ -1308,6 +1309,11 @@ pub const Printer = struct { } } + // updates.len > 0 is a simpler check than to keep track of a boolean + // this assert ensures it is accurate. + if (bun.Environment.allow_assert) + std.debug.assert(had_printed_new_install == (this.updates.len > 0)); + if (this.updates.len > 0) { try writer.writeAll("\n"); } diff --git a/test/cli/install/bun-add.test.ts b/test/cli/install/bun-add.test.ts index aeca053b51..5385be8f2c 100644 --- a/test/cli/install/bun-add.test.ts +++ b/test/cli/install/bun-add.test.ts @@ -70,7 +70,6 @@ it("should add existing package", async () => { "", ` installed foo@${add_path}`, "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -280,7 +279,6 @@ it("should add dependency with capital letters", async () => { "", " installed BaR@0.0.2", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -336,7 +334,6 @@ it("should add exact version with --exact", async () => { "", " installed BaR@0.0.2", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -393,7 +390,6 @@ it("should add exact version with install.exact", async () => { "", " installed BaR@0.0.2", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -448,7 +444,6 @@ it("should add exact version with -E", async () => { "", " installed BaR@0.0.2", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -513,7 +508,6 @@ it("should add dependency with specified semver", async () => { " installed baz@0.0.3 with binaries:", " - baz-run", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -575,7 +569,6 @@ it("should add dependency (GitHub)", async () => { " installed uglify-js@github:mishoo/UglifyJS#e219a9a with binaries:", " - uglifyjs", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -659,12 +652,12 @@ it("should add dependency alongside workspaces", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:packages/bar", "", " installed baz@0.0.3 with binaries:", " - baz-run", "", - "", " 2 packages installed", ]); expect(await exited).toBe(0); @@ -737,7 +730,6 @@ it("should add aliased dependency (npm)", async () => { " installed bar@0.0.3 with binaries:", " - baz-run", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -799,7 +791,6 @@ it("should add aliased dependency (GitHub)", async () => { " installed uglify@github:mishoo/UglifyJS#e219a9a with binaries:", " - uglifyjs", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -884,7 +875,6 @@ it("should let you add the same package twice", async () => { "", " installed baz@0.0.3", "", - "", " 1 package installed", ]); expect(await exited1).toBe(0); @@ -1001,7 +991,6 @@ it("should install version tagged with `latest` by default", async () => { "", " installed baz@0.0.3", "", - "", " 1 package installed", ]); expect(await exited1).toBe(0); @@ -1051,6 +1040,7 @@ it("should install version tagged with `latest` by default", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@0.0.3", "", " 1 package installed", @@ -1117,7 +1107,6 @@ it("should handle Git URL in dependencies (SCP-style)", async () => { " installed uglify-js@git+ssh://bun@github.com:mishoo/UglifyJS.git with binaries:", " - uglifyjs", "", - "", " 1 package installed", ]); expect(await exited1).toBe(0); @@ -1263,7 +1252,6 @@ it("should prefer optionalDependencies over dependencies of the same name", asyn "", " installed bar@0.0.2", "", - "", " 2 packages installed", ]); expect(await exited).toBe(0); @@ -1324,7 +1312,6 @@ it("should prefer dependencies over peerDependencies of the same name", async () "", " installed bar@0.0.2", "", - "", " 2 packages installed", ]); expect(await exited).toBe(0); @@ -1383,7 +1370,6 @@ it("should add dependency without duplication", async () => { "", " installed bar@0.0.2", "", - "", " 1 package installed", ]); expect(await exited1).toBe(0); @@ -1486,7 +1472,6 @@ it("should add dependency without duplication (GitHub)", async () => { " installed uglify-js@github:mishoo/UglifyJS#e219a9a with binaries:", " - uglifyjs", "", - "", " 1 package installed", ]); expect(await exited1).toBe(0); @@ -1626,7 +1611,6 @@ it("should add dependencies to workspaces directly", async () => { "", ` installed foo@${relative(package_dir, add_dir)}`, "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -1691,7 +1675,6 @@ async function installRedirectsToAdd(saveFlagFirst: boolean) { "", ` installed foo@${add_path}`, "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -1728,7 +1711,6 @@ it("should add dependency alongside peerDependencies", async () => { "", " installed bar@0.0.2", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -1783,7 +1765,6 @@ it("should add local tarball dependency", async () => { " installed baz@baz-0.0.3.tgz with binaries:", " - baz-run", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); diff --git a/test/cli/install/bun-install.test.ts b/test/cli/install/bun-install.test.ts index ee319f160b..306554f7c6 100644 --- a/test/cli/install/bun-install.test.ts +++ b/test/cli/install/bun-install.test.ts @@ -70,6 +70,7 @@ describe("chooses", () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + baz@${chosen}`, "", " 1 package installed", @@ -279,6 +280,7 @@ it("should handle empty string in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", "", " 1 package installed", @@ -358,6 +360,7 @@ it("should handle workspaces", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @org/nominally-scoped@workspace:packages/nominally-scoped", " + Asterisk@workspace:packages/asterisk", " + AsteriskTheSecond@workspace:packages/second-asterisk", @@ -404,6 +407,7 @@ it("should handle workspaces", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @org/nominally-scoped@workspace:packages/nominally-scoped", " + Asterisk@workspace:packages/asterisk", " + AsteriskTheSecond@workspace:packages/second-asterisk", @@ -467,6 +471,7 @@ it("should handle `workspace:` specifier", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:path/to/bar", "", " 1 package installed", @@ -496,6 +501,7 @@ it("should handle `workspace:` specifier", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:path/to/bar", "", " 1 package installed", @@ -540,6 +546,7 @@ it("should handle workspaces with packages array", async () => { const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -596,6 +603,7 @@ it("should handle inter-dependency between workspaces", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", " + Baz@workspace:packages/baz", "", @@ -654,6 +662,7 @@ it("should handle inter-dependency between workspaces (devDependencies)", async expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", " + Baz@workspace:packages/baz", "", @@ -712,6 +721,7 @@ it("should handle inter-dependency between workspaces (optionalDependencies)", a expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", " + Baz@workspace:packages/baz", "", @@ -769,6 +779,7 @@ it("should ignore peerDependencies within workspaces", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Baz@workspace:packages/baz", "", " 1 package installed", @@ -812,6 +823,7 @@ it("should handle installing the same peerDependency with different versions", a expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + boba@0.0.2", "", " 2 packages installed", @@ -850,6 +862,7 @@ it("should handle installing the same peerDependency with the same version", asy expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + boba@0.0.2", "", " 1 package installed", @@ -897,6 +910,7 @@ it("should handle life-cycle scripts within workspaces", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -962,6 +976,7 @@ it("should handle life-cycle scripts during re-installation", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", " + qux@0.0.2", "", @@ -995,6 +1010,7 @@ it("should handle life-cycle scripts during re-installation", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", " + qux@0.0.2", "", @@ -1028,6 +1044,7 @@ it("should handle life-cycle scripts during re-installation", async () => { expect(stdout3).toBeDefined(); const out3 = await new Response(stdout3).text(); expect(out3.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", " + qux@0.0.2", "", @@ -1087,6 +1104,7 @@ it("should use updated life-cycle scripts in root during re-installation", async expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -1136,6 +1154,7 @@ it("should use updated life-cycle scripts in root during re-installation", async expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -1172,6 +1191,7 @@ it("should use updated life-cycle scripts in root during re-installation", async expect(stdout3).toBeDefined(); const out3 = await new Response(stdout3).text(); expect(out3.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -1231,6 +1251,7 @@ it("should use updated life-cycle scripts in dependency during re-installation", expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -1283,6 +1304,7 @@ it("should use updated life-cycle scripts in dependency during re-installation", expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -1321,6 +1343,7 @@ it("should use updated life-cycle scripts in dependency during re-installation", expect(stdout3).toBeDefined(); const out3 = await new Response(stdout3).text(); expect(out3.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@workspace:bar", "", " 1 package installed", @@ -1367,6 +1390,7 @@ it("should ignore workspaces within workspaces", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", "", " 1 package installed", @@ -1405,6 +1429,7 @@ it("should handle ^0 in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", "", " 1 package installed", @@ -1485,6 +1510,7 @@ it("should handle ^0.0 in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", "", " 1 package installed", @@ -1603,6 +1629,7 @@ it("should handle ^0.0.2 in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", "", " 1 package installed", @@ -1670,6 +1697,7 @@ it("should handle matching workspaces from dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + pkg1@workspace:packages/pkg1", " + pkg2@workspace:packages/pkg2", "", @@ -1798,6 +1826,7 @@ it("should handle ^0.0.2-rc in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2-rc", "", " 1 package installed", @@ -1842,6 +1871,7 @@ it("should handle ^0.0.2-alpha.3+b4d in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2-alpha.3", "", " 1 package installed", @@ -1886,6 +1916,7 @@ it("should choose the right version with prereleases", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2-alpha.3", "", " 1 package installed", @@ -1930,6 +1961,7 @@ it("should handle ^0.0.2rc1 in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2-rc1", "", " 1 package installed", @@ -1974,6 +2006,7 @@ it("should handle ^0.0.2_pre3 in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2-_pre3", "", " 1 package installed", @@ -2018,6 +2051,7 @@ it("should handle ^0.0.2b_4+cafe_b0ba in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2-b_4+cafe_b0ba", "", " 1 package installed", @@ -2062,6 +2096,7 @@ it("should handle caret range in dependencies when the registry has prereleased expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@6.3.0", "", " 1 package installed", @@ -2119,6 +2154,7 @@ it("should prefer latest-tagged dependency", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@0.0.3", "", " 1 package installed", @@ -2174,7 +2210,6 @@ it("should install latest with prereleases", async () => { "", " installed baz@1.0.0-0", "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -2204,7 +2239,12 @@ it("should install latest with prereleases", async () => { expect(err).toContain("Saved lockfile"); expect(stdout).toBeDefined(); out = await new Response(stdout).text(); - expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\n/)).toEqual([" + baz@1.0.0-0", "", " 1 package installed"]); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\n/)).toEqual([ + "", + " + baz@1.0.0-0", + "", + " 1 package installed", + ]); expect(await exited).toBe(0); await rm(join(package_dir, "node_modules"), { recursive: true, force: true }); await rm(join(package_dir, "bun.lockb"), { recursive: true, force: true }); @@ -2231,7 +2271,12 @@ it("should install latest with prereleases", async () => { expect(err).toContain("Saved lockfile"); expect(stdout).toBeDefined(); out = await new Response(stdout).text(); - expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\n/)).toEqual([" + baz@1.0.0-8", "", " 1 package installed"]); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\n/)).toEqual([ + "", + " + baz@1.0.0-8", + "", + " 1 package installed", + ]); expect(await exited).toBe(0); await rm(join(package_dir, "node_modules"), { recursive: true, force: true }); @@ -2259,7 +2304,12 @@ it("should install latest with prereleases", async () => { expect(err).toContain("Saved lockfile"); expect(stdout).toBeDefined(); out = await new Response(stdout).text(); - expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\n/)).toEqual([" + baz@1.0.0-0", "", " 1 package installed"]); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\n/)).toEqual([ + "", + " + baz@1.0.0-0", + "", + " 1 package installed", + ]); expect(await exited).toBe(0); await access(join(package_dir, "bun.lockb")); }); @@ -2299,6 +2349,7 @@ it("should handle dependency aliasing", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@0.0.3", "", " 1 package installed", @@ -2355,6 +2406,7 @@ it("should handle dependency aliasing (versioned)", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@0.0.3", "", " 1 package installed", @@ -2411,6 +2463,7 @@ it("should handle dependency aliasing (dist-tagged)", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@0.0.3", "", " 1 package installed", @@ -2471,6 +2524,7 @@ it("should not reinstall aliased dependencies", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + Bar@0.0.3", "", " 1 package installed", @@ -2577,6 +2631,7 @@ it("should handle aliased & direct dependency references", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", " + baz@0.0.3", "", @@ -2658,6 +2713,7 @@ it("should not hoist if name collides with alias", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + moo@workspace:moo", " + bar@0.0.3", "", @@ -2737,6 +2793,7 @@ it("should get npm alias with matching version", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + moo@workspace:moo", " + boba@0.0.5", "", @@ -2791,6 +2848,7 @@ it("should not apply overrides to package name of aliased package", async () => expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.3", "", " 1 package installed", @@ -2836,6 +2894,7 @@ it("should handle unscoped alias on scoped dependency", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @barn/moo@0.1.0", " + moo@0.1.0", "", @@ -2896,6 +2955,7 @@ it("should handle scoped alias on unscoped dependency", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @baz/bar@0.0.2", " + bar@0.0.2", "", @@ -2966,6 +3026,7 @@ it("should handle aliased dependency with existing lockfile", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + moz@0.1.0", "", " 3 packages installed", @@ -3027,6 +3088,7 @@ it("should handle aliased dependency with existing lockfile", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + moz@0.1.0", "", " 3 packages installed", @@ -3094,7 +3156,7 @@ it("should handle GitHub URL in dependencies (user/repo)", async () => { let out = await new Response(stdout).text(); out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(github:[^#]+)#[a-f0-9]+/, "$1"); - expect(out.split(/\r?\n/)).toEqual([" + uglify@github:mishoo/UglifyJS", "", " 1 package installed"]); + expect(out.split(/\r?\n/)).toEqual(["", " + uglify@github:mishoo/UglifyJS", "", " 1 package installed"]); expect(await exited).toBe(0); expect(urls.sort()).toBeEmpty(); expect(requested).toBe(0); @@ -3146,6 +3208,7 @@ it("should handle GitHub URL in dependencies (user/repo#commit-id)", async () => expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify@github:mishoo/UglifyJS#e219a9a", "", " 1 package installed", @@ -3212,6 +3275,7 @@ it("should handle GitHub URL in dependencies (user/repo#tag)", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify@github:mishoo/UglifyJS#e219a9a", "", " 1 package installed", @@ -3286,6 +3350,7 @@ it("should handle bitbucket git dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + public-install-test@git+ssh://${dep}#79265e2d9754c60b60f97cc8d859fb6da073b5d2`, "", " 1 package installed", @@ -3325,7 +3390,6 @@ it("should handle bitbucket git dependencies", async () => { "", ` installed publicinstalltest@git+ssh://${dep}#79265e2d9754c60b60f97cc8d859fb6da073b5d2`, "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -3365,6 +3429,7 @@ it("should handle gitlab git dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + public-install-test@git+ssh://${dep}#93f3aa4ec9ca8a0bacc010776db48bfcd915c44c`, "", " 1 package installed", @@ -3404,7 +3469,6 @@ it("should handle gitlab git dependencies", async () => { "", ` installed public-install-test@git+ssh://${dep}#93f3aa4ec9ca8a0bacc010776db48bfcd915c44c`, "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -3441,6 +3505,7 @@ it("should handle GitHub URL in dependencies (github:user/repo#tag)", async () = expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify@github:mishoo/UglifyJS#e219a9a", "", " 1 package installed", @@ -3511,7 +3576,7 @@ it("should handle GitHub URL in dependencies (https://github.com/user/repo.git)" let out = await new Response(stdout).text(); out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(github:[^#]+)#[a-f0-9]+/, "$1"); - expect(out.split(/\r?\n/)).toEqual([" + uglify@github:mishoo/UglifyJS", "", " 1 package installed"]); + expect(out.split(/\r?\n/)).toEqual(["", " + uglify@github:mishoo/UglifyJS", "", " 1 package installed"]); expect(await exited).toBe(0); expect(urls.sort()).toBeEmpty(); expect(requested).toBe(0); @@ -3563,6 +3628,7 @@ it("should handle GitHub URL in dependencies (git://github.com/user/repo.git#com expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify@github:mishoo/UglifyJS#e219a9a", "", " 1 package installed", @@ -3633,7 +3699,7 @@ it("should handle GitHub URL in dependencies (git+https://github.com/user/repo.g let out = await new Response(stdout).text(); out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(github:[^#]+)#[a-f0-9]+/, "$1"); - expect(out.split(/\r?\n/)).toEqual([" + uglify@github:mishoo/UglifyJS", "", " 1 package installed"]); + expect(out.split(/\r?\n/)).toEqual(["", " + uglify@github:mishoo/UglifyJS", "", " 1 package installed"]); expect(await exited).toBe(0); expect(urls.sort()).toBeEmpty(); expect(requested).toBe(0); @@ -3687,6 +3753,7 @@ it("should handle GitHub tarball URL in dependencies (https://github.com/user/re out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(github:[^#]+)#[a-f0-9]+/, "$1"); expect(out.split(/\r?\n/)).toEqual([ + "", " + when@https://github.com/cujojs/when/tarball/1.0.2", "", " 1 package installed", @@ -3746,6 +3813,7 @@ it("should handle GitHub tarball URL in dependencies (https://github.com/user/re out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(github:[^#]+)#[a-f0-9]+/, "$1"); expect(out.split(/\r?\n/)).toEqual([ + "", " + when@https://github.com/cujojs/when/tarball/1.0.2", "", " 1 package installed", @@ -3807,6 +3875,7 @@ it("should treat non-GitHub http(s) URLs as tarballs (https://some.url/path?stuf out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(github:[^#]+)#[a-f0-9]+/, "$1"); expect(out.split(/\r?\n/)).toEqual([ + "", " + @vercel/turbopack-node@https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230922.2", "", " 2 packages installed", @@ -3862,6 +3931,7 @@ cache = false expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + html-minifier@github:kangax/html-minifier#4beb325", "", " 12 packages installed", @@ -3915,6 +3985,7 @@ cache = false expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + html-minifier@github:kangax/html-minifier#4beb325", "", " 12 packages installed", @@ -4012,6 +4083,7 @@ it("should consider peerDependencies during hoisting", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", " + moo@workspace:moo", "", @@ -4113,6 +4185,7 @@ it("should install peerDependencies when needed", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", " + moo@workspace:moo", "", @@ -4179,6 +4252,7 @@ it("should not regard peerDependencies declarations as duplicates", async () => expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", "", " 1 package installed", @@ -4370,6 +4444,7 @@ it("should handle Git URL in dependencies", async () => { out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(\.git)#[a-f0-9]+/, "$1"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify-js@git+https://git@github.com/mishoo/UglifyJS.git", "", " 1 package installed", @@ -4431,6 +4506,7 @@ it("should handle Git URL in dependencies (SCP-style)", async () => { out = out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, ""); out = out.replace(/(\.git)#[a-f0-9]+/, "$1"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify@git+ssh://github.com:mishoo/UglifyJS.git", "", " 1 package installed", @@ -4490,6 +4566,7 @@ it("should handle Git URL with committish in dependencies", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify@git+https://git@github.com/mishoo/UglifyJS.git#e219a9a78a0d2251e4dcbd4bb9034207eb484fe8", "", " 1 package installed", @@ -4632,6 +4709,7 @@ it("should de-duplicate committish in Git URLs", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uglify-hash@git+https://git@github.com/mishoo/UglifyJS.git#e219a9a78a0d2251e4dcbd4bb9034207eb484fe8", " + uglify-ver@git+https://git@github.com/mishoo/UglifyJS.git#e219a9a78a0d2251e4dcbd4bb9034207eb484fe8", "", @@ -4729,6 +4807,7 @@ cache = false expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + html-minifier@git+https://git@github.com/kangax/html-minifier#4beb325eb01154a40c0cbebff2e5737bbd7071ab", "", " 12 packages installed", @@ -4782,6 +4861,7 @@ cache = false expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + html-minifier@git+https://git@github.com/kangax/html-minifier#4beb325eb01154a40c0cbebff2e5737bbd7071ab", "", " 12 packages installed", @@ -4852,6 +4932,7 @@ cache = false expect(stdout3).toBeDefined(); const out3 = await new Response(stdout3).text(); expect(out3.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + html-minifier@git+https://git@github.com/kangax/html-minifier#4beb325eb01154a40c0cbebff2e5737bbd7071ab", "", " 12 packages installed", @@ -4921,6 +5002,7 @@ it("should prefer optionalDependencies over dependencies of the same name", asyn expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@0.0.3", "", " 1 package installed", @@ -4974,6 +5056,7 @@ it("should prefer dependencies over peerDependencies of the same name", async () expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@0.0.5", "", " 1 package installed", @@ -5019,6 +5102,7 @@ it("should handle tarball URL", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + baz@${root_url}/baz-0.0.3.tgz`, "", " 1 package installed", @@ -5067,6 +5151,7 @@ it("should handle tarball path", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + baz@${join(import.meta.dir, "baz-0.0.3.tgz")}`, "", " 1 package installed", @@ -5114,6 +5199,7 @@ it("should handle tarball URL with aliasing", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + bar@${root_url}/baz-0.0.3.tgz`, "", " 1 package installed", @@ -5162,6 +5248,7 @@ it("should handle tarball path with aliasing", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + bar@${join(import.meta.dir, "baz-0.0.3.tgz")}`, "", " 1 package installed", @@ -5219,6 +5306,7 @@ it("should de-duplicate dependencies alongside tarball URL", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + @barn/moo@${root_url}/moo-0.1.0.tgz`, " + bar@0.0.2", "", @@ -5302,6 +5390,7 @@ it("should handle tarball URL with existing lockfile", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + @barn/moo@${root_url}/moo-0.1.0.tgz`, "", " 3 packages installed", @@ -5363,6 +5452,7 @@ it("should handle tarball URL with existing lockfile", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + @barn/moo@${root_url}/moo-0.1.0.tgz`, "", " 3 packages installed", @@ -5445,6 +5535,7 @@ it("should handle tarball path with existing lockfile", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + @barn/moo@${join(import.meta.dir, "moo-0.1.0.tgz")}`, "", " 3 packages installed", @@ -5505,6 +5596,7 @@ it("should handle tarball path with existing lockfile", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + @barn/moo@${join(import.meta.dir, "moo-0.1.0.tgz")}`, "", " 3 packages installed", @@ -5581,7 +5673,12 @@ it("should handle devDependencies from folder", async () => { expect(err).toContain("Saved lockfile"); expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); - expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([" + moo@moo", "", " 2 packages installed"]); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", + " + moo@moo", + "", + " 2 packages installed", + ]); expect(await exited).toBe(0); expect(urls.sort()).toEqual([`${root_url}/bar`, `${root_url}/bar-0.0.2.tgz`]); expect(requested).toBe(2); @@ -5633,6 +5730,7 @@ it("should deduplicate devDependencies from folder", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", " + moo@moo", "", @@ -5686,6 +5784,7 @@ it("should install dependencies in root package of workspace", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + moo@workspace:moo", "", " 2 packages installed", @@ -5738,6 +5837,7 @@ it("should install dependencies in root package of workspace (*)", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + moo@workspace:moo", "", " 2 packages installed", @@ -5789,6 +5889,7 @@ it("should ignore invalid workspaces from parent directory", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", "", " 1 package installed", @@ -5845,6 +5946,7 @@ it("should handle --cwd", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@0.0.2", "", " 1 package installed", @@ -5955,6 +6057,7 @@ cache = false expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + conditional-type-checks@1.0.6", " + prettier@2.8.8", " + tsd@0.22.0", @@ -6095,7 +6198,7 @@ cache = false expect(err2).not.toContain("error:"); expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); - expect(out2.replace(/\[[0-9\.]+m?s\]/, "[]").split(/\r?\n/)).toEqual(["[] done", ""]); + expect(out2.replace(/\[[0-9\.]+m?s\]/, "[]").split(/\r?\n/)).toEqual(["", "[] done", ""]); expect(await exited2).toBe(0); 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); @@ -6155,6 +6258,7 @@ it("should handle trustedDependencies", async () => { const out = await new Response(stdout).text(); const moo_dir = await realpath(join(package_dir, "node_modules", "moo")); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@bar", " + moo@moo", "", @@ -6204,6 +6308,7 @@ it("should handle `workspaces:*` and `workspace:*` gracefully", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", "", " 1 package installed", @@ -6234,6 +6339,7 @@ it("should handle `workspaces:*` and `workspace:*` gracefully", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", "", " 1 package installed", @@ -6277,6 +6383,7 @@ it("should handle `workspaces:bar` and `workspace:*` gracefully", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", "", " 1 package installed", @@ -6320,6 +6427,7 @@ it("should handle `workspaces:*` and `workspace:bar` gracefully", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", "", " 1 package installed", @@ -6363,6 +6471,7 @@ it("should handle `workspaces:bar` and `workspace:bar` gracefully", async () => expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", "", " 1 package installed", @@ -6417,6 +6526,7 @@ it("should handle installing packages from inside a workspace with `*`", async ( expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + swag@workspace:packages/swag", " + yolo@workspace:packages/yolo", "", @@ -6499,6 +6609,7 @@ it("should handle installing packages from inside a workspace without prefix", a expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + p1@workspace:packages/p1", " + p2@workspace:packages/p2", "", @@ -6670,6 +6781,7 @@ it("should handle installing packages inside workspaces with difference versions expect(err1).toContain("Saved lockfile"); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + package1@workspace:packages/package1", " + package2@workspace:packages/package2", " + package3@workspace:packages/package3", @@ -6728,6 +6840,7 @@ it("should handle installing packages inside workspaces with difference versions expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + package1@workspace:packages/package1", " + package2@workspace:packages/package2", " + package3@workspace:packages/package3", @@ -6782,6 +6895,7 @@ it("should handle installing packages inside workspaces with difference versions expect(stdout3).toBeDefined(); const out3 = await new Response(stdout3).text(); expect(out3.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + package1@workspace:packages/package1", " + package2@workspace:packages/package2", " + package3@workspace:packages/package3", @@ -6836,6 +6950,7 @@ it("should handle installing packages inside workspaces with difference versions expect(stdout4).toBeDefined(); const out4 = await new Response(stdout4).text(); expect(out4.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + package1@workspace:packages/package1", " + package2@workspace:packages/package2", " + package3@workspace:packages/package3", @@ -6891,6 +7006,7 @@ it("should handle installing packages inside workspaces with difference versions expect(stdout5).toBeDefined(); const out5 = await new Response(stdout5).text(); expect(out5.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + package1@workspace:packages/package1", " + package2@workspace:packages/package2", " + package3@workspace:packages/package3", @@ -6963,6 +7079,7 @@ it("should override npm dependency by matching workspace", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", "", " 1 package installed", @@ -7053,6 +7170,7 @@ it("should override @scoped npm dependency by matching workspace", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @bar/baz@workspace:packages/bar-baz", "", " 1 package installed", @@ -7102,6 +7220,7 @@ it("should override aliased npm dependency by matching workspace", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:baz", "", " 1 package installed", @@ -7156,6 +7275,7 @@ it("should override child npm dependency by matching workspace", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", " + baz@workspace:baz", "", @@ -7213,6 +7333,7 @@ it("should not override child npm dependency by workspace with mismatched versio expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", " + baz@workspace:baz", "", @@ -7276,6 +7397,7 @@ it("should override @scoped child npm dependency by matching workspace", async ( expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @moo/bar@workspace:packages/moo-bar", " + @moo/baz@workspace:packages/moo-baz", "", @@ -7338,6 +7460,7 @@ it("should override aliased child npm dependency by matching workspace", async ( expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @moo/bar@workspace:packages/bar", " + baz@workspace:packages/baz", "", @@ -7398,6 +7521,7 @@ it("should handle `workspace:` with semver range", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + bar@workspace:bar", " + baz@workspace:baz", "", @@ -7454,6 +7578,7 @@ it("should handle `workspace:` with alias & @scope", async () => { expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @moo/bar@workspace:packages/bar", " + @moz/baz@workspace:packages/baz", "", @@ -7524,6 +7649,7 @@ it("should handle `workspace:*` on both root & child", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@workspace:packages/baz", " + bar@workspace:packages/bar", "", @@ -7561,6 +7687,7 @@ it("should handle `workspace:*` on both root & child", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@workspace:packages/baz", " + bar@workspace:packages/bar", "", @@ -7646,6 +7773,7 @@ it("should install correct version of peer dependency from root package", async expect(stdout).toBeDefined(); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@0.0.3", "", " 1 package installed", diff --git a/test/cli/install/bun-link.test.ts b/test/cli/install/bun-link.test.ts index 7883bedc8a..a8731eb4e7 100644 --- a/test/cli/install/bun-link.test.ts +++ b/test/cli/install/bun-link.test.ts @@ -66,6 +66,7 @@ it("should link and unlink workspace package", async () => { expect(stdout).toBeDefined(); var out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + boba@workspace:packages/boba", " + moo@workspace:packages/moo", "", @@ -106,7 +107,6 @@ it("should link and unlink workspace package", async () => { "", ` installed moo@link:moo`, "", - "", " 1 package installed", ]); expect(await exited).toBe(0); @@ -165,7 +165,6 @@ it("should link and unlink workspace package", async () => { "", ` installed foo@link:foo`, "", - "", " 1 package installed", ]); expect(await file(join(link_dir, "packages", "boba", "node_modules", "foo", "package.json")).json()).toEqual({ @@ -249,7 +248,6 @@ it("should link package", async () => { "", ` installed ${link_name}@link:${link_name}`, "", - "", " 1 package installed", ]); expect(await exited2).toBe(0); @@ -350,7 +348,6 @@ it("should link scoped package", async () => { "", ` installed ${link_name}@link:${link_name}`, "", - "", " 1 package installed", ]); expect(await exited2).toBe(0); @@ -395,6 +392,7 @@ it("should link scoped package", async () => { }); it("should link dependency without crashing", async () => { + console.log(link_dir); const link_name = basename(link_dir).slice("bun-link.".length) + "-really-long-name"; await writeFile( join(link_dir, "package.json"), @@ -455,6 +453,7 @@ it("should link dependency without crashing", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + ${link_name}@link:${link_name}`, "", " 1 package installed", @@ -506,6 +505,11 @@ it("should link dependency without crashing", async () => { expect(err4).toContain(`error: FileNotFound installing ${link_name}`); expect(stdout4).toBeDefined(); const out4 = await new Response(stdout4).text(); - expect(out4.replace(/\[[0-9\.]+m?s\]/, "[]").split(/\r?\n/)).toEqual(["Failed to install 1 package", "[] done", ""]); + expect(out4.replace(/\[[0-9\.]+m?s\]/, "[]").split(/\r?\n/)).toEqual([ + "", + "Failed to install 1 package", + "[] done", + "", + ]); expect(await exited4).toBe(0); }); diff --git a/test/cli/install/bun-remove.test.ts b/test/cli/install/bun-remove.test.ts index 2b70900ddc..d9352e6c57 100644 --- a/test/cli/install/bun-remove.test.ts +++ b/test/cli/install/bun-remove.test.ts @@ -100,6 +100,7 @@ it("should remove existing package", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]/, "").split(/\r?\n/)).toEqual([ + "", ` + pkg2@${pkg2_path}`, "", " 1 package installed", diff --git a/test/cli/install/bun-update.test.ts b/test/cli/install/bun-update.test.ts index 7cdfb3a971..bb7fd15e37 100644 --- a/test/cli/install/bun-update.test.ts +++ b/test/cli/install/bun-update.test.ts @@ -65,6 +65,7 @@ it("should update to latest version of dependency", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@0.0.3", "", " 1 package installed", @@ -112,7 +113,6 @@ it("should update to latest version of dependency", async () => { " installed baz@0.0.5 with binaries:", " - baz-exec", "", - "", " 1 package installed", ]); expect(await exited2).toBe(0); @@ -178,6 +178,7 @@ it("should update to latest versions of dependencies", async () => { expect(stdout1).toBeDefined(); const out1 = await new Response(stdout1).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @barn/moo@0.1.0", " + baz@0.0.3", "", @@ -229,6 +230,7 @@ it("should update to latest versions of dependencies", async () => { expect(stdout2).toBeDefined(); const out2 = await new Response(stdout2).text(); expect(out2.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + @barn/moo@0.1.0", " + baz@0.0.5", "", @@ -294,6 +296,7 @@ it("lockfile should not be modified when there are no version changes, issue#588 expect(stdout).toBeDefined(); const out1 = await new Response(stdout).text(); expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + baz@0.0.3", "", " 1 package installed", diff --git a/test/cli/install/registry/bun-install-registry.test.ts b/test/cli/install/registry/bun-install-registry.test.ts index 8e1765c9c3..786f13bb5c 100644 --- a/test/cli/install/registry/bun-install-registry.test.ts +++ b/test/cli/install/registry/bun-install-registry.test.ts @@ -76,6 +76,7 @@ test("basic 1", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + basic-1@1.0.0", "", " 1 package installed", @@ -103,6 +104,7 @@ test("basic 1", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + basic-1@1.0.0", "", " 1 package installed", @@ -140,6 +142,7 @@ test("dependency from root satisfies range from dependency", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps@1.0.0", " + one-range-dep@1.0.0", "", @@ -168,6 +171,7 @@ test("dependency from root satisfies range from dependency", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps@1.0.0", " + one-range-dep@1.0.0", "", @@ -205,6 +209,7 @@ test("package added after install", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + one-range-dep@1.0.0", "", " 2 packages installed", @@ -246,6 +251,7 @@ test("package added after install", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps@1.0.0", "", " 2 packages installed", @@ -281,6 +287,7 @@ test("package added after install", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps@1.0.0", " + one-range-dep@1.0.0", "", @@ -315,6 +322,7 @@ test("it should correctly link binaries after deleting node_modules", async () = expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uses-what-bin@1.5.0", " + what-bin@1.0.0", "", @@ -339,6 +347,7 @@ test("it should correctly link binaries after deleting node_modules", async () = expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uses-what-bin@1.5.0", " + what-bin@1.0.0", "", @@ -386,6 +395,7 @@ test("it should install with missing bun.lockb, node_modules, and/or cache", asy expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dep-loop-entry@1.0.0", " + dep-with-tags@3.0.0", " + dev-deps@1.0.0", @@ -421,6 +431,7 @@ test("it should install with missing bun.lockb, node_modules, and/or cache", asy expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dep-loop-entry@1.0.0", " + dep-with-tags@3.0.0", " + dev-deps@1.0.0", @@ -934,6 +945,7 @@ describe("workspaces", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + pkg1@workspace:packages/pkg1", " + pkg2@workspace:packages/pkg2", "", @@ -956,6 +968,7 @@ describe("workspaces", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + pkg1@workspace:packages/pkg1", " + pkg2@workspace:packages/pkg2", "", @@ -981,6 +994,7 @@ describe("workspaces", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + pkg1@workspace:packages/pkg1", " + pkg2@workspace:packages/pkg2", "", @@ -1003,6 +1017,7 @@ describe("workspaces", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + pkg1@workspace:packages/pkg1", " + pkg2@workspace:packages/pkg2", "", @@ -1052,6 +1067,7 @@ describe("workspaces", async () => { expect(err).not.toContain('workspace dependency "workspace-1" not found'); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + workspace-1@workspace:packages/workspace-1", "", " 1 package installed", @@ -1076,6 +1092,7 @@ describe("workspaces", async () => { expect(err).not.toContain('workspace dependency "workspace-1" not found'); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + workspace-1@workspace:packages/workspace-1", "", " 1 package installed", @@ -1104,6 +1121,7 @@ describe("workspaces", async () => { expect(err).not.toContain('workspace dependency "workspace-1" not found'); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + workspace-1@workspace:packages/workspace-1", "", " 1 package installed", @@ -1128,6 +1146,7 @@ describe("workspaces", async () => { expect(err).not.toContain('workspace dependency "workspace-1" not found'); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + workspace-1@workspace:packages/workspace-1", "", " 1 package installed", @@ -1163,6 +1182,7 @@ test("it should re-populate .bin folder if package is reinstalled", async () => expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + what-bin@1.5.0", "", " 1 package installed", @@ -1191,6 +1211,7 @@ test("it should re-populate .bin folder if package is reinstalled", async () => expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + what-bin@1.5.0", "", expect.stringContaining("1 package installed"), @@ -1239,6 +1260,7 @@ test("missing package on reinstall, some with binaries", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dep-loop-entry@1.0.0", " + dep-with-tags@3.0.0", " + dev-deps@1.0.0", @@ -1287,6 +1309,7 @@ test("missing package on reinstall, some with binaries", async () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dep-loop-entry@1.0.0", " + left-pad@1.0.0", " + native@1.0.0", @@ -1425,6 +1448,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + all-lifecycle-scripts@1.0.0", "", expect.stringContaining("1 package installed"), @@ -1477,6 +1501,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + all-lifecycle-scripts@1.0.0", "", expect.stringContaining("1 package installed"), @@ -1564,6 +1589,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).toContain("Saved lockfile"); var out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + pkg1@workspace:packages/pkg1", " + pkg2@workspace:packages/pkg2", "", @@ -1665,6 +1691,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + all-lifecycle-scripts@1.0.0", "", " 1 package installed", @@ -1752,6 +1779,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + what-bin@1.0.0", "", " 1 package installed", @@ -1807,6 +1835,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + what-bin@1.0.0", "", " 1 package installed", @@ -1898,6 +1927,7 @@ for (const forceWaiterThread of [false, true]) { expect(stdout).toBeDefined(); var out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + lifecycle-postinstall@1.0.0", "", // @ts-ignore @@ -1922,6 +1952,7 @@ for (const forceWaiterThread of [false, true]) { expect(stdout).toBeDefined(); out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + lifecycle-postinstall@1.0.0", "", expect.stringContaining("1 package installed"), @@ -1978,6 +2009,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + another-init-cwd@1.0.0", " + lifecycle-init-cwd@1.0.0", "", @@ -2048,6 +2080,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("hello"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + lifecycle-failing-postinstall@1.0.0", "", " 1 package installed", @@ -2083,6 +2116,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + binding-gyp-scripts@1.5.0", "", expect.stringContaining("2 packages installed"), @@ -2116,6 +2150,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + binding-gyp-scripts@1.5.0", "", expect.stringContaining("2 packages installed"), @@ -2168,6 +2203,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + node-gyp@1.5.0", "", expect.stringContaining("1 package installed"), @@ -2224,6 +2260,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + node-gyp@1.5.0", "", expect.stringContaining("1 package installed"), @@ -2262,6 +2299,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + node-gyp@1.5.0", "", expect.stringContaining("1 package installed"), @@ -2298,6 +2336,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + lifecycle-install-test@github:dylan-conway/lifecycle-install-test#3ba6af5", "", expect.stringContaining("1 package installed"), @@ -2376,6 +2415,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uses-what-bin-slow@1.0.0", "", " 2 packages installed", @@ -2458,6 +2498,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("error:"); var out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uses-what-bin@1.0.0", " + what-bin@1.5.0", "", @@ -2520,6 +2561,7 @@ for (const forceWaiterThread of [false, true]) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + uses-what-bin@1.5.0", " + what-bin@1.0.0", "", @@ -2602,6 +2644,7 @@ require("fs").writeFileSync("missing-bin.txt", "missing-bin@WHAT"); expect(err).not.toContain("error:"); const out = await new Response(stdout).text(); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + what-bin@1.0.0", "", expect.stringContaining("1 package installed"), @@ -2739,6 +2782,7 @@ describe("semver", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + dep-with-tags@${expected}`, "", " 1 package installed", @@ -2904,6 +2948,7 @@ for (let i = 0; i < prereleaseTests.length; i++) { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", ` + ${depName}@${expected}`, "", " 1 package installed", @@ -3080,6 +3125,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dragon-test-1-d@1.0.0", " + dragon-test-1-e@1.0.0", "", @@ -3170,6 +3216,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dragon-test-2-b@workspace:dragon-test-2-b", " + dragon-test-2-a@workspace:dragon-test-2-a", "", @@ -3222,6 +3269,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dragon-test-3-a@1.0.0", "", " 3 packages installed", @@ -3289,6 +3337,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + my-workspace@workspace:my-workspace", "", " 3 packages installed", @@ -3368,6 +3417,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + a@workspace:packages/a", " + b@workspace:packages/b", "", @@ -3502,6 +3552,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + a@workspace:packages/a", " + b@workspace:packages/b", " + c@workspace:packages/c", @@ -3547,6 +3598,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dragon-test-7-a@1.0.0", " + dragon-test-7-b@2.0.0", " + dragon-test-7-c@3.0.0", @@ -3630,6 +3682,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + dragon-test-8-a@1.0.0", " + dragon-test-8-b@1.0.0", " + dragon-test-8-c@1.0.0", @@ -3670,6 +3723,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("error:"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + first@1.0.0", " + no-deps@1.0.0", " + second@1.0.0", @@ -3747,6 +3801,7 @@ describe("yarn tests", () => { expect(err).not.toContain("error:"); expect(err).not.toContain("not found"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + a@workspace:packages/a", " + b@workspace:packages/b", " + c@workspace:packages/c", @@ -3809,6 +3864,7 @@ describe("yarn tests", () => { expect(err).not.toContain("error:"); expect(err).not.toContain("not found"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + pkg-a@workspace:pkg-a", " + pkg-b@workspace:pkg-b", "", @@ -3862,6 +3918,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("incorrect peer dependency"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps@1.0.0", " + peer-deps-fixed@1.0.0", "", @@ -3902,6 +3959,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).toContain("incorrect peer dependency"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps@2.0.0", " + peer-deps-fixed@1.0.0", "", @@ -3942,6 +4000,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("incorrect peer dependency"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + provides-peer-deps-1-0-0@1.0.0", " + provides-peer-deps-2-0-0@1.0.0", "", @@ -4047,6 +4106,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("incorrect peer dependency"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + provides-peer-deps-1-0-0@1.0.0", " + provides-peer-deps-1-0-0-too@1.0.0", "", @@ -4107,6 +4167,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("incorrect peer dependency"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + forward-peer-deps@1.0.0", " + forward-peer-deps-too@1.0.0", " + no-deps@1.0.0", @@ -4169,6 +4230,7 @@ describe("yarn tests", () => { expect(err).not.toContain("not found"); expect(err).not.toContain("incorrect peer dependency"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps@1.0.0", " + peer-deps@1.0.0", " + peer-deps-too@1.0.0", @@ -4224,6 +4286,7 @@ describe("yarn tests", () => { expect(err).not.toContain("error:"); expect(err).not.toContain("not found"); expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + "", " + no-deps-scripted@1.0.0", " + one-dep-scripted@1.5.0", "",