diff --git a/tests/e2e/new-task-picker-touch.spec.ts b/tests/e2e/new-task-picker-touch.spec.ts index b48d7084d6..6804125114 100644 --- a/tests/e2e/new-task-picker-touch.spec.ts +++ b/tests/e2e/new-task-picker-touch.spec.ts @@ -21,13 +21,23 @@ async function swipeToLastOption(page: Page, picker: Locator, list = picker.getB }).toBeLessThanOrEqual(page.viewportSize()!.height); expect((await picker.boundingBox())!.y).toBeGreaterThanOrEqual(0); const session = await page.context().newCDPSession(page); + const targetHandle = await last.elementHandle(); + expect(targetHandle).not.toBeNull(); try { expect(await list.evaluate((element) => element.scrollHeight > element.clientHeight)).toBe(true); for (let attempt = 0; attempt < 20; attempt += 1) { - const bounds = (await list.boundingBox())!; - const target = (await last.boundingBox())!; + // Momentum can finish between protocol round trips. Observe geometry and + // scrollTop together so a stale target cannot trigger a swipe at the end. + const { bounds, target, before } = await list.evaluate((element, option) => { + const container = element.getBoundingClientRect(); + const item = option!.getBoundingClientRect(); + return { + bounds: { x: container.x, y: container.y, width: container.width, height: container.height }, + target: { y: item.y, height: item.height }, + before: element.scrollTop, + }; + }, targetHandle); if (target.y >= bounds.y && target.y + target.height <= bounds.y + bounds.height) break; - const before = await list.evaluate((element) => element.scrollTop); const x = bounds.x + bounds.width / 2; const y = bounds.y + bounds.height - 20; const distance = Math.min(180, bounds.height - 40); @@ -49,6 +59,7 @@ async function swipeToLastOption(page: Page, picker: Locator, list = picker.getB expect(target.y).toBeGreaterThanOrEqual(bounds.y); expect(target.y + target.height).toBeLessThanOrEqual(bounds.y + bounds.height + 1); } finally { + await targetHandle?.dispose(); await session.detach(); } return last; @@ -56,6 +67,25 @@ async function swipeToLastOption(page: Page, picker: Locator, list = picker.getB test.use({ viewport: { width: 390, height: 844 }, hasTouch: true, isMobile: true }); +test("touch scroll observation stays valid when momentum finishes between browser reads", async ({ page, browserName }) => { + test.skip(browserName !== "chromium", "Native touch drags use Chromium's input protocol."); + await page.setContent(`