Files
oh-my-pi/packages/utils/test/env.test.ts
T
roboomp 9f9c9758a1 fix(tui): prevented test env from suppressing interactive launch
Scoped test-runtime detection to explicit runner markers and Bun test entrypoints, so application NODE_ENV/BUN_ENV values no longer make ProcessTerminal headless.

Added subprocess regression coverage and propagated the private marker to test children.

Fixes #7261
2026-08-01 11:39:57 +00:00

153 lines
4.2 KiB
TypeScript

import { afterEach, describe, expect, it } from "bun:test";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { filterProcessEnv, parseEnvFile } from "@oh-my-pi/pi-utils/env";
const tempDirs: string[] = [];
const runtimeProbePath = path.join(import.meta.dir, "fixtures", "test-runtime-probe.ts");
afterEach(() => {
for (const dir of tempDirs.splice(0)) {
fs.rmSync(dir, { force: true, recursive: true });
}
});
function writeTempEnv(content: string): string {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-utils-env-"));
tempDirs.push(dir);
const filePath = path.join(dir, ".env");
fs.writeFileSync(filePath, content);
return filePath;
}
async function runRuntimeProbe(env: Record<string, string | undefined>): Promise<boolean> {
const cwd = path.dirname(writeTempEnv(""));
const proc = Bun.spawn([process.execPath, runtimeProbePath], {
cwd,
env: { ...process.env, ...env },
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
proc.exited,
]);
expect(exitCode, stderr).toBe(0);
return JSON.parse(stdout) as boolean;
}
describe("parseEnvFile", () => {
it("ignores malformed names and nul-containing values", () => {
const filePath = writeTempEnv(
[
"GOOD=value",
"_ALSO_GOOD='quoted value'",
"1BAD=value",
"BAD-NAME=value",
"BAD NAME=value",
"BAD_VALUE=before\0after",
"# comment",
"NO_EQUALS",
].join("\n"),
);
expect(parseEnvFile(filePath)).toEqual({
GOOD: "value",
_ALSO_GOOD: "quoted value",
});
});
it("mirrors valid OMP_ variables to PI_ variables", () => {
const filePath = writeTempEnv("OMP_FEATURE=enabled\nOMP_BAD=before\0after\n");
expect(parseEnvFile(filePath)).toEqual({
OMP_FEATURE: "enabled",
PI_FEATURE: "enabled",
});
});
it("matches Bun dotenv syntax for export prefixes and inline comments", () => {
const filePath = writeTempEnv(
[
"export EXPORTED=value",
"COMMENTED=secret # trailing comment",
'QUOTED_HASH="keep # this"',
"NO_SPACE=http://host/path#frag",
].join("\n"),
);
expect(parseEnvFile(filePath)).toEqual({
EXPORTED: "value",
COMMENTED: "secret",
QUOTED_HASH: "keep # this",
NO_SPACE: "http://host/path#frag",
});
});
it("keeps escaped quotes inside quoted values literal, matching Bun", () => {
const filePath = writeTempEnv(['JSON="{\\"a\\":1}"', "SINGLE='it\\'s'"].join("\n"));
expect(parseEnvFile(filePath)).toEqual({
JSON: '{\\"a\\":1}',
SINGLE: "it\\'s",
});
});
});
describe("filterProcessEnv", () => {
it("drops entries that cannot be passed to process spawn env", () => {
expect(
filterProcessEnv({
GOOD: "value",
EMPTY: "",
"BAD=NAME": "value",
BAD_VALUE: "before\0after",
MISSING: undefined,
}),
).toEqual({
GOOD: "value",
EMPTY: "",
});
});
it("drops macOS malloc stack logging toggles instead of forwarding disabled values", () => {
expect(
filterProcessEnv({
GOOD: "value",
MallocStackLogging: "0",
MallocStackLoggingNoCompact: "0",
}),
).toEqual({
GOOD: "value",
});
});
it("preserves Windows-style variable names containing parentheses", () => {
// `ProgramFiles(x86)` and friends are standard on Windows and must
// survive the scrub so Git Bash discovery in procmgr.ts can resolve
// 32-bit Program Files installations.
expect(
filterProcessEnv({
"ProgramFiles(x86)": "C:\\Program Files (x86)",
"CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files",
}),
).toEqual({
"ProgramFiles(x86)": "C:\\Program Files (x86)",
"CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files",
});
});
});
describe("isBunTestRuntime", () => {
it("does not treat shared application env names as a test runner signal", async () => {
expect(await runRuntimeProbe({ NODE_ENV: "test", BUN_ENV: undefined, PI_TEST_RUNTIME: undefined })).toBe(false);
expect(await runRuntimeProbe({ NODE_ENV: undefined, BUN_ENV: "test", PI_TEST_RUNTIME: undefined })).toBe(false);
});
it("honors the private test runner signal", async () => {
expect(await runRuntimeProbe({ NODE_ENV: undefined, BUN_ENV: undefined, PI_TEST_RUNTIME: "1" })).toBe(true);
});
});