import { describe, test, expect } from "bun:test"; import { bunExe, fakeNodeRun, tempDirWithFiles } from "../../harness"; import { join } from "path"; describe("fake node cli", () => { test("the node cli actually works", () => { const temp = tempDirWithFiles("fake-node", { "index.ts": "console.log(Bun.version)", }); expect(fakeNodeRun(temp, join(temp, "index.ts")).stdout).toBe(Bun.version); }); test("doesnt resolve bins", () => { const temp = tempDirWithFiles("fake-node", { "vite.js": "console.log('pass')", "node_modules/.bin/vite": "#!/usr/bin/sh\necho fail && exit 1", }); expect(fakeNodeRun(temp, "vite").stdout).toBe("pass"); }); test("doesnt resolve scripts", () => { const temp = tempDirWithFiles("fake-node", { "vite.js": "console.log('pass')", "package.json": '{"scripts":{"vite":"echo fail && exit 1"}}', }); expect(fakeNodeRun(temp, "vite").stdout).toBe("pass"); }); test("can run a script named run.js", () => { const temp = tempDirWithFiles("fake-node", { "run.js": "console.log('pass')", "run/index.js": "console.log('fail')", "node_modules/run/index.js": "console.log('fail')", }); expect(fakeNodeRun(temp, "run").stdout).toBe("pass"); }); describe("entrypoint file extension picking", () => { // Bun supports JSX and TS, and node doesnt, so our behavior here differs a bit // Hopefully these priorization rules will not break any node apps. test("picks tsx over any other ext", () => { const temp = tempDirWithFiles("fake-node", { "build.js": "console.log('fail (build.js)')", "build.jsx": "console.log('fail (build.jsx)')", "build.cjs": "console.log('fail (build.cjs)')", "build.mjs": "console.log('fail (build.mjs)')", "build.ts": "console.log('fail (build.ts)')", "build.cts": "console.log('fail (build.cts)')", "build.mts": "console.log('fail (build.mts)')", "build.tsx": "console.log('pass')", }); expect(fakeNodeRun(temp, "build").stdout).toBe("pass"); }); test("picks jsx over ts", () => { const temp = tempDirWithFiles("fake-node", { "build.js": "console.log('fail (build.js)')", "build.jsx": "console.log('pass')", "build.cjs": "console.log('fail (build.cjs)')", "build.mjs": "console.log('fail (build.mjs)')", "build.ts": "console.log('fail (build.ts)')", "build.cts": "console.log('fail (build.cts)')", "build.mts": "console.log('fail (build.mts)')", }); expect(fakeNodeRun(temp, "build").stdout).toBe("pass"); }); test("picks mts over ts", () => { const temp = tempDirWithFiles("fake-node", { "build.js": "console.log('fail (build.js)')", "build.cjs": "console.log('fail (build.cjs)')", "build.mjs": "console.log('fail (build.mjs)')", "build.ts": "console.log('fail (build.ts)')", "build.cts": "console.log('fail (build.cts)')", "build.mts": "console.log('pass')", }); expect(fakeNodeRun(temp, "build").stdout).toBe("pass"); }); test("picks ts over js/cjs/etc", () => { const temp = tempDirWithFiles("fake-node", { "build.js": "console.log('fail (build.js)')", "build.cjs": "console.log('fail (build.cjs)')", "build.mjs": "console.log('fail (build.mjs)')", "build.ts": "console.log('pass')", "build.cts": "console.log('fail (build.cts)')", }); expect(fakeNodeRun(temp, "build").stdout).toBe("pass"); }); }); test("node -e ", () => { const temp = tempDirWithFiles("fake-node", {}); expect(fakeNodeRun(temp, ["-e", "console.log('pass')"]).stdout).toBe("pass"); }); test("process args work", () => { const temp = tempDirWithFiles("fake-node", { "index.js": "console.log(JSON.stringify(process.argv.slice(1)))", }); expect(fakeNodeRun(temp, ["index", "a", "b", "c"]).stdout).toBe( // note: no extension here is INTENTIONAL JSON.stringify([join(temp, "index"), "a", "b", "c"]), ); }); test("no args is exit code zero for now", () => { const temp = tempDirWithFiles("fake-node", {}); expect(() => fakeNodeRun(temp, [])).toThrow(); }); });