Files

124 lines
4.4 KiB
TypeScript
Raw Permalink Normal View History

2026-08-27 21:09:14 +00:00
import { describe, expect, test } from "bun:test";
import { mkdirSync } from "fs";
import { bunEnv, bunExe, tempDir, tmpdirSync } from "harness";
import { join } from "path";
// --install=<val> Configure auto-install behavior. One of "auto" (default, auto-installs when no node_modules), "fallback" (missing packages only), "force" (always).
// -i Auto-install dependencies during execution. Equivalent to --install=fallback.
describe("basic autoinstall", () => {
for (const install of ["", "-i", "--install=auto", "--install=fallback", "--install=force"]) {
for (const has_node_modules of [true, false]) {
let should_install = false;
if (has_node_modules) {
if (install === "" || install === "--install=auto") {
should_install = false;
} else {
should_install = true;
}
} else {
should_install = true;
}
test(`${install || "<no flag>"} ${has_node_modules ? "with" : "without"} node_modules ${should_install ? "should" : "should not"} autoinstall`, async () => {
const dir = tmpdirSync();
mkdirSync(dir, { recursive: true });
await Bun.write(join(dir, "index.js"), "import isEven from 'is-even'; console.log(isEven(2));");
const env = bunEnv;
env.BUN_INSTALL = install;
if (has_node_modules) {
mkdirSync(join(dir, "node_modules/abc"), { recursive: true });
}
const { stdout, stderr } = Bun.spawnSync({
cmd: [bunExe(), ...(install === "" ? [] : [install]), join(dir, "index.js")],
cwd: dir,
env,
stdout: "pipe",
stderr: "pipe",
});
if (should_install) {
expect(stderr?.toString("utf8")).not.toContain("error: Cannot find package 'is-even'");
expect(stdout?.toString("utf8")).toBe("true\n");
} else {
expect(stderr?.toString("utf8")).toContain("error: Cannot find package 'is-even'");
}
});
}
}
});
// In auto-install mode the project's own package.json is the lockfile's root
// package (resolution tag `root`, not `npm`). With a name and an exact version
// present, resolving any missing bare specifier used to read that resolution
// through the npm union accessor: "assertion failed: self.tag == Tag::Npm".
test("auto-install in a project whose package.json has a name and version", async () => {
const requests: string[] = [];
using registry = Bun.serve({
port: 0,
fetch(req) {
requests.push(new URL(req.url).pathname);
return new Response("not found", { status: 404 });
},
});
using dir = tempDir("autoinstall-root-name-version", {
"package.json": JSON.stringify({ name: "myapp", version: "1.0.0" }),
"index.js": `import "pkg-that-does-not-exist-anywhere";\n`,
"bunfig.toml": `[install]\nregistry = "http://127.0.0.1:${registry.port}/"\n`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "index.js"],
cwd: String(dir),
env: { ...bunEnv, BUN_INSTALL_CACHE_DIR: join(String(dir), ".bun-cache") },
stdout: "pipe",
stderr: "pipe",
});
const [, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// The resolver must get as far as asking the (local) registry for the
// missing package, then report it as missing instead of dying while
// re-parsing the project's own package.json.
expect(requests).toContain("/pkg-that-does-not-exist-anywhere");
expect(stderr).toContain("Cannot find package 'pkg-that-does-not-exist-anywhere'");
expect(exitCode).toBe(1);
});
test("--install=fallback to install missing packages", async () => {
const dir = tmpdirSync();
mkdirSync(dir, { recursive: true });
await Promise.all([
Bun.write(
join(dir, "index.js"),
"import isEven from 'is-even'; import isOdd from 'is-odd'; console.log(isEven(2), isOdd(2));",
),
Bun.write(
join(dir, "package.json"),
JSON.stringify({
name: "test",
dependencies: {
"is-odd": "1.0.0",
},
}),
),
]);
Bun.spawnSync({
cmd: [bunExe(), "install"],
cwd: dir,
env: bunEnv,
});
const { stdout, stderr } = Bun.spawnSync({
cmd: [bunExe(), "--install=fallback", join(dir, "index.js")],
cwd: dir,
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
expect(stderr?.toString("utf8")).not.toContain("error: Cannot find package 'is-odd'");
expect(stdout?.toString("utf8")).toBe("true false\n");
});