test(tui): isolate Herdr env in direct-terminal fixtures

This commit is contained in:
Chess Luo
2026-08-06 16:06:40 +08:00
parent c720597d43
commit 32d6421e84
12 changed files with 55 additions and 7 deletions
@@ -21,7 +21,15 @@ import type { TerminalAppearance, TerminalAppearanceRequestToken } from "@oh-my-
import { TempDir } from "@oh-my-pi/pi-utils";
import { VirtualTerminal } from "../../tui/test/virtual-terminal";
const MULTIPLEXER_ENV_KEYS = ["TMUX", "STY", "ZELLIJ", "CMUX_WORKSPACE_ID", "CMUX_SURFACE_ID", "TERM"] as const;
const MULTIPLEXER_ENV_KEYS = [
"TMUX",
"STY",
"ZELLIJ",
"HERDR_ENV",
"CMUX_WORKSPACE_ID",
"CMUX_SURFACE_ID",
"TERM",
] as const;
class AppearanceVirtualTerminal extends VirtualTerminal {
#appearance?: TerminalAppearance;
+12 -1
View File
@@ -1,4 +1,4 @@
import { describe, expect, it } from "bun:test";
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import {
type Component,
Container,
@@ -13,6 +13,17 @@ import { StressRenderScheduler } from "./render-stress-scheduler";
import { defaultEditorTheme } from "./test-themes";
import { VirtualTerminal } from "./virtual-terminal";
const ORIGINAL_HERDR_ENV = Bun.env.HERDR_ENV;
beforeEach(() => {
delete Bun.env.HERDR_ENV;
});
afterEach(() => {
if (ORIGINAL_HERDR_ENV === undefined) delete Bun.env.HERDR_ENV;
else Bun.env.HERDR_ENV = ORIGINAL_HERDR_ENV;
});
// Behavioral tests for TUI.requestComponentRender: a component whose own
// content changed (spinner frame, blink) asks for a component-scoped frame.
// When every request since the last frame is component-scoped and the frame is
+4
View File
@@ -29,14 +29,18 @@ const BASE64_ONE_PIXEL_PNG =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNgAAAAAgABSK+kcQAAAABJRU5ErkJggg==";
const ORIGINAL_TMUX = Bun.env.TMUX;
const ORIGINAL_HERDR_ENV = Bun.env.HERDR_ENV;
beforeEach(() => {
delete Bun.env.TMUX;
delete Bun.env.HERDR_ENV;
});
afterEach(() => {
if (ORIGINAL_TMUX === undefined) delete Bun.env.TMUX;
else Bun.env.TMUX = ORIGINAL_TMUX;
if (ORIGINAL_HERDR_ENV === undefined) delete Bun.env.HERDR_ENV;
else Bun.env.HERDR_ENV = ORIGINAL_HERDR_ENV;
});
/** Drive one render pass against the budget with `count` images (ids 1..count, stable across passes). */
+8 -1
View File
@@ -1,4 +1,4 @@
import { afterEach, describe, expect, it, vi } from "bun:test";
import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
import { type Component, type RenderScheduler, type RenderTimer, TUI } from "@oh-my-pi/pi-tui";
import { VirtualTerminal } from "./virtual-terminal";
@@ -13,6 +13,7 @@ import { VirtualTerminal } from "./virtual-terminal";
// replay crossed ~1-2 MiB.
const PLATFORM_DESCRIPTOR = Object.getOwnPropertyDescriptor(process, "platform");
const ORIGINAL_HERDR_ENV = Bun.env.HERDR_ENV;
class LargeCjkContent implements Component {
#lines: string[];
@@ -85,9 +86,15 @@ class ManualRenderScheduler implements RenderScheduler {
}
}
beforeEach(() => {
delete Bun.env.HERDR_ENV;
});
describe("issue #2115: ConPTY large-session resume truncates at logical lines", () => {
afterEach(() => {
if (PLATFORM_DESCRIPTOR) Object.defineProperty(process, "platform", PLATFORM_DESCRIPTOR);
if (ORIGINAL_HERDR_ENV === undefined) delete Bun.env.HERDR_ENV;
else Bun.env.HERDR_ENV = ORIGINAL_HERDR_ENV;
vi.restoreAllMocks();
});
+8 -1
View File
@@ -1,4 +1,4 @@
import { afterEach, describe, expect, it, vi } from "bun:test";
import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
import { type Component, TUI } from "@oh-my-pi/pi-tui";
import { VirtualTerminal } from "./virtual-terminal";
@@ -15,6 +15,7 @@ import { VirtualTerminal } from "./virtual-terminal";
const PLATFORM_DESCRIPTOR = Object.getOwnPropertyDescriptor(process, "platform");
const WSL_DISTRO_NAME = process.env.WSL_DISTRO_NAME;
const TMUX = process.env.TMUX;
const HERDR_ENV = process.env.HERDR_ENV;
// A full paint clears the viewport with ED2 (`CSI 2 J`), or — when it also
// clears native scrollback — homes the cursor and emits ED3 (`CSI H CSI 3 J`)
@@ -41,6 +42,10 @@ class LargeContent implements Component {
}
}
beforeEach(() => {
delete process.env.HERDR_ENV;
});
describe("issue #4863: Ctrl+O full-view expand truncates the session on ConPTY", () => {
afterEach(() => {
if (PLATFORM_DESCRIPTOR) Object.defineProperty(process, "platform", PLATFORM_DESCRIPTOR);
@@ -48,6 +53,8 @@ describe("issue #4863: Ctrl+O full-view expand truncates the session on ConPTY",
else process.env.WSL_DISTRO_NAME = WSL_DISTRO_NAME;
if (TMUX === undefined) delete process.env.TMUX;
else process.env.TMUX = TMUX;
if (HERDR_ENV === undefined) delete process.env.HERDR_ENV;
else process.env.HERDR_ENV = HERDR_ENV;
vi.restoreAllMocks();
});
+1
View File
@@ -205,6 +205,7 @@ describe("Raw 0x08 backspace disambiguation", () => {
"TMUX",
"STY",
"ZELLIJ",
"HERDR_ENV",
"TERM",
"CMUX_WORKSPACE_ID",
"CMUX_SURFACE_ID",
+3
View File
@@ -19,6 +19,7 @@ const stdinSetRawModeDescriptor = Object.getOwnPropertyDescriptor(process.stdin,
const originalOsc99Probe = Bun.env.PI_TUI_OSC99_PROBE;
const originalTmux = Bun.env.TMUX;
const originalZellij = Bun.env.ZELLIJ;
const originalHerdrEnv = Bun.env.HERDR_ENV;
const originalPiNotifications = Bun.env.PI_NOTIFICATIONS;
const originalCmuxSurfaceId = Bun.env.CMUX_SURFACE_ID;
const originalCmuxWorkspaceId = Bun.env.CMUX_WORKSPACE_ID;
@@ -77,6 +78,7 @@ describe("terminal notifications", () => {
// assertions never see a stray inherited TMUX leaking the DCS wrap in.
delete Bun.env.TMUX;
delete Bun.env.ZELLIJ;
delete Bun.env.HERDR_ENV;
delete Bun.env.CMUX_SURFACE_ID;
delete Bun.env.CMUX_WORKSPACE_ID;
delete Bun.env.CMUX_SOCKET_PATH;
@@ -94,6 +96,7 @@ describe("terminal notifications", () => {
restoreEnv("PI_TUI_OSC99_PROBE", originalOsc99Probe);
restoreEnv("TMUX", originalTmux);
restoreEnv("ZELLIJ", originalZellij);
restoreEnv("HERDR_ENV", originalHerdrEnv);
restoreEnv("PI_NOTIFICATIONS", originalPiNotifications);
restoreEnv("CMUX_SURFACE_ID", originalCmuxSurfaceId);
restoreEnv("CMUX_WORKSPACE_ID", originalCmuxWorkspaceId);
@@ -13,6 +13,7 @@ const ENV: Record<string, string | undefined> = {
TMUX: undefined,
STY: undefined,
ZELLIJ: undefined,
HERDR_ENV: undefined,
CMUX_WORKSPACE_ID: undefined,
CMUX_SURFACE_ID: undefined,
CMUX_REMOTE_TRANSPORT: undefined,
+1 -1
View File
@@ -173,7 +173,7 @@ describe("TUI overlays", () => {
// A resize on Warp takes the in-place path (no ED3), so neutralize the
// ambient terminal identity to keep the direct-terminal resize/scrollback
// assertions below deterministic on any dev machine.
for (const key of ["TERM_PROGRAM", "PI_TUI_RESIZE_IN_PLACE"]) {
for (const key of ["TERM_PROGRAM", "PI_TUI_RESIZE_IN_PLACE", "HERDR_ENV"]) {
savedTerminalEnv[key] = Bun.env[key];
delete Bun.env[key];
}
+6 -1
View File
@@ -223,7 +223,7 @@ describe("TUI terminal-state regressions", () => {
// Resize classification now depends on TERM_PROGRAM (Warp takes the
// in-place path), so neutralize the ambient terminal identity to keep
// these direct-terminal assertions deterministic on any dev machine.
for (const key of ["TERM_PROGRAM", "PI_TUI_RESIZE_IN_PLACE"]) {
for (const key of ["TERM_PROGRAM", "PI_TUI_RESIZE_IN_PLACE", "HERDR_ENV"]) {
savedTerminalEnv[key] = Bun.env[key];
delete Bun.env[key];
}
@@ -4215,7 +4215,10 @@ describe("TUI terminal-state regressions", () => {
});
describe("foreground-tool streaming on ED3-risk terminals", () => {
let originalHerdrEnv: string | undefined;
beforeEach(() => {
originalHerdrEnv = Bun.env.HERDR_ENV;
delete Bun.env.HERDR_ENV;
let monotonicNow = 0;
vi.spyOn(performance, "now").mockImplementation(() => {
monotonicNow += 20;
@@ -4224,6 +4227,8 @@ describe("foreground-tool streaming on ED3-risk terminals", () => {
});
afterEach(() => {
if (originalHerdrEnv === undefined) delete Bun.env.HERDR_ENV;
else Bun.env.HERDR_ENV = originalHerdrEnv;
vi.restoreAllMocks();
});
@@ -21,6 +21,7 @@ const NO_MULTIPLEXER_ENV: Record<string, string | undefined> = {
TMUX: undefined,
STY: undefined,
ZELLIJ: undefined,
HERDR_ENV: undefined,
CMUX_WORKSPACE_ID: undefined,
CMUX_SURFACE_ID: undefined,
CMUX_REMOTE_TRANSPORT: undefined,
@@ -179,7 +179,7 @@ function saveTerminalEnv(): Record<string, string | undefined> {
// ambient terminal identity to keep the direct-terminal scrollback
// assertions deterministic on any dev machine.
const saved: Record<string, string | undefined> = {};
for (const key of ["TERM_PROGRAM", "PI_TUI_RESIZE_IN_PLACE"]) {
for (const key of ["TERM_PROGRAM", "PI_TUI_RESIZE_IN_PLACE", "HERDR_ENV"]) {
saved[key] = Bun.env[key];
delete Bun.env[key];
}