fix: reset xterm before terminal reconnect (#1342)
This commit is contained in:
@@ -3,6 +3,8 @@ import { buildTerminalWsUrl } from "./use-passthrough-terminal";
|
||||
import { reconnectDelayMs, startReconnectLoop } from "./ws-reconnect";
|
||||
import type { Terminal } from "@xterm/xterm";
|
||||
|
||||
const WS_BASE_URL = "ws://localhost:38429";
|
||||
|
||||
describe("reconnectDelayMs", () => {
|
||||
it("returns 300ms for attempt 0", () => {
|
||||
expect(reconnectDelayMs(0)).toBe(300);
|
||||
@@ -29,7 +31,7 @@ describe("reconnectDelayMs", () => {
|
||||
describe("buildTerminalWsUrl", () => {
|
||||
it("routes shell terminals by task environment ID", () => {
|
||||
expect(
|
||||
buildTerminalWsUrl("ws://localhost:38429", {
|
||||
buildTerminalWsUrl(WS_BASE_URL, {
|
||||
mode: "shell",
|
||||
environmentId: "env-1",
|
||||
terminalId: "terminal with spaces",
|
||||
@@ -39,7 +41,7 @@ describe("buildTerminalWsUrl", () => {
|
||||
|
||||
it("routes agent terminals by session ID", () => {
|
||||
expect(
|
||||
buildTerminalWsUrl("ws://localhost:38429", {
|
||||
buildTerminalWsUrl(WS_BASE_URL, {
|
||||
mode: "agent",
|
||||
sessionId: "session-1",
|
||||
}),
|
||||
@@ -62,11 +64,11 @@ describe("startReconnectLoop", () => {
|
||||
|
||||
const stop = startReconnectLoop({
|
||||
environmentId: "env-1",
|
||||
wsBaseUrl: "ws://localhost:38429",
|
||||
wsBaseUrl: WS_BASE_URL,
|
||||
mode: "shell",
|
||||
terminalId: "shell-1",
|
||||
label: undefined,
|
||||
terminal: {} as Terminal,
|
||||
terminal: { reset: vi.fn() } as unknown as Terminal,
|
||||
fitAndResize: vi.fn(),
|
||||
wsRef: { current: null },
|
||||
attachAddonRef: { current: null },
|
||||
@@ -81,4 +83,43 @@ describe("startReconnectLoop", () => {
|
||||
expect(onDisconnected).toHaveBeenCalledTimes(1);
|
||||
stop();
|
||||
});
|
||||
|
||||
it("resets xterm before each connection so replayed PTY buffers do not append duplicates", () => {
|
||||
vi.useFakeTimers();
|
||||
|
||||
const terminal = { reset: vi.fn() } as unknown as Terminal;
|
||||
let closes = 0;
|
||||
const connectWebSocket = vi.fn(({ onSocketClose }) => {
|
||||
if (closes < 1) {
|
||||
closes += 1;
|
||||
onSocketClose({ code: 1006 } as CloseEvent);
|
||||
}
|
||||
});
|
||||
|
||||
const stop = startReconnectLoop({
|
||||
environmentId: "env-1",
|
||||
wsBaseUrl: WS_BASE_URL,
|
||||
mode: "shell",
|
||||
terminalId: "shell-1",
|
||||
label: undefined,
|
||||
terminal,
|
||||
fitAndResize: vi.fn(),
|
||||
wsRef: { current: null },
|
||||
attachAddonRef: { current: null },
|
||||
onConnected: vi.fn(),
|
||||
onDisconnected: vi.fn(),
|
||||
connectWebSocket,
|
||||
});
|
||||
|
||||
vi.advanceTimersByTime(150);
|
||||
|
||||
expect(connectWebSocket).toHaveBeenCalledTimes(1);
|
||||
expect(terminal.reset).toHaveBeenCalledTimes(1);
|
||||
|
||||
vi.advanceTimersByTime(300);
|
||||
|
||||
expect(connectWebSocket).toHaveBeenCalledTimes(2);
|
||||
expect(terminal.reset).toHaveBeenCalledTimes(2);
|
||||
stop();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -95,6 +95,10 @@ export function startReconnectLoop({
|
||||
if (connectTimeout) clearTimeout(connectTimeout);
|
||||
connectTimeout = setTimeout(() => {
|
||||
if (!isMounted) return;
|
||||
// The backend replays the PTY buffer whenever a terminal WebSocket
|
||||
// reconnects. Clear the existing xterm contents first so replay replaces
|
||||
// the visible terminal instead of appending duplicate prompt lines.
|
||||
terminal.reset();
|
||||
connectWebSocket({
|
||||
sessionId,
|
||||
environmentId,
|
||||
|
||||
Reference in New Issue
Block a user