Files
bun.sh/test/cli/install/bun-patch.test.ts

820 lines
28 KiB
TypeScript

import { $, ShellOutput, ShellPromise } from "bun";
import { bunExe, bunEnv as env, toBeValidBin, toHaveBins, toBeWorkspaceLink, tempDirWithFiles, bunEnv } from "harness";
import { afterAll, afterEach, beforeAll, beforeEach, expect, it, describe, test, setDefaultTimeout } from "bun:test";
import { join, sep } from "path";
const expectNoError = (o: ShellOutput) => expect(o.stderr.toString()).not.toContain("error");
// const platformPath = (path: string) => (process.platform === "win32" ? path.replaceAll("/", sep) : path);
const platformPath = (path: string) => path;
beforeAll(() => {
setDefaultTimeout(1000 * 60 * 5);
});
describe("bun patch <pkg>", async () => {
describe("workspace interactions", async () => {
/**
* @repo/eslint-config and @repo/typescript-config both depend on @types/ws@8.5.4
* so it should be hoisted to the root node_modules
*/
describe("inside workspace with hoisting", async () => {
const args = [
["node_modules/@types/ws", "node_modules/@types/ws"],
["@types/ws@8.5.4", "node_modules/@types/ws"],
];
for (const [arg, path] of args) {
test(arg, async () => {
const tempdir = tempDirWithFiles("lol", {
"package.json": JSON.stringify({
"name": "my-workspace",
private: "true",
version: "0.0.1",
"devDependencies": {
"@repo/ui": "*",
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
},
workspaces: ["packages/*"],
}),
packages: {
"eslint-config": {
"package.json": JSON.stringify({
name: "@repo/eslint-config",
"version": "0.0.0",
dependencies: {
"@types/ws": "8.5.4",
},
private: "true",
}),
},
"typescript-config": {
"package.json": JSON.stringify({
"name": "@repo/typescript-config",
"version": "0.0.0",
dependencies: {
"@types/ws": "8.5.4",
},
private: "true",
}),
},
"ui": {
"package.json": JSON.stringify({
name: "@repo/ui",
version: "0.0.0",
private: "true",
devDependencies: {
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
},
}),
},
},
});
console.log("TEMPDIR", tempdir);
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir);
let result = await $` ${bunExe()} patch ${arg}`.env(bunEnv).cwd(tempdir);
expect(result.stderr.toString()).not.toContain("error");
expect(result.stdout.toString()).toContain(`To patch @types/ws, edit the following folder:\n\n ${path}\n`);
await $`echo LOL > ${path}/index.d.ts`.env(bunEnv).cwd(tempdir);
expectNoError(await $`${bunExe()} patch --commit ${arg}`.env(bunEnv).cwd(tempdir));
expect(await $`cat ${path}/index.d.ts`.env(bunEnv).cwd(tempdir).text()).toEqual("LOL\n");
expect(
(await $`cat package.json`.cwd(tempdir).env(bunEnv).json()).patchedDependencies["@types/ws@8.5.4"],
).toEqual("patches/@types%2Fws@8.5.4.patch");
});
}
});
describe("inside workspace with multiple workspace packages with same dependency", async () => {
const args = [
["node_modules/@types/ws", "packages/eslint-config/node_modules/@types/ws"],
["@types/ws@8.5.4", "node_modules/@repo/eslint-config/node_modules/@types/ws"],
];
for (const [arg, path] of args) {
test(arg, async () => {
const tempdir = tempDirWithFiles("lol", {
"package.json": JSON.stringify({
"name": "my-workspace",
private: "true",
version: "0.0.1",
"devDependencies": {
"@repo/ui": "*",
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
"@types/ws": "7.4.7",
},
workspaces: ["packages/*"],
}),
packages: {
"eslint-config": {
"package.json": JSON.stringify({
name: "@repo/eslint-config",
"version": "0.0.0",
dependencies: {
"@types/ws": "8.5.4",
},
private: "true",
}),
},
"typescript-config": {
"package.json": JSON.stringify({
"name": "@repo/typescript-config",
"version": "0.0.0",
dependencies: {
"@types/ws": "8.5.4",
},
private: "true",
}),
},
"ui": {
"package.json": JSON.stringify({
name: "@repo/ui",
version: "0.0.0",
private: "true",
devDependencies: {
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
},
}),
},
},
});
console.log("TEMPDIR", tempdir);
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir);
let result = await $`cd packages/eslint-config; ${bunExe()} patch ${arg}`.env(bunEnv).cwd(tempdir);
expect(result.stderr.toString()).not.toContain("error");
expect(result.stdout.toString()).toContain(
`To patch @types/ws, edit the following folder:\n\n ${tempdir}/${path}\n`,
);
await $`echo LOL > ${path}/index.d.ts`.env(bunEnv).cwd(tempdir);
expectNoError(await $`cd packages/eslint-config; ${bunExe()} patch --commit ${arg}`.env(bunEnv).cwd(tempdir));
expect(await $`cat ${path}/index.d.ts`.env(bunEnv).cwd(tempdir).text()).toEqual("LOL\n");
expect(
(await $`cat package.json`.cwd(tempdir).env(bunEnv).json()).patchedDependencies["@types/ws@8.5.4"],
).toEqual("patches/@types%2Fws@8.5.4.patch");
});
}
});
describe("inside workspace package", async () => {
const args = [
["node_modules/@types/ws", "packages/eslint-config/node_modules/@types/ws"],
["@types/ws@8.5.4", "node_modules/@repo/eslint-config/node_modules/@types/ws"],
];
for (const [arg, path] of args) {
test(arg, async () => {
const tempdir = tempDirWithFiles("lol", {
"package.json": JSON.stringify({
"name": "my-workspace",
private: "true",
version: "0.0.1",
"devDependencies": {
"@repo/ui": "*",
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
"@types/ws": "7.4.7",
},
workspaces: ["packages/*"],
}),
packages: {
"eslint-config": {
"package.json": JSON.stringify({
name: "@repo/eslint-config",
"version": "0.0.0",
dependencies: {
"@types/ws": "8.5.4",
},
private: "true",
}),
},
"typescript-config": {
"package.json": JSON.stringify({
"name": "@repo/typescript-config",
"version": "0.0.0",
private: "true",
}),
},
"ui": {
"package.json": JSON.stringify({
name: "@repo/ui",
version: "0.0.0",
private: "true",
devDependencies: {
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
},
}),
},
},
});
console.log("TEMPDIR", tempdir);
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir);
let result = await $`cd packages/eslint-config; ${bunExe()} patch ${arg}`.env(bunEnv).cwd(tempdir);
expect(result.stderr.toString()).not.toContain("error");
expect(result.stdout.toString()).toContain(
`To patch @types/ws, edit the following folder:\n\n ${tempdir}/${path}\n`,
);
await $`echo LOL > ${path}/index.js`.env(bunEnv).cwd(tempdir);
expectNoError(await $`cd packages/eslint-config; ${bunExe()} patch --commit ${arg}`.env(bunEnv).cwd(tempdir));
expect(await $`cat ${path}/index.js`.env(bunEnv).cwd(tempdir).text()).toEqual("LOL\n");
expect(
(await $`cat package.json`.cwd(tempdir).env(bunEnv).json()).patchedDependencies["@types/ws@8.5.4"],
).toEqual("patches/@types%2Fws@8.5.4.patch");
});
}
});
describe("inside ROOT workspace package", async () => {
const args = [
[
"packages/eslint-config/node_modules/@types/ws",
"packages/eslint-config/node_modules/@types/ws",
"@types/ws@8.5.4",
"patches/@types%2Fws@8.5.4.patch",
],
[
"@types/ws@8.5.4",
"node_modules/@repo/eslint-config/node_modules/@types/ws",
"@types/ws@8.5.4",
"patches/@types%2Fws@8.5.4.patch",
],
["@types/ws@7.4.7", "node_modules/@types/ws", "@types/ws@7.4.7", "patches/@types%2Fws@7.4.7.patch"],
];
for (const [arg, path, version, patch_path] of args) {
test(arg, async () => {
const tempdir = tempDirWithFiles("lol", {
"package.json": JSON.stringify({
"name": "my-workspace",
private: "true",
version: "0.0.1",
"devDependencies": {
"@repo/ui": "*",
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
"@types/ws": "7.4.7",
},
workspaces: ["packages/*"],
}),
packages: {
"eslint-config": {
"package.json": JSON.stringify({
name: "@repo/eslint-config",
"version": "0.0.0",
dependencies: {
"@types/ws": "8.5.4",
},
private: "true",
}),
},
"typescript-config": {
"package.json": JSON.stringify({
"name": "@repo/typescript-config",
"version": "0.0.0",
private: "true",
}),
},
"ui": {
"package.json": JSON.stringify({
name: "@repo/ui",
version: "0.0.0",
private: "true",
devDependencies: {
"@repo/eslint-config": "*",
"@repo/typescript-config": "*",
},
}),
},
},
});
console.log("TEMPDIR", tempdir);
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir);
let result = await $`${bunExe()} patch ${arg}`.env(bunEnv).cwd(tempdir);
expect(result.stderr.toString()).not.toContain("error");
expect(result.stdout.toString()).toContain(`To patch @types/ws, edit the following folder:\n\n ${path}\n`);
await $`echo LOL > ${path}/index.js`.env(bunEnv).cwd(tempdir);
expectNoError(await $`${bunExe()} patch --commit ${arg}`.env(bunEnv).cwd(tempdir));
expect(await $`cat ${path}/index.js`.env(bunEnv).cwd(tempdir).text()).toEqual("LOL\n");
expect((await $`cat package.json`.cwd(tempdir).env(bunEnv).json()).patchedDependencies[version]).toEqual(
patch_path,
);
});
}
});
});
// Tests to make sure that patching
describe("popular pkg", async () => {
const dummyCode = /* ts */ `
module.exports = function lmao() {
return 420;
}
`;
function makeTest(pkgName: string, version: string, folder_in_node_modules: string = `${pkgName}`) {
test(
`${pkgName}@${version}`,
async () => {
const tempdir = tempDirWithFiles("popular", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
[pkgName]: version,
},
}),
"index.ts": /* ts */ `import lmao from '${pkgName}'; console.log(lmao())`,
});
console.log("TEMPDIR", tempdir);
expectNoError(await $`${bunExe()} i`.env(bunEnv).cwd(tempdir));
expectNoError(await $`${bunExe()} patch ${pkgName}@${version}`.env(bunEnv).cwd(tempdir));
await $`echo ${dummyCode} > node_modules/${folder_in_node_modules}/index.js`.env(bunEnv).cwd(tempdir);
const { type, module, exports, ...package_json }: Record<string, any> =
await $`cat node_modules/${folder_in_node_modules}/package.json`.env(bunEnv).cwd(tempdir).json();
package_json["main"] = "index.js";
await $`echo ${JSON.stringify(package_json)} > node_modules/${folder_in_node_modules}/package.json`
.env(bunEnv)
.cwd(tempdir);
expectNoError(
await $`${bunExe()} patch --commit node_modules/${folder_in_node_modules}`.env(bunEnv).cwd(tempdir),
);
const { stdout } = await $`${bunExe()} run index.ts`.env(bunEnv).cwd(tempdir);
expect(stdout.toString()).toBe("420\n");
},
30 * 1000,
);
}
makeTest("lodash", "4.17.21");
makeTest("react", "18.3.1");
makeTest("react-dom", "18.3.1");
makeTest("axios", "1.7.2");
// makeTest("tslib", "2.6.3");
// makeTest("chalk", "5.3.0");
// makeTest("next", "14.2.4");
// makeTest("express", "4.19.2");
// makeTest("inquirer", "9.2.23");
// makeTest("commander", "12.1.0");
// // vercel/next.js
// makeTest("webpack-sources", "3.2.3");
// // vitejs/vite
// makeTest("acorn", "8.11.3");
// makeTest("chokidar", "3.6.0");
// makeTest("http-proxy", "1.18.1");
// makeTest("sirv", "2.0.4");
// // mermaid-js/mermaid
// makeTest("cytoscape", "3.28.1");
// // remix-run/react-router
// makeTest("@changesets/get-dependents-graph", "1.3.6", "@changesets/get-dependents-graph");
// // n8n-io/n8n
// makeTest("typedi", "0.10.0");
// makeTest("@sentry/cli", "2.17.0", "@sentry/cli");
// makeTest("pkce-challenge", "3.0.0");
// makeTest("pyodide", "0.23.4");
makeTest("@types/express-serve-static-core", "4.17.43", "@types/express-serve-static-core");
makeTest("@types/ws", "8.5.4", "@types/ws");
makeTest("@types/uuencode", "0.0.3", "@types/uuencode");
});
test("should patch a package when it is already patched", async () => {
const tempdir = tempDirWithFiles("lol", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
"is-even": "1.0.0",
"is-odd": "3.0.1",
},
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven(420))`,
});
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir);
const { stderr } = await $`${bunExe()} patch is-odd@0.1.2`.env(bunEnv).cwd(tempdir).throws(false);
expect(stderr.toString()).not.toContain("error");
const firstChange = /* ts */ `/*!
* is-odd <https://github.com/jonschlinkert/is-odd>
*
* Copyright (c) 2015-2017, Jon Schlinkert.
* Released under the MIT License.
*/
'use strict';
var isNumber = require('is-number');
module.exports = function isOdd(i) {
if (!isNumber(i)) {
throw new TypeError('is-odd expects a number.');
}
if (Number(i) !== Math.floor(i)) {
throw new RangeError('is-odd expects an integer.');
}
console.log('hi')
return !!(~~i & 1);
};`;
await $`echo ${firstChange} > node_modules/is-even/node_modules/is-odd/index.js`.env(bunEnv).cwd(tempdir);
const { stderr: stderr2 } = await $`${bunExe()} patch --commit node_modules/is-even/node_modules/is-odd`
.env(bunEnv)
.cwd(tempdir)
.throws(false);
expect(stderr2.toString()).not.toContain("error");
const { stderr: stderr3 } = await $`${bunExe()} patch is-odd@0.1.2`.env(bunEnv).cwd(tempdir).throws(false);
expect(stderr3.toString()).not.toContain("error");
const secondChange = /* ts */ `/*!
* is-odd <https://github.com/jonschlinkert/is-odd>
*
* Copyright (c) 2015-2017, Jon Schlinkert.
* Released under the MIT License.
*/
'use strict';
var isNumber = require('is-number');
module.exports = function isOdd(i) {
if (!isNumber(i)) {
throw new TypeError('is-odd expects a number.');
}
if (Number(i) !== Math.floor(i)) {
throw new RangeError('is-odd expects an integer.');
}
console.log('hi')
console.log('hello')
return !!(~~i & 1);
};`;
await $`echo ${secondChange} > node_modules/is-even/node_modules/is-odd/index.js`.env(bunEnv).cwd(tempdir);
const { stderr: stderr4 } = await $`${bunExe()} patch --commit node_modules/is-even/node_modules/is-odd`
.env(bunEnv)
.cwd(tempdir)
.throws(false);
expect(stderr4.toString()).not.toContain("error");
await $`cat patches/is-odd@0.1.2.patch`.env(bunEnv).cwd(tempdir);
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir).throws(false);
const { stdout } = await $`${bunExe()} run index.ts`.env(bunEnv).cwd(tempdir).throws(false);
expect(stdout.toString()).toContain("hi\nhello\n");
});
test("bad patch arg", async () => {
const tempdir = tempDirWithFiles("lol", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
"is-even": "1.0.0",
},
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven(420))`,
});
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir);
const { stderr, exitCode } = await $`${bunExe()} patch lkflksdkfj`.env(bunEnv).cwd(tempdir).throws(false);
expect(exitCode).toBe(1);
expect(stderr.toString()).toContain("error: package lkflksdkfj not found");
});
test("bad patch commit arg", async () => {
const tempdir = tempDirWithFiles("lol", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
"is-even": "1.0.0",
},
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven(420))`,
});
await $`${bunExe()} i`.env(bunEnv).cwd(tempdir);
const { stderr } = await $`${bunExe()} patch is-even`.env(bunEnv).cwd(tempdir);
expect(stderr.toString()).not.toContain("error");
const { stderr: stderr2 } = await $`${bunExe()} patch --commit lskfjdslkfjsldkfjlsdkfj`
.env(bunEnv)
.cwd(tempdir)
.throws(false);
expect(stderr2.toString()).toContain("error: package lskfjdslkfjsldkfjlsdkfj not found");
});
function makeTest(
name: string,
{
dependencies,
mainScript,
patchArg,
patchedCode,
expected,
}: {
dependencies: Record<string, string>;
mainScript: string;
patchArg: string;
patchedCode: string;
expected: { patchName: string; patchPath: string; stdout: string };
extra?: (filedir: string) => Promise<void>;
},
) {
expected.patchPath = platformPath(expected.patchPath);
test(name, async () => {
$.throws(true);
const filedir = tempDirWithFiles("patch1", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": dependencies,
}),
"index.ts": mainScript,
});
{
const { stderr } = await $`${bunExe()} i`.env(bunEnv).cwd(filedir);
expect(stderr.toString()).not.toContain("error");
}
{
const { stderr, stdout } = await $`${bunExe()} patch ${patchArg}`.env(bunEnv).cwd(filedir);
expect(stderr.toString()).not.toContain("error");
expect(stdout.toString()).toContain(
`To patch ${platformPath(expected.patchName)}, edit the following folder:
${platformPath(expected.patchPath)}
Once you're done with your changes, run:
bun patch --commit '${platformPath(expected.patchPath)}'`,
);
}
{
const newCode = patchedCode;
await $`echo ${newCode} > ${expected.patchPath}/index.js`.env(bunEnv).cwd(filedir);
const { stderr, stdout } = await $`${bunExe()} patch --commit ${expected.patchPath}`.env(bunEnv).cwd(filedir);
}
const output = await $`${bunExe()} run index.ts`.env(bunEnv).cwd(filedir).text();
expect(output).toBe(expected.stdout);
});
}
test(
"overwriting module with multiple levels of directories",
async () => {
const filedir = tempDirWithFiles("patch1", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": { lodash: "4.17.21" },
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven())`,
});
{
const { stderr } = await $`${bunExe()} i`.env(bunEnv).cwd(filedir);
expect(stderr.toString()).not.toContain("error");
}
{
const { stderr, stdout } = await $`${bunExe()} patch lodash`.env(bunEnv).cwd(filedir);
expect(stderr.toString()).not.toContain("error");
}
// run it again to make sure we didn't f something up
{
const { stderr, stdout } = await $`${bunExe()} patch lodash`.env(bunEnv).cwd(filedir);
expect(stderr.toString()).not.toContain("error");
}
},
15 * 1000,
);
["is-even@1.0.0", "node_modules/is-even"].map(patchArg =>
makeTest("should patch a node_modules package", {
dependencies: { "is-even": "1.0.0" },
mainScript: /* ts */ `import isEven from 'is-even'; isEven(420)`,
patchArg,
patchedCode: /* ts */ `/*!
* is-even <https://github.com/jonschlinkert/is-even>
*
* Copyright (c) 2015, 2017, Jon Schlinkert.
* Released under the MIT License.
*/
'use strict';
var isOdd = require('is-odd');
module.exports = function isEven(i) {
console.log("If you're reading this, the patch worked!")
return !isOdd(i);
};
`,
expected: {
patchName: "is-even",
patchPath: "node_modules/is-even",
stdout: "If you're reading this, the patch worked!\n",
},
}),
);
["is-odd@0.1.2", "node_modules/is-even/node_modules/is-odd"].map(patchArg =>
makeTest("should patch a nested node_modules package", {
dependencies: { "is-even": "1.0.0", "is-odd": "3.0.1" },
mainScript: /* ts */ `import isEven from 'is-even'; isEven(420)`,
patchArg,
patchedCode: /* ts */ `/*!
* is-odd <https://github.com/jonschlinkert/is-odd>
*
* Copyright (c) 2015-2017, Jon Schlinkert.
* Released under the MIT License.
*/
'use strict';
var isNumber = require('is-number');
module.exports = function isOdd(i) {
if (!isNumber(i)) {
throw new TypeError('is-odd expects a number.');
}
if (Number(i) !== Math.floor(i)) {
throw new RangeError('is-odd expects an integer.');
}
console.log("If you're reading this, the patch worked.")
return !!(~~i & 1);
};
`,
expected: {
patchName: "is-odd",
patchPath: "node_modules/is-even/node_modules/is-odd",
stdout: "If you're reading this, the patch worked.\n",
},
extra: async filedir => {
const patchfile = await $`cat ${join(filedir, "patches", "is-odd@0.1.2.patch")}`.cwd(filedir).text();
// ensure node modules is not in the patch
expect(patchfile).not.toContain("node_modules");
},
}),
);
test("should overwrite the node_modules folder of the package", async () => {
const patchArgs = ["is-even@1.0.0", "node_modules/is-even"];
for (const patchArg of patchArgs) {
$.throws(true);
const filedir = tempDirWithFiles("patch1", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
"is-even": "1.0.0",
},
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven())`,
});
{
const { stderr } = await $`${bunExe()} i --backend hardlink`.env(bunEnv).cwd(filedir);
expect(stderr.toString()).toContain("Saved lockfile");
const newCode = /* ts */ `
module.exports = function isEven() {
return 'LOL'
}
`;
await $`${bunExe()} patch ${patchArg}`.env(bunEnv).cwd(filedir);
await $`echo ${newCode} > node_modules/is-even/index.js`.env(bunEnv).cwd(filedir);
}
const tempdir = tempDirWithFiles("unpatched", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
"is-even": "1.0.0",
},
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven(420))`,
});
await $`${bunExe()} i`
.env(bunEnv)
.cwd(tempdir)
.then(o => expect(o.stderr.toString()).not.toContain("error"));
const { stdout, stderr } = await $`${bunExe()} run index.ts`.env(bunEnv).cwd(tempdir);
expect(stderr.toString()).toBe("");
expect(stdout.toString()).toBe("true\n");
}
});
test("should overwrite nested node_modules folder of the package", async () => {
const patchArgs = ["is-odd@0.1.2", "node_modules/is-even/node_modules/is-odd"];
for (const patchArg of patchArgs) {
$.throws(true);
const filedir = tempDirWithFiles("patch1", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
"is-even": "1.0.0",
"is-odd": "3.0.1",
},
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven())`,
});
{
const { stderr } = await $`${bunExe()} i --backend hardlink`.env(bunEnv).cwd(filedir);
expect(stderr.toString()).toContain("Saved lockfile");
const newCode = /* ts */ `
module.exports = function isOdd() {
return 'LOL'
}
`;
await $`ls -d node_modules/is-even/node_modules/is-odd`.cwd(filedir);
await $`${bunExe()} patch ${patchArg}`.env(bunEnv).cwd(filedir);
await $`echo ${newCode} > node_modules/is-even/node_modules/is-odd/index.js`.env(bunEnv).cwd(filedir);
}
const tempdir = tempDirWithFiles("unpatched", {
"package.json": JSON.stringify({
"name": "bun-patch-test",
"module": "index.ts",
"type": "module",
"dependencies": {
"is-even": "1.0.0",
},
}),
"index.ts": /* ts */ `import isEven from 'is-even'; console.log(isEven(420))`,
});
await $`${bunExe()} i`
.env(bunEnv)
.cwd(tempdir)
.then(o => expect(o.stderr.toString()).not.toContain("error"));
const { stdout, stderr } = await $`${bunExe()} run index.ts`.env(bunEnv).cwd(tempdir);
expect(stderr.toString()).toBe("");
expect(stdout.toString()).toBe("true\n");
}
});
});