Files
oh-my-pi/packages/tui/test/sixel-probe.test.ts
T
roboomp 6eb9574436 fix(tui): ran sixel probe under wsl windows terminal
The SIXEL capability probe gated on process.platform === "win32", but
under WSL process.platform is "linux", so the probe never ran and inline
images fell back to the text placeholder even on Sixel-capable Windows
Terminal. Gate on isConPTYHosted() (native win32 or WSL) instead; the
existing WT_SESSION and TTY requirements still scope it to WT.

Fixes #6009
2026-08-04 02:55:38 +00:00

135 lines
5.1 KiB
TypeScript

import { afterEach, describe, expect, it } from "bun:test";
import { ImageProtocol, setTerminalImageProtocol, TERMINAL, TUI } from "@oh-my-pi/pi-tui";
import { VirtualTerminal } from "./virtual-terminal";
type MutableTerminalInfo = {
imageProtocol: ImageProtocol | null;
};
const terminalInfo = TERMINAL as unknown as MutableTerminalInfo;
const originalProtocol = TERMINAL.imageProtocol;
const originalWtSession = Bun.env.WT_SESSION;
const originalWslDistro = Bun.env.WSL_DISTRO_NAME;
const originalWslInterop = Bun.env.WSL_INTEROP;
const stdinIsTtyDescriptor = Object.getOwnPropertyDescriptor(process.stdin, "isTTY");
const stdoutIsTtyDescriptor = Object.getOwnPropertyDescriptor(process.stdout, "isTTY");
function restoreIsTty(
stream: NodeJS.ReadStream | NodeJS.WriteStream,
descriptor: PropertyDescriptor | undefined,
): void {
if (descriptor) {
Object.defineProperty(stream, "isTTY", descriptor);
return;
}
delete (stream as unknown as { isTTY?: boolean }).isTTY;
}
describe("TUI SIXEL capability probe", () => {
afterEach(() => {
setTerminalImageProtocol(originalProtocol);
terminalInfo.imageProtocol = originalProtocol;
if (originalWtSession === undefined) delete Bun.env.WT_SESSION;
else Bun.env.WT_SESSION = originalWtSession;
if (originalWslDistro === undefined) delete Bun.env.WSL_DISTRO_NAME;
else Bun.env.WSL_DISTRO_NAME = originalWslDistro;
if (originalWslInterop === undefined) delete Bun.env.WSL_INTEROP;
else Bun.env.WSL_INTEROP = originalWslInterop;
restoreIsTty(process.stdin, stdinIsTtyDescriptor);
restoreIsTty(process.stdout, stdoutIsTtyDescriptor);
});
it("enables SIXEL only after positive terminal capability response", () => {
if (process.platform !== "win32") return;
setTerminalImageProtocol(null);
terminalInfo.imageProtocol = null;
Bun.env.WT_SESSION = "test-wt-session";
Object.defineProperty(process.stdin, "isTTY", { value: true, configurable: true });
Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
const terminal = new VirtualTerminal(80, 24);
const tui = new TUI(terminal);
tui.start();
terminal.sendInput("\x1b[?1;2;4c");
expect(TERMINAL.imageProtocol).toBe(ImageProtocol.Sixel);
tui.stop();
});
it("enables SIXEL when DA and graphics replies are coalesced in one chunk", () => {
if (process.platform !== "win32") return;
setTerminalImageProtocol(null);
terminalInfo.imageProtocol = null;
Bun.env.WT_SESSION = "test-wt-session";
Object.defineProperty(process.stdin, "isTTY", { value: true, configurable: true });
Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
const terminal = new VirtualTerminal(80, 24);
const tui = new TUI(terminal);
tui.start();
terminal.sendInput("\x1b[?1;2;4c\x1b[?2;1;0S");
expect(TERMINAL.imageProtocol).toBe(ImageProtocol.Sixel);
tui.stop();
});
it("enables SIXEL when DA reply arrives split across chunks", () => {
if (process.platform !== "win32") return;
setTerminalImageProtocol(null);
terminalInfo.imageProtocol = null;
Bun.env.WT_SESSION = "test-wt-session";
Object.defineProperty(process.stdin, "isTTY", { value: true, configurable: true });
Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
const terminal = new VirtualTerminal(80, 24);
const tui = new TUI(terminal);
tui.start();
terminal.sendInput("\x1b[?1;2;");
terminal.sendInput("4c");
expect(TERMINAL.imageProtocol).toBe(ImageProtocol.Sixel);
tui.stop();
});
it("keeps SIXEL disabled when capability responses are negative", () => {
if (process.platform !== "win32") return;
setTerminalImageProtocol(null);
terminalInfo.imageProtocol = null;
Bun.env.WT_SESSION = "test-wt-session";
Object.defineProperty(process.stdin, "isTTY", { value: true, configurable: true });
Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
const terminal = new VirtualTerminal(80, 24);
const tui = new TUI(terminal);
tui.start();
terminal.sendInput("\x1b[?1;2c");
terminal.sendInput("\x1b[?2;0;0S");
expect(TERMINAL.imageProtocol).toBeNull();
tui.stop();
});
it("enables SIXEL under WSL + Windows Terminal (process.platform is linux)", () => {
// Regression for #6009: inside WSL, process.platform reports "linux" even
// though the host is Windows Terminal. The probe used to gate on
// process.platform === "win32", so WSL sessions never negotiated SIXEL and
// fell back to the text image card. It now gates on isConPTYHosted(), which
// treats WSL (WSL_DISTRO_NAME/WSL_INTEROP) as a Windows host.
if (process.platform !== "linux") return;
setTerminalImageProtocol(null);
terminalInfo.imageProtocol = null;
Bun.env.WT_SESSION = "test-wt-session";
Bun.env.WSL_DISTRO_NAME = "Ubuntu";
Object.defineProperty(process.stdin, "isTTY", { value: true, configurable: true });
Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
const terminal = new VirtualTerminal(80, 24);
const tui = new TUI(terminal);
tui.start();
terminal.sendInput("\x1b[?1;2;4c");
expect(TERMINAL.imageProtocol).toBe(ImageProtocol.Sixel);
tui.stop();
});
});