import { describe, expect, it, vi } from 'vitest' import { deriveContentKey, encodeEnvelope, openReplayCiphertext, randomBytes, sealReplayFrame } from 'relay-e2e' // Mock the xterm modules so the DEFAULT (non-injected) terminal loaders run without a real canvas. const writes: string[] = [] vi.mock('@xterm/xterm', () => ({ Terminal: class { cols = 80 rows = 24 constructor(_opts?: unknown) {} loadAddon(_a: unknown): void {} open(_el: unknown): void {} write(data: string): void { writes.push(data) } onData(_cb: (d: string) => void): void {} dispose(): void {} }, })) vi.mock('@xterm/addon-fit', () => ({ FitAddon: class { fit(): void {} }, })) import { mountTerminalView } from '../src/terminal-view' import { mountPreviewClient, type ReplaySource } from '../src/preview-client' import type { TerminalTransport } from '../src/ws-transport' const tick = () => new Promise((r) => setTimeout(r, 0)) describe('default (real-xterm) loaders behind the DI seam', () => { it('mountTerminalView loads the default xterm + FitAddon and sends attach', async () => { const root = document.createElement('div') Object.defineProperty(root, 'clientWidth', { value: 100 }) Object.defineProperty(root, 'clientHeight', { value: 100 }) const sent: Uint8Array[] = [] const transport: TerminalTransport = { open: async () => {}, send: (b) => sent.push(b), onMessage: () => {}, onClose: () => {}, close: () => {}, } const view = mountTerminalView(root, transport) // NO createTerminal → default loader path await tick() await tick() const first = JSON.parse(new TextDecoder().decode(sent[0]!)) expect(first.type).toBe('attach') view.dispose() }) it('mountPreviewClient renders via the default read-only xterm loader', async () => { const secret = randomBytes(32) const k = deriveContentKey({ hostContentSecret: secret, sessionId: 's', alg: 'aes-256-gcm' }) const replay: ReplaySource = { sessionId: 's', alg: 'aes-256-gcm', frames: [encodeEnvelope(sealReplayFrame(k, 0n, new TextEncoder().encode('DEFAULT-XTERM')))], } const card = document.createElement('div') const client = mountPreviewClient(card, replay, secret, { cols: 80, rows: 24 }, { deriveContentKey, openReplayCiphertext, }) await client.render() await tick() await tick() expect(writes).toContain('DEFAULT-XTERM') client.dispose() }) })