orca/tests/e2e/terminal-typing-latency.spe...

112 lines
3.7 KiB
TypeScript

import type { Page } from '@stablyai/playwright-test'
import { randomUUID } from 'node:crypto'
import { rmSync, writeFileSync } from 'node:fs'
import path from 'node:path'
import { test, expect } from './helpers/orca-app'
import {
focusActiveTerminalInput,
getTerminalContent,
waitForActivePanePtyId,
waitForActiveTerminalManager,
waitForTerminalOutput,
sendToTerminal
} from './helpers/terminal'
import { ensureTerminalVisible, waitForActiveWorktree, waitForSessionReady } from './helpers/store'
const KEY_LATENCY_SAMPLES = 'abcdefghijklmnop'
const MAX_MEDIAN_KEY_LATENCY_MS = 250
const MAX_WORST_KEY_LATENCY_MS = 1_000
function interactivePromptScript(runId: string): string {
return `
process.stdin.setEncoding('utf8')
if (process.stdin.isTTY) process.stdin.setRawMode(true)
process.stdin.resume()
let seq = 0
const interrupt = String.fromCharCode(3)
process.stdout.write('\\x1b]0;Terminal typing benchmark\\x07')
process.stdout.write('TYPING_READY_${runId}\\n')
process.stdin.on('data', (chunk) => {
if (chunk.includes(interrupt)) {
process.exit(0)
}
for (const char of chunk) {
if (char === '\\r' || char === '\\n') continue
seq += 1
process.stdout.write('\\r\\x1b[2KInteractive prompt ' + seq + ': ' + char + ' TYPING_KEY_${runId}_' + seq + '\\n')
}
})
`
}
async function waitForMarkerLatency(
page: Page,
marker: string,
timeoutMs: number
): Promise<number> {
const start = performance.now()
while (performance.now() - start < timeoutMs) {
if ((await getTerminalContent(page, 12_000)).includes(marker)) {
return performance.now() - start
}
await page.waitForTimeout(5)
}
throw new Error(`Timed out waiting for terminal marker ${marker}`)
}
function median(values: number[]): number {
const sorted = [...values].sort((a, b) => a - b)
return sorted[Math.floor(sorted.length / 2)] ?? 0
}
test.describe('Terminal typing latency', () => {
test('interactive prompt echoes typed keys without visible lag', async ({
orcaPage,
testRepoPath
}, testInfo) => {
await waitForSessionReady(orcaPage)
await waitForActiveWorktree(orcaPage)
await ensureTerminalVisible(orcaPage)
await waitForActiveTerminalManager(orcaPage, 30_000)
const ptyId = await waitForActivePanePtyId(orcaPage)
const runId = randomUUID()
const scriptPath = path.join(testRepoPath, `.orca-typing-benchmark-${runId}.mjs`)
writeFileSync(scriptPath, interactivePromptScript(runId))
let commandSent = false
try {
await sendToTerminal(orcaPage, ptyId, `node ${JSON.stringify(scriptPath)}\r`)
commandSent = true
await waitForTerminalOutput(orcaPage, `TYPING_READY_${runId}`, 10_000)
await focusActiveTerminalInput(orcaPage)
const latencies: number[] = []
for (const [index, char] of [...KEY_LATENCY_SAMPLES].entries()) {
const seq = index + 1
const marker = `TYPING_KEY_${runId}_${seq}`
const start = performance.now()
await orcaPage.keyboard.type(char)
await waitForMarkerLatency(orcaPage, marker, MAX_WORST_KEY_LATENCY_MS)
latencies.push(performance.now() - start)
}
const medianLatency = median(latencies)
const worstLatency = Math.max(...latencies)
testInfo.annotations.push({
type: 'terminal-typing-latency',
description: `median=${medianLatency.toFixed(1)}ms worst=${worstLatency.toFixed(1)}ms samples=${latencies
.map((value) => value.toFixed(1))
.join(',')}`
})
expect(medianLatency).toBeLessThan(MAX_MEDIAN_KEY_LATENCY_MS)
expect(worstLatency).toBeLessThan(MAX_WORST_KEY_LATENCY_MS)
} finally {
if (commandSent) {
await sendToTerminal(orcaPage, ptyId, '\x03').catch(() => undefined)
}
rmSync(scriptPath, { force: true })
}
})
})