Files
bun.sh/test/cli/run/run-eval.test.ts
2025-02-24 15:39:47 -08:00

199 lines
6.4 KiB
TypeScript

import { SyncSubprocess } from "bun";
import { describe, expect, test } from "bun:test";
import { rmSync, writeFileSync } from "fs";
import { bunEnv, bunExe, isWindows, tmpdirSync } from "harness";
import { tmpdir } from "os";
import { join, sep } from "path";
for (const flag of ["-e", "--print"]) {
describe(`bun ${flag}`, () => {
test("it works", async () => {
const input = flag === "--print" ? '"hello world"' : 'console.log("hello world")';
let { stdout } = Bun.spawnSync({
cmd: [bunExe(), flag, input],
env: bunEnv,
});
expect(stdout.toString("utf8")).toEqual("hello world\n");
});
test("import, tsx, require in esm, import.meta", async () => {
const ref = await import("react");
const input =
flag === "--print"
? 'import {version} from "react"; console.log(JSON.stringify({version,file:import.meta.path,require:require("react").version})); <hello>world</hello>'
: 'import {version} from "react"; console.log(JSON.stringify({version,file:import.meta.path,require:require("react").version})); console.log(<hello>world</hello>);';
let { stdout } = Bun.spawnSync({
cmd: [bunExe(), flag, input],
env: bunEnv,
});
const json = {
version: ref.version,
file: join(process.cwd(), "[eval]"),
require: ref.version,
};
expect(stdout.toString("utf8")).toEqual(JSON.stringify(json) + "\n<hello>world</hello>\n");
});
test("error has source map info 1", async () => {
let { stderr } = Bun.spawnSync({
cmd: [bunExe(), flag, '(throw new Error("hi" as 2))'],
env: bunEnv,
});
expect(stderr.toString("utf8")).toInclude('"hi" as 2');
expect(stderr.toString("utf8")).toInclude("Unexpected throw");
});
test("process.argv", async () => {
function testProcessArgv(args: string[], expected: string[]) {
const input = flag === "--print" ? "process.argv" : "console.log(process.argv)";
let { stdout, stderr, exitCode } = Bun.spawnSync({
cmd: [bunExe(), flag, input, ...args],
env: bunEnv,
});
expect(stderr.toString("utf8")).toBe("");
expect(JSON.parse(stdout.toString("utf8"))).toEqual(expected);
expect(exitCode).toBe(0);
}
// replace the trailin
const exe = isWindows ? bunExe().replaceAll("/", "\\") : bunExe();
testProcessArgv([], [exe]);
testProcessArgv(["abc", "def"], [exe, "abc", "def"]);
testProcessArgv(["--", "abc", "def"], [exe, "abc", "def"]);
// testProcessArgv(["--", "abc", "--", "def"], [exe, "abc", "--", "def"]);
});
});
}
describe("--print for cjs/esm", () => {
test("eval result between esm imports", async () => {
let cwd = tmpdirSync();
writeFileSync(join(cwd, "foo.js"), "'foo'");
writeFileSync(join(cwd, "bar.js"), "'bar'");
let { stdout, stderr, exitCode } = Bun.spawnSync({
cmd: [bunExe(), "--print", 'import "./foo.js"; 123; import "./bar.js"'],
cwd: cwd,
env: bunEnv,
});
expect(stderr.toString("utf8")).toBe("");
expect(stdout.toString("utf8")).toEqual("123\n");
expect(exitCode).toBe(0);
rmSync(cwd, { recursive: true, force: true });
});
test("forced cjs", async () => {
let { stdout, stderr, exitCode } = Bun.spawnSync({
cmd: [bunExe(), "--print", "module.exports; 123"],
env: bunEnv,
});
expect(stderr.toString("utf8")).toBe("");
expect(stdout.toString("utf8")).toEqual("123\n");
expect(exitCode).toBe(0);
});
test("module, exports, require, __filename, __dirname", async () => {
let { stdout, stderr, exitCode } = Bun.spawnSync({
cmd: [
bunExe(),
"--print",
`
console.log(typeof module, typeof exports, typeof require, typeof __filename, typeof __dirname); 123
`,
],
env: bunEnv,
});
expect(stderr.toString("utf8")).toBe("");
expect(stdout.toString("utf8")).toEqual("object object function string string\n123\n");
expect(exitCode).toBe(0);
});
});
function group(run: (code: string) => SyncSubprocess<"pipe", "inherit">) {
test("it works", async () => {
const { stdout } = run('console.log("hello world")');
expect(stdout.toString("utf8")).toEqual("hello world\n");
});
test("it gets a correct specifer", async () => {
const { stdout } = run("console.log(import.meta.path)");
expect(stdout.toString("utf8")).toEndWith(sep + "[stdin]\n");
});
test("it can require", async () => {
const { stdout } = run(`
const process = require("node:process");
console.log(process.platform);
`);
expect(stdout.toString("utf8")).toEqual(process.platform + "\n");
});
test("it can import", async () => {
const { stdout } = run(`
import * as process from "node:process";
console.log(process.platform);
`);
expect(stdout.toString("utf8")).toEqual(process.platform + "\n");
});
test("process.argv", async () => {
const { stdout } = run("console.log(process.argv)");
const exe = isWindows ? bunExe().replaceAll("/", "\\") : bunExe();
expect(JSON.parse(stdout.toString("utf8"))).toEqual([exe, "-"]);
});
}
describe("bun run - < file-path.js", () => {
function run(code: string) {
// bash only supports / as path separator
const file = join(tmpdir(), "bun-run-eval-test.js").replaceAll("\\", "/");
require("fs").writeFileSync(file, code);
try {
let result;
if (process.platform === "win32") {
result = Bun.spawnSync(["powershell", "-c", `Get-Content ${file} | ${bunExe()} run -`], {
env: bunEnv,
stderr: "inherit",
});
} else {
result = Bun.spawnSync(["bash", "-c", `${bunExe()} run - < ${file}`], {
env: bunEnv,
stderr: "inherit",
});
}
if (!result.success) {
queueMicrotask(() => {
throw new Error("bun run - < file-path.js failed");
});
}
return result;
} finally {
try {
require("fs").unlinkSync(file);
} catch (e) {}
}
}
group(run);
});
describe("echo | bun run -", () => {
function run(code: string) {
const result = Bun.spawnSync([bunExe(), "run", "-"], {
env: bunEnv,
stdin: Buffer.from(code),
stderr: "inherit",
});
if (!result.success) {
queueMicrotask(() => {
throw new Error("bun run - failed");
});
}
return result;
}
group(run);
});