Catch an exit half-way on a slow machine, not only on a fast one
tests / feature (8.4) (push) Successful in 1m45s
tests / feature (8.5) (push) Successful in 2m0s
tests / browser (chrome, chromium) (push) Successful in 8m6s
tests / browser (firefox, firefox) (push) Failing after 12m52s
tests / browser (safari, webkit) (push) Failing after 13m1s

The browser suite passes on every engine here and fails on the runner,
which takes three times as long: each failing test triggers a close and
then samples for an in-between state — a rail part-way out, a scrim
part-way faded, a menu's exit copy part-way sunk — and a starved runner
takes its one sample after the 150-650ms exit has already finished.

So the tests that assert *that* something animates now stretch every
motion duration token to three seconds first (`slowMotion()`, beside
`ready()` in tests/Pest.php; ActionsTest's own copy of it goes). The two
polling helpers grew their budget to match: the rail panel and the sheet
slide on emphasized-accelerate, which is under 1% of its travel at a
quarter of the way through, so a 300ms window no longer reached the
threshold once the exit itself was three seconds long.

The two full-screen date picker tests waited for a resize through
click()'s own retry, which ate the whole 15s budget on Firefox; they now
wait for the new width and a settled document first. The bottom sheet's
preset test waits for its entry to finish before pressing the grip.

`hold()` in search.js reads the view's animations a frame after the
closed state, as the rail's settle() does, but one frame is not always
enough: an engine that starts them on its next tick shows none, and the
full-screen layout would end at once, mid-exit. An empty list is now
asked again on the following frame.

Feature 1159 passed. Browser 299 passed on Chrome, Firefox and WebKit,
and again on WebKit under ten spinning cores.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Reinhold / reini
2026-09-17 23:57:43 +02:00
co-authored by Claude Opus 5
parent 145f60aa11
commit 94d6e31432
7 changed files with 82 additions and 21 deletions
+1 -15
View File
@@ -993,20 +993,6 @@ it('scrolls the FAB menu\'s items on a short window, behind the close button, wh
$page->assertScript("{$trigger}.getBoundingClientRect().top === window.__fabTop");
});
/**
* Slows the page's motion tokens, so a popover's exit copy (resources/js/popover-exit.js) is
* still on screen after a separate round trip to the browser: a key press or a click already
* costs about as long as a 150350ms exit, and the copy moves on the tokens as the popover would.
*/
function slowMotion(mixed $page, string $duration = '1500ms'): mixed
{
$page->script(<<<JS
document.head.insertAdjacentHTML('beforeend', '<style>:root { --md-sys-motion-effects-fast-duration: {$duration}; --md-sys-motion-effects-default-duration: {$duration}; --md-sys-motion-spatial-fast-duration: {$duration}; --md-sys-motion-spatial-default-duration: {$duration}; }</style>')
JS);
return $page;
}
/** The exit copy on screen: shown, inert, hidden from assistive technology, with no ids of its own. */
const EXIT_COPY = "(() => { const copy = document.querySelector('[data-md-popover-ghost]'); return copy !== null && copy.matches(':popover-open') && copy.inert && copy.getAttribute('aria-hidden') === 'true' && ! copy.hasAttribute('id') && copy.querySelector('[id], [popover]:not([data-md-popover-ghost])') === null; })()";
@@ -1030,7 +1016,7 @@ it('fades a menu out after the browser has closed it, on Escape or a press outsi
// The copy is decoration: Alpine starts nothing inside it.
->assertScript("window.eval(\"[...document.querySelectorAll('[data-md-popover-ghost], [data-md-popover-ghost] *')].every((element) => element._x_dataStack === undefined)\")")
// Gone once the slowest of its transitions has run.
->assertScript('new Promise((resolve) => setTimeout(() => resolve(document.querySelector("[data-md-popover-ghost]") === null), 1800))');
->assertScript('new Promise((resolve) => setTimeout(() => resolve(document.querySelector("[data-md-popover-ghost]") === null), 3300))');
// A press outside it.
$page->click(MORE)