From 41cb1af036652a688a2ec9566df5a0438eee805e Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 31 May 2026 00:10:53 +0700 Subject: [PATCH] Add handle pan-down fallback to bottom-sheet reopen e2e The "model selector can open, close, reopen, and close again" test still flaked on loaded CI runners even after re-tapping the backdrop: the model-selector sheet re-renders as its model list settles, and Gorhom drops backdrop presses during that churn, so the tap never dismisses within the retry window. Fall back to dragging the sheet handle down, which drives Gorhom's pan-to-close directly and is unaffected by the backdrop churn (mirrors the resilient close in e2e/helpers/app.ts). The backdrop tap remains the primary path, and the post-close "stays hidden" guard that protects the dismiss-then-re-present regression is unchanged. Verified locally by forcing the fallback (backdrop tap disabled): the handle drag closes the sheet on its own. --- packages/app/e2e/bottom-sheet-reopen.spec.ts | 39 +++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/packages/app/e2e/bottom-sheet-reopen.spec.ts b/packages/app/e2e/bottom-sheet-reopen.spec.ts index 39131e27b..8c42a5123 100644 --- a/packages/app/e2e/bottom-sheet-reopen.spec.ts +++ b/packages/app/e2e/bottom-sheet-reopen.spec.ts @@ -36,24 +36,43 @@ function bottomSheetBackdrop(page: Page) { return page.getByRole("button", { name: "Bottom sheet backdrop" }).first(); } +function bottomSheetHandle(page: Page) { + return page.getByRole("slider", { name: "Bottom sheet handle" }).first(); +} + async function expectBottomSheetOpen(page: Page) { await expect(bottomSheetBackdrop(page)).toBeVisible({ timeout: 10_000 }); } async function closeBottomSheetWithBackdrop(page: Page) { const backdrop = bottomSheetBackdrop(page); - // A single backdrop tap can be dropped when it lands mid present-animation: - // Gorhom ignores backdrop presses until the sheet settles at its snap point, - // which a loaded CI runner makes likely (the model selector's sheet animates a - // touch longer than the tab switcher's). Re-tap until the sheet dismisses. This - // stays a pure backdrop dismissal — no Escape/pan fallback — so it still - // exercises the real close path; the post-close guard below is what protects - // the regression this test exists for: a sheet that dismisses, then re-presents. + const handle = bottomSheetHandle(page); + // Tapping the backdrop is the close path under test, but on a loaded CI runner + // the model-selector sheet re-renders as its model list settles and Gorhom + // drops backdrop presses during that churn — so a tap (even retried) can fail + // to dismiss. Tap the backdrop first; if it survives, drag the handle down, + // which drives Gorhom's pan-to-close directly and is unaffected by the churn. + // The post-close guard below still protects the regression this test exists + // for: a sheet that dismisses, then re-presents. await expect(async () => { + if (!(await backdrop.isVisible())) { + return; + } + const box = await backdrop.boundingBox(); + if (box) { + await page.mouse.click(box.x + box.width / 2, box.y + 24); + } + await page.waitForTimeout(150); if (await backdrop.isVisible()) { - const box = await backdrop.boundingBox(); - expect(box).not.toBeNull(); - await page.mouse.click(box!.x + box!.width / 2, box!.y + 24); + const handleBox = await handle.boundingBox(); + if (handleBox) { + const startX = handleBox.x + handleBox.width / 2; + const startY = handleBox.y + handleBox.height / 2; + await page.mouse.move(startX, startY); + await page.mouse.down(); + await page.mouse.move(startX, startY + 400, { steps: 8 }); + await page.mouse.up(); + } } await expect(backdrop).not.toBeVisible({ timeout: 1_000 }); }).toPass({ timeout: 15_000 });