diff --git a/test/mobile/keyboard.test.ts b/test/mobile/keyboard.test.ts index 91cf4000..a6ddb765 100644 --- a/test/mobile/keyboard.test.ts +++ b/test/mobile/keyboard.test.ts @@ -1254,7 +1254,11 @@ describe('Virtual Keyboard', () => { }); it('keeps terminal touch drag available for scrollback with the visible textarea enabled', async () => { - const calls = await page.evaluate(async () => { + // A Codex pane with REAL local scrollback (an older inline Codex, or any pane + // whose output scrolled lines into xterm's normal buffer). A blank pane is + // hollow and correctly pages the CLI instead (terminal-touch-paging.browser + // test), so the history is written first and checked before the drag. + const result = await page.evaluate(async () => { app.activeSessionId = 'mobile-touch-scroll-test'; app.sessions.set('mobile-touch-scroll-test', { id: 'mobile-touch-scroll-test', @@ -1262,22 +1266,42 @@ describe('Virtual Keyboard', () => { status: 'running', }); app.hideWelcome(); + const settings = app.loadAppSettingsFromStorage(); + settings.cjkInputEnabled = true; + app.saveAppSettingsToStorage(settings); + app._serverCjkOverride = true; app._updateCjkInputState(); + const history = Array.from({ length: 200 }, (_, i) => `history line ${i}`).join('\r\n') + '\r\n'; + await new Promise((resolve) => app.terminal.write(history, resolve)); + app.terminal.scrollToBottom(); + const buffer = app.terminal.buffer.active; + const before = { + type: buffer.type, + baseY: buffer.baseY, + viewportY: buffer.viewportY, + hollow: app._localScrollbackIsHollow(), + forwards: app._shouldForwardWheelToApp({ shiftKey: false }), + cjkVisible: document.body.classList.contains('cjk-input-visible'), + }; + const originalScrollLines = app.terminal.scrollLines.bind(app.terminal); const scrollCalls: number[] = []; app.terminal.scrollLines = (lines: number) => { scrollCalls.push(lines); return originalScrollLines(lines); }; + const sentToCli: string[] = []; + app._sendInputEphemeral = (_id: string, data: string) => sentToCli.push(data); const target = document.querySelector('#terminalContainer .xterm-screen') ?? document.getElementById('terminalContainer'); - if (!target) return scrollCalls; + if (!target) return { before, scrollCalls, sentToCli, viewportAfter: -1 }; const rect = target.getBoundingClientRect(); const x = rect.left + rect.width / 2; - const startY = rect.top + Math.min(180, rect.height - 20); - const endY = startY - 120; + // The finger moves DOWN the screen, so the content follows it back into history. + const startY = rect.top + 20; + const endY = startY + 120; function createTouch(y: number) { return new Touch({ @@ -1315,11 +1339,23 @@ describe('Virtual Keyboard', () => { }) ); await new Promise((resolve) => setTimeout(resolve, 50)); - return scrollCalls; + app._flushWheelSgrQueue?.(); + return { before, scrollCalls, sentToCli, viewportAfter: app.terminal.buffer.active.viewportY }; }); - expect(calls.length).toBeGreaterThan(0); - expect(calls.some((lines) => lines !== 0)).toBe(true); + // The scenario is real local scrollback with the visible textarea on. + expect(result.before.cjkVisible).toBe(true); + expect(result.before.type).toBe('normal'); + expect(result.before.baseY).toBeGreaterThan(0); + expect(result.before.viewportY).toBe(result.before.baseY); + expect(result.before.hollow).toBe(false); + expect(result.before.forwards).toBe(false); + + // The drag scrolled xterm's own history upward, and sent nothing to the CLI. + expect(result.scrollCalls.length).toBeGreaterThan(0); + expect(result.scrollCalls.some((lines) => lines < 0)).toBe(true); + expect(result.viewportAfter).toBeLessThan(result.before.viewportY); + expect(result.sentToCli).toEqual([]); }); it('keeps typed phone text in the terminal local echo path', async () => {