Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion test/cli/install/bun-lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1721,7 +1721,7 @@ describe.each(["hoisted", "isolated"] as const)("peer no published version satis
// The request assertions below need a cache of their own per project: the
// environment's cache dir takes precedence over bunfig, and a package
// extracted there by one of the concurrent tests is not downloaded again.
env: { ...env, BUN_INSTALL_CACHE_DIR: join(cwd, ".bun-cache") },
env: { ...env, BUN_INSTALL_CACHE_DIR: cacheDir(cwd) },
stdout: "pipe",
stderr: "pipe",
// Only matters if an install never returns.
Expand All @@ -1732,6 +1732,19 @@ describe.each(["hoisted", "isolated"] as const)("peer no published version satis
return { out, err };
}

function cacheDir(cwd: string) {
return join(cwd, ".bun-cache");
}

// How many manifests the project's installs have written to its cache. The
// entries are written by a thread pool task that bun install does not wait
// for before exiting (`save_async` in src/install/npm.rs), so the last
// manifest an install fetches is occasionally missing. An install that has
// to fetch it again writes it again.
function cachedManifests(cwd: string) {
return Array.from(new Bun.Glob("*.npm").scanSync(cacheDir(cwd))).length;
}

it.concurrent("declared by a registry package", async () => {
using registry = await serveRegistry();
using dir = createProject(registry.url, {
Expand Down Expand Up @@ -1768,6 +1781,16 @@ describe.each(["hoisted", "isolated"] as const)("peer no published version satis
expect(err).not.toContain("Ignoring lockfile");
expect(await file(lockfilePath).text()).toBe(lockfile);

// The resolve below needs both manifests cached. peer-target's was the last
// thing the first install fetched, and nothing was left to do after it, so
// its entry is the one that is occasionally missing (see cachedManifests);
// resolving without the lockfile fetches and writes it again.
for (let retries = 5; retries > 0 && cachedManifests(String(dir)) < 2; retries--) {
await rm(lockfilePath);
await install(String(dir));
}
expect(cachedManifests(String(dir))).toBe(2);

// Resolve from scratch again. Both manifests are cached now, so the peer
// is looked up synchronously instead of through a network task.
await rm(lockfilePath);
Expand Down