Files
bun.sh/test/cli/install/migrate-bun-lockb-v2.test.ts
Dylan Conway f770b1b1c7 fix(install): fix optional peer resolving (#24272)
### What does this PR do?
Allows optional peers to resolve to package if possible.

Optional peers aren't auto-installed, but they should still be given a
chance to resolve. If they're always left unresolved it's possible for
multiple dependencies on the same package to result in different peer
resolutions when they should be the same. For example, this bug this
could cause monorepos using elysia to have corrupt node_modules because
there might be more than one copy of elysia in `node_modules/.bun` (or
more than the expected number of copies).

fixes #23725
most likely fixes #23895

fixes ENG-21411

### How did you verify your code works?
Added a test for optional peers and non-optional peers that would
previously trigger this bug.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved resolution of optional peer dependencies during isolated
installations, with better propagation across package hierarchies.

* **Tests**
* Added comprehensive test suite covering optional peer dependency
scenarios in isolated workspaces.
* Added test fixtures for packages with peer and optional peer
dependencies.
* Enhanced lockfile migration test verification using snapshot-based
assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-01 22:38:36 -07:00

126 lines
3.5 KiB
TypeScript

import { file, spawn } from "bun";
import { install_test_helpers } from "bun:internal-for-testing";
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";
import { cp } from "node:fs/promises";
import { join } from "node:path";
const { parseLockfile } = install_test_helpers;
const tests = [
{
name: "migrate-bun-lockb-v2",
lockfile: "bun.lockb.v2",
files: {
"bunfig.toml": "install.saveTextLockfile = false",
"package.json": JSON.stringify({
name: "migrate-bun-lockb-v2",
dependencies: {
jquery: "~3.7.1",
"is-even": "^1.0.0",
},
}),
},
},
{
name: "migrate-bun-lockb-v2-most-features",
lockfile: "bun.lockb.v2-most-features",
files: {
"bunfig.toml": "install.saveTextLockfile = false",
"packages/pkg1/package.json": JSON.stringify({
"name": "pkg-wat",
"dependencies": {
"jquery": "3.7.0",
"pkg-wat-2": "workspace:",
},
}),
"packages/pkg2/package.json": JSON.stringify({
"name": "pkg-wat-2",
"dependencies": {
"kind-of": "6.0.3",
},
}),
"package.json": JSON.stringify({
"name": "migrate-everything",
"dependencies": {
"false": "^0.0.4",
"jquery": "~3.7.1",
"scheduler": "^0.23.0",
},
"devDependencies": {
"zod": "^3.22.4",
"esbuild": "0.25.10",
"react": "catalog:",
},
"optionalDependencies": {
"is-number": "^7.0.0",
},
"peerDependencies": {
"lodash": "^4.17.21",
"is-even": "^1.0.0",
},
"peerDependenciesMeta": {
"lodash": {
"optional": true,
},
},
"resolutions": {
"scheduler": "0.20.0",
},
"trustedDependencies": ["esbuild"],
"workspaces": {
"packages": ["packages/*"],
"catalog": {
"react": ">19.0.0",
},
},
}),
},
},
];
for (const testInfo of tests) {
test(`migrate ${testInfo.name}`, async () => {
const oldLockfileContents = await file(join(import.meta.dir, "fixtures", testInfo.lockfile)).text();
using testDir = tempDir(testInfo.name, testInfo.files);
await cp(join(import.meta.dir, "fixtures", testInfo.lockfile), join(testDir, "bun.lockb"));
let { stderr, exited } = spawn({
cmd: [bunExe(), "install"],
cwd: testDir,
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
let err = await stderr.text();
expect(await exited).toBe(0);
expect(err).toContain("Saved lockfile");
const newLockfileContents = await file(join(testDir, "bun.lockb")).bytes();
const newLockfile = parseLockfile(testDir);
// contents should be different due to semver numbers changing size
expect(newLockfileContents).not.toEqual(oldLockfileContents);
// but parse result should be the same
expect(newLockfile).toMatchSnapshot();
// another install should not change the lockfile
({ stderr, exited } = spawn({
cmd: [bunExe(), "install"],
cwd: testDir,
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
}));
expect(await exited).toBe(0);
const newLockfileContents2 = await file(join(testDir, "bun.lockb")).bytes();
const newLockfile2 = parseLockfile(testDir);
expect(newLockfileContents2).toEqual(newLockfileContents);
expect(newLockfile2).toEqual(newLockfile);
});
}