fix(terminal): drive the shipped Shift+Enter handlers and the Key tester cap in their browser tests (#520, #522 review)

- Minor: the Key tester "14 lines" test never pressed a key into the
  tester (the previous test blurred it, so the presses landed on <body>
  and the cap was never exercised). It now refocuses the field, asserts
  the focus, clears the log, checks 2 presses accumulate to 6 lines, then
  4 presses of another key cap the log at exactly 14 with the oldest 4
  lines evicted in order, and the readonly field stays empty. Verified to
  fail with the cap changed to 20.
- Nit: the split-pane invariant implied Ctrl+Enter could use the CLI's
  declared newline chord. Reworded after checking the send-key route:
  Ctrl+Enter is always a real 0x0a, Shift+Enter is the declared
  capabilities.newline chord (0x0a unless the CLI declares another), sent
  on keydown only. The same imprecision in the auto-named sessions
  paragraph is corrected too.
- Nit: docs/wiki/Settings-Reference.md now lists the Key tester row in
  the Terminal & Input table.

- Nit: test/shift-enter-keypress.browser.test.ts exercised a hand-copied
  predicate named `shipped`. It now loads the real app from a real
  WebServer and presses real keys into the handlers terminal-ui.js
  (app.terminal, recording the real _sendInputAsync send path) and
  terminal-split.js (a real SplitTerminalPane) attach, recording the
  send-key POSTs through a fetch wrapper. It asserts no \r reaches either
  send path for Shift/Ctrl+Enter, exactly one send-key per press for the
  right session, and that Enter and Alt+Enter are untouched. The old
  keydown-only gate stays as a labelled reproduction of xterm's keypress
  behaviour on a bare Terminal. Verified to fail on both panes with the
  gate narrowed back to keydown.
- Nit: the keypress trap is now written down beside the other key-gate
  rules (Command palette and shortcut registry): xterm runs the custom
  handler for keydown, keypress and keyup and drops only Ctrl/Alt/Meta
  keypresses, so a gate on a chord that can carry Shift alone must
  swallow every event type. The smart-copy keydown-only rule points at it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-04 23:52:41 +02:00
parent 36af183f97
commit 52267f8617
4 changed files with 223 additions and 63 deletions
+23 -2
View File
@@ -89,8 +89,29 @@ describe('Key tester in a real browser', () => {
});
it('keeps only the last 14 lines and never types into the field', async () => {
for (let i = 0; i < 8; i++) await page.keyboard.press('a');
expect((await log()).split('\n').length).toBeLessThanOrEqual(14);
// The test above blurred the field, so focus it again: without this the presses land on
// <body>, the log keeps whatever the earlier tests left, and the cap is never exercised.
await page.focus('#keyTesterInput');
expect(await page.evaluate(() => document.activeElement?.id)).toBe('keyTesterInput');
await page.evaluate(() => (document.getElementById('keyTesterLog')!.textContent = ''));
const lines = async () => (await log()).split('\n');
// A printable key fires keydown, keypress and keyup, so 2 presses are 6 lines: under the cap
// the log accumulates rather than showing only the latest event.
for (let i = 0; i < 2; i++) await page.keyboard.press('a');
expect(await lines()).toHaveLength(6);
// A different key, so eviction is visible: 4 x 3 = 12 more lines makes 18, capped to 14. The
// oldest 4 go (all of the first 'a' press and the second one's keydown), the newest stay in order.
for (let i = 0; i < 4; i++) await page.keyboard.press('b');
const capped = await lines();
expect(capped).toHaveLength(14);
expect(capped.filter((l) => l.includes('key="a"'))).toHaveLength(2);
expect(capped.filter((l) => l.includes('key="b"'))).toHaveLength(12);
expect(capped[0]).toMatch(/^keypress\s+key="a" code=KeyA mods=none charCode=97$/);
expect(capped[13]).toMatch(/^keyup\s+key="b" code=KeyB mods=none$/);
// Readonly: none of those presses typed anything into the field itself.
expect(await page.inputValue('#keyTesterInput')).toBe('');
});
});