test: target terminal viewport for scroll perf probe

This commit is contained in:
Neil
2026-06-07 16:16:44 -07:00
parent 8feb63901d
commit d2f31680d3
@@ -82,12 +82,17 @@ export async function measureActiveTerminalWheelScroll(page: Page): Promise<Scro
})()
pane.terminal.focus()
pane.terminal.scrollToBottom()
const screen = pane.container.querySelector<HTMLElement>('.xterm-screen')
if (!screen) {
throw new Error('Active terminal screen is unavailable')
// Why: Linux headless can miss wheel input over xterm's text layer while
// output is flooding; the viewport is the scrollable surface users affect.
const wheelTarget =
pane.container.querySelector<HTMLElement>('.xterm-viewport') ??
pane.container.querySelector<HTMLElement>('.xterm') ??
pane.container.querySelector<HTMLElement>('.xterm-screen')
if (!wheelTarget) {
throw new Error('Active terminal wheel target is unavailable')
}
const buffer = pane.terminal.buffer.active
const rect = screen.getBoundingClientRect()
const rect = wheelTarget.getBoundingClientRect()
return {
baseY: buffer.baseY,
beforeViewportY: buffer.viewportY,
@@ -119,6 +124,16 @@ export async function measureActiveTerminalWheelScroll(page: Page): Promise<Scro
await page.mouse.move(target.x, target.y)
await page.mouse.wheel(0, -1200)
let afterViewportY = target.beforeViewportY
while (performance.now() - start < 75) {
afterViewportY = await readActiveTerminalViewportY(page)
if (afterViewportY < target.beforeViewportY) {
break
}
await page.waitForTimeout(5)
}
if (afterViewportY >= target.beforeViewportY) {
await dispatchActiveTerminalWheelEvent(page)
}
while (performance.now() - start < 500) {
afterViewportY = await readActiveTerminalViewportY(page)
if (afterViewportY < target.beforeViewportY) {
@@ -164,6 +179,45 @@ export function annotateScrollMeasurement(
})
}
async function dispatchActiveTerminalWheelEvent(page: Page): Promise<void> {
await page.evaluate(() => {
const store = window.__store
const state = store?.getState()
const worktreeId = state?.activeWorktreeId
const tabId =
state?.activeTabType === 'terminal'
? state.activeTabId
: worktreeId
? (state?.activeTabIdByWorktree?.[worktreeId] ?? null)
: null
const manager = tabId ? window.__paneManagers?.get(tabId) : null
const pane = manager?.getActivePane?.() ?? manager?.getPanes?.()[0] ?? null
if (!pane) {
throw new Error('Active terminal pane is unavailable')
}
// Why: CI can drop CDP wheel input while the active textarea is focused;
// dispatching on xterm's own surfaces still exercises its user scroll path.
const wheelTargets = [
pane.container.querySelector<HTMLElement>('.xterm'),
pane.container.querySelector<HTMLElement>('.xterm-viewport'),
pane.container.querySelector<HTMLElement>('.xterm-screen')
].filter((target): target is HTMLElement => Boolean(target))
if (wheelTargets.length === 0) {
throw new Error('Active terminal wheel target is unavailable')
}
for (const wheelTarget of wheelTargets) {
wheelTarget.dispatchEvent(
new WheelEvent('wheel', {
bubbles: true,
cancelable: true,
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaY: -1200
})
)
}
})
}
async function readActiveTerminalViewportY(page: Page): Promise<number> {
return page.evaluate(() => {
const store = window.__store