test(mobile): give the touch-scrollback case real local history

"keeps terminal touch drag available for scrollback with the visible
textarea enabled" built a Codex session on a blank terminal. With Codex
in transcriptPageKeys that pane is hollow, so the drag is correctly
consumed by the page-key fallback and never reaches scrollLines; the
fixture no longer described local scrollback.

The case now writes 200 lines into xterm (awaiting the write), turns the
visible CJK textarea on explicitly, and asserts the scenario before the
drag: normal buffer, baseY > 0, viewport at the bottom, not hollow, wheel
forwarding off, cjk-input-visible set. A real touch drag back into history
must then call scrollLines with negative lines, move the viewport up, and
send nothing to the CLI. Hollow Codex paging stays covered by
terminal-touch-paging.browser.test.ts.
This commit is contained in:
Aamer Akhter committed 2026-10-10 22:59:54 -04:00
1 parent d6c87bbd27
commit dd7774f9ad
1 file changed
+43 -7
+43 -7
View File
@@ -1254,7 +1254,11 @@ describe('Virtual Keyboard', () => {
}); });
it('keeps terminal touch drag available for scrollback with the visible textarea enabled', async () => { 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.activeSessionId = 'mobile-touch-scroll-test';
app.sessions.set('mobile-touch-scroll-test', { app.sessions.set('mobile-touch-scroll-test', {
id: 'mobile-touch-scroll-test', id: 'mobile-touch-scroll-test',
@@ -1262,22 +1266,42 @@ describe('Virtual Keyboard', () => {
status: 'running', status: 'running',
}); });
app.hideWelcome(); app.hideWelcome();
const settings = app.loadAppSettingsFromStorage();
settings.cjkInputEnabled = true;
app.saveAppSettingsToStorage(settings);
app._serverCjkOverride = true;
app._updateCjkInputState(); app._updateCjkInputState();
const history = Array.from({ length: 200 }, (_, i) => `history line ${i}`).join('\r\n') + '\r\n';
await new Promise<void>((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 originalScrollLines = app.terminal.scrollLines.bind(app.terminal);
const scrollCalls: number[] = []; const scrollCalls: number[] = [];
app.terminal.scrollLines = (lines: number) => { app.terminal.scrollLines = (lines: number) => {
scrollCalls.push(lines); scrollCalls.push(lines);
return originalScrollLines(lines); return originalScrollLines(lines);
}; };
const sentToCli: string[] = [];
app._sendInputEphemeral = (_id: string, data: string) => sentToCli.push(data);
const target = const target =
document.querySelector('#terminalContainer .xterm-screen') ?? document.getElementById('terminalContainer'); 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 rect = target.getBoundingClientRect();
const x = rect.left + rect.width / 2; const x = rect.left + rect.width / 2;
const startY = rect.top + Math.min(180, rect.height - 20); // The finger moves DOWN the screen, so the content follows it back into history.
const endY = startY - 120; const startY = rect.top + 20;
const endY = startY + 120;
function createTouch(y: number) { function createTouch(y: number) {
return new Touch({ return new Touch({
@@ -1315,11 +1339,23 @@ describe('Virtual Keyboard', () => {
}) })
); );
await new Promise((resolve) => setTimeout(resolve, 50)); 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); // The scenario is real local scrollback with the visible textarea on.
expect(calls.some((lines) => lines !== 0)).toBe(true); 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 () => { it('keeps typed phone text in the terminal local echo path', async () => {