mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 08:59:40 +02:00
test(mobile): cover the scroll case in the keyboard-dismiss test
The dismiss handler fired on any touchend, so a scroll closed the keyboard too — a regression the original test could not see, because it only ever dispatched a stationary tap. The helper now takes an optional travel distance and emits touchmove steps, and the test asserts a 120px scroll leaves the terminal input focused. Removing the `if (moved) return` guard fails this assertion, so it genuinely pins the fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -633,24 +633,41 @@ describe('Virtual Keyboard', () => {
|
|||||||
// document, and calling the internal helper would bypass the routing this
|
// document, and calling the internal helper would bypass the routing this
|
||||||
// test exists to check.
|
// test exists to check.
|
||||||
const result = await page.evaluate(async () => {
|
const result = await page.evaluate(async () => {
|
||||||
const tap = async (el: Element) => {
|
const tap = async (el: Element, travel = 0) => {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const x = Math.max(2, rect.left + Math.min(6, rect.width / 2));
|
const x = Math.max(2, rect.left + Math.min(6, rect.width / 2));
|
||||||
const y = Math.max(2, rect.top + Math.min(6, rect.height / 2));
|
const y = Math.max(2, rect.top + Math.min(6, rect.height / 2));
|
||||||
const target = document.elementFromPoint(x, y) || el;
|
const target = document.elementFromPoint(x, y) || el;
|
||||||
const touch = new Touch({ identifier: 21, target, clientX: x, clientY: y });
|
const at = (cy: number) => new Touch({ identifier: 21, target, clientX: x, clientY: cy });
|
||||||
target.dispatchEvent(
|
target.dispatchEvent(
|
||||||
new TouchEvent('touchstart', {
|
new TouchEvent('touchstart', {
|
||||||
touches: [touch],
|
touches: [at(y)],
|
||||||
targetTouches: [touch],
|
targetTouches: [at(y)],
|
||||||
changedTouches: [touch],
|
changedTouches: [at(y)],
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
for (const step of travel ? [travel / 3, (travel * 2) / 3, travel] : []) {
|
||||||
|
target.dispatchEvent(
|
||||||
|
new TouchEvent('touchmove', {
|
||||||
|
touches: [at(y + step)],
|
||||||
|
targetTouches: [at(y + step)],
|
||||||
|
changedTouches: [at(y + step)],
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 15));
|
||||||
|
}
|
||||||
await new Promise((resolve) => setTimeout(resolve, 25));
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
||||||
target.dispatchEvent(
|
target.dispatchEvent(
|
||||||
new TouchEvent('touchend', { touches: [], changedTouches: [touch], bubbles: true, cancelable: true })
|
new TouchEvent('touchend', {
|
||||||
|
touches: [],
|
||||||
|
changedTouches: [at(y + travel)],
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 250));
|
await new Promise((resolve) => setTimeout(resolve, 250));
|
||||||
return document.activeElement?.className ?? '';
|
return document.activeElement?.className ?? '';
|
||||||
@@ -677,7 +694,12 @@ describe('Virtual Keyboard', () => {
|
|||||||
app._focusMobileTerminalInput();
|
app._focusMobileTerminalInput();
|
||||||
const afterTerminal = await tap(document.querySelector('#terminalContainer')!);
|
const afterTerminal = await tap(document.querySelector('#terminalContainer')!);
|
||||||
|
|
||||||
return { focusedBefore, afterOutside, afterButton, afterTerminal };
|
// A SCROLL also ends in touchend. Scrolling to read something while
|
||||||
|
// composing must not close the keyboard and drop the composer.
|
||||||
|
app._focusMobileTerminalInput();
|
||||||
|
const afterScroll = await tap(document.querySelector('.logo, .header-brand, header') ?? document.body, 120);
|
||||||
|
|
||||||
|
return { focusedBefore, afterOutside, afterButton, afterTerminal, afterScroll };
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.focusedBefore).toContain('xterm-helper-textarea');
|
expect(result.focusedBefore).toContain('xterm-helper-textarea');
|
||||||
@@ -685,6 +707,8 @@ describe('Virtual Keyboard', () => {
|
|||||||
expect(result.afterOutside).not.toContain('xterm-helper-textarea');
|
expect(result.afterOutside).not.toContain('xterm-helper-textarea');
|
||||||
expect(result.afterButton).toContain('xterm-helper-textarea');
|
expect(result.afterButton).toContain('xterm-helper-textarea');
|
||||||
expect(result.afterTerminal).toContain('xterm-helper-textarea');
|
expect(result.afterTerminal).toContain('xterm-helper-textarea');
|
||||||
|
// A scroll ends in touchend too, and must NOT close the keyboard.
|
||||||
|
expect(result.afterScroll).toContain('xterm-helper-textarea');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('routes CJK textarea typing through local echo on Enter', async () => {
|
it('routes CJK textarea typing through local echo on Enter', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user