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
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Bun test-runtime detection treating application-owned `NODE_ENV=test` and `BUN_ENV=test` values as test-runner signals ([#7261](https://github.com/can1357/oh-my-pi/issues/7261)).
|
||||
|
||||
## [17.2.1] - 2026-07-30
|
||||
|
||||
### Added
|
||||
|
||||
@@ -258,9 +258,13 @@ export function $envpos(name: string, defaultValue: number): number {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/** True when `BUN_ENV` or `NODE_ENV` is the string `test`. */
|
||||
const BUN_TEST_ENTRY_PATTERN = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
||||
|
||||
/** True when the process is an explicitly marked test child or Bun is running a test entrypoint. */
|
||||
export function isBunTestRuntime(): boolean {
|
||||
return Bun.env.BUN_ENV === "test" || Bun.env.NODE_ENV === "test";
|
||||
if (Bun.env.PI_TEST_RUNTIME === "1") return true;
|
||||
const hasTestEnvironment = Bun.env.BUN_ENV === "test" || Bun.env.NODE_ENV === "test";
|
||||
return hasTestEnvironment && BUN_TEST_ENTRY_PATTERN.test(Bun.main);
|
||||
}
|
||||
|
||||
let terminalHeadless = isBunTestRuntime();
|
||||
|
||||
@@ -5,6 +5,7 @@ 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)) {
|
||||
@@ -20,6 +21,23 @@ function writeTempEnv(content: string): string {
|
||||
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(
|
||||
@@ -121,3 +139,14 @@ describe("filterProcessEnv", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { isBunTestRuntime } from "@oh-my-pi/pi-utils/env";
|
||||
|
||||
process.stdout.write(JSON.stringify(isBunTestRuntime()));
|
||||
Reference in New Issue
Block a user