test(web): cover direct terminal websocket URL selection

This commit is contained in:
Prateek 2026-03-08 04:21:41 +05:30
parent 40055eb0d1
commit 06011be6f0
2 changed files with 103 additions and 16 deletions

View File

@ -21,6 +21,40 @@ interface DirectTerminalProps {
height?: string;
}
interface DirectTerminalLocation {
protocol: string;
hostname: string;
host: string;
port: string;
}
interface DirectTerminalWsUrlOptions {
location: DirectTerminalLocation;
sessionId: string;
proxyWsPath?: string;
directTerminalPort?: string;
}
export function buildDirectTerminalWsUrl({
location,
sessionId,
proxyWsPath,
directTerminalPort,
}: DirectTerminalWsUrlOptions): string {
const protocol = location.protocol === "https:" ? "wss:" : "ws:";
if (proxyWsPath) {
// Path-based proxy uses host so non-standard ports are preserved.
return `${protocol}//${location.host}${proxyWsPath}?session=${encodeURIComponent(sessionId)}`;
}
if (location.port === "" || location.port === "443" || location.port === "80") {
return `${protocol}//${location.hostname}/ao-terminal-ws?session=${encodeURIComponent(sessionId)}`;
}
const port = directTerminalPort ?? "14801";
return `${protocol}//${location.hostname}:${port}/ws?session=${encodeURIComponent(sessionId)}`;
}
/**
* Direct xterm.js terminal with native WebSocket connection.
* Implements Extended Device Attributes (XDA) handler to enable
@ -186,22 +220,12 @@ export function DirectTerminal({
// WebSocket URL (stable across reconnects)
// When accessed via reverse proxy (HTTPS on standard port), use path-based
// WebSocket endpoint instead of direct port access.
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
const hostname = window.location.hostname;
const host = window.location.host;
const proxyWsPath = process.env.NEXT_PUBLIC_TERMINAL_WS_PATH;
let wsUrl: string;
if (proxyWsPath) {
// Path-based proxy (e.g. /ao-terminal-ws)
wsUrl = `${protocol}//${host}${proxyWsPath}?session=${encodeURIComponent(sessionId)}`;
} else if (window.location.port === "" || window.location.port === "443" || window.location.port === "80") {
// Behind reverse proxy on standard port — use path-based endpoint
wsUrl = `${protocol}//${hostname}/ao-terminal-ws?session=${encodeURIComponent(sessionId)}`;
} else {
// Direct access (dev mode) — use direct port
const port = process.env.NEXT_PUBLIC_DIRECT_TERMINAL_PORT ?? "14801";
wsUrl = `${protocol}//${hostname}:${port}/ws?session=${encodeURIComponent(sessionId)}`;
}
const wsUrl = buildDirectTerminalWsUrl({
location: window.location,
sessionId,
proxyWsPath: process.env.NEXT_PUBLIC_TERMINAL_WS_PATH,
directTerminalPort: process.env.NEXT_PUBLIC_DIRECT_TERMINAL_PORT,
});
// ── Preserve selection while terminal receives output ────────
// xterm.js clears the selection on every terminal.write(). We

View File

@ -0,0 +1,63 @@
import { describe, it, expect } from "vitest";
import { buildDirectTerminalWsUrl } from "@/components/DirectTerminal";
describe("buildDirectTerminalWsUrl", () => {
it("keeps non-standard port when proxy path override is set", () => {
const wsUrl = buildDirectTerminalWsUrl({
location: {
protocol: "https:",
hostname: "example.com",
host: "example.com:8443",
port: "8443",
},
sessionId: "session-1",
proxyWsPath: "/ao-terminal-ws",
});
expect(wsUrl).toBe("wss://example.com:8443/ao-terminal-ws?session=session-1");
});
it("uses proxy path without port when default port is used", () => {
const wsUrl = buildDirectTerminalWsUrl({
location: {
protocol: "https:",
hostname: "example.com",
host: "example.com",
port: "",
},
sessionId: "session-2",
proxyWsPath: "/ao-terminal-ws",
});
expect(wsUrl).toBe("wss://example.com/ao-terminal-ws?session=session-2");
});
it("uses default path-based endpoint on standard ports when no proxy override is set", () => {
const wsUrl = buildDirectTerminalWsUrl({
location: {
protocol: "https:",
hostname: "example.com",
host: "example.com",
port: "443",
},
sessionId: "session-3",
});
expect(wsUrl).toBe("wss://example.com/ao-terminal-ws?session=session-3");
});
it("uses direct terminal port on non-standard ports when no proxy override is set", () => {
const wsUrl = buildDirectTerminalWsUrl({
location: {
protocol: "http:",
hostname: "localhost",
host: "localhost:3000",
port: "3000",
},
sessionId: "session-4",
directTerminalPort: "14888",
});
expect(wsUrl).toBe("ws://localhost:14888/ws?session=session-4");
});
});