Files
web-terminal/test/helpers/mock-pty.test.ts
Yaojia Wang 0fa0b69ce9 feat: W1 batch — config, protocol, ring-buffer, origin, mock-pty (TDD)
Parallel module-builder subagents, disjoint file ownership, shared tree:
- T4 src/config.ts        — loadConfig+M1 origins (32 tests)
- T5 src/protocol.ts      — parse/serialize+SESSION_ID_RE+M7 (60 tests)
- T6 src/session/ring-buffer.ts — byte-accurate, no UTF-8/ANSI split+M2 (15 tests)
- T7 src/http/origin.ts   — host+port match, undefined rejected (12 tests)
- T3 test/helpers/mock-pty.ts — IPty double w/ emitData/emitExit (9 tests)

Verified by orchestrator: tsc --noEmit clean; full suite 128 tests pass.
2026-06-16 08:09:40 +02:00

120 lines
2.8 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { createMockPty } from './mock-pty'
describe('createMockPty', () => {
it('emitData triggers all onData listeners', () => {
const pty = createMockPty()
const listener1Results: string[] = []
const listener2Results: string[] = []
pty.onData((data) => {
listener1Results.push(data)
})
pty.onData((data) => {
listener2Results.push(data)
})
pty.emitData('hello')
pty.emitData(' world')
expect(listener1Results).toEqual(['hello', ' world'])
expect(listener2Results).toEqual(['hello', ' world'])
})
it('onData returns a disposable that unsubscribes', () => {
const pty = createMockPty()
const results: string[] = []
const disposable = pty.onData((data) => {
results.push(data)
})
pty.emitData('first')
disposable.dispose()
pty.emitData('second')
expect(results).toEqual(['first'])
})
it('records write calls', () => {
const pty = createMockPty()
pty.write('input 1')
pty.write('input 2')
expect(pty.writes).toEqual(['input 1', 'input 2'])
})
it('records resize calls', () => {
const pty = createMockPty()
pty.resize(100, 50)
pty.resize(120, 60)
expect(pty.resizes).toEqual([
{ cols: 100, rows: 50 },
{ cols: 120, rows: 60 },
])
})
it('emitExit triggers onExit listeners', () => {
const pty = createMockPty()
const results: Array<{ exitCode: number; signal?: number }> = []
pty.onExit((event) => {
results.push(event)
})
pty.emitExit(0)
pty.emitExit(1, 9)
expect(results).toEqual([
{ exitCode: 0 },
{ exitCode: 1, signal: 9 },
])
})
it('onExit returns a disposable that unsubscribes', () => {
const pty = createMockPty()
const results: Array<{ exitCode: number; signal?: number }> = []
const disposable = pty.onExit((event) => {
results.push(event)
})
pty.emitExit(0)
disposable.dispose()
pty.emitExit(1)
expect(results).toEqual([{ exitCode: 0 }])
})
it('kill marks killed flag', () => {
const pty = createMockPty()
expect(pty.killed).toBe(false)
pty.kill()
expect(pty.killed).toBe(true)
})
it('kill can accept an optional signal', () => {
const pty = createMockPty()
pty.kill('SIGTERM')
expect(pty.killed).toBe(true)
})
it('has IPty interface properties', () => {
const pty = createMockPty()
expect(typeof pty.pid).toBe('number')
expect(typeof pty.cols).toBe('number')
expect(typeof pty.rows).toBe('number')
expect(typeof pty.onData).toBe('function')
expect(typeof pty.onExit).toBe('function')
expect(typeof pty.write).toBe('function')
expect(typeof pty.resize).toBe('function')
expect(typeof pty.kill).toBe('function')
})
})