Playwright Actionability: Stability checks during CSS transitions
0 reputation · 23 Dec 2020, 13:50 UTC
0 reputation · 23 Dec 2020, 13:50 UTC
Playwright's auto-waiting mechanism ensures elements are actionable by verifying visibility, enablement, and stability before performing interactions. This process is critical for reducing flakiness in dynamic user interfaces.
A distinction exists in how the stability check handles different animation types. While JavaScript-driven movements are tracked, the behavior regarding elements moving via CSS transitions may vary depending on the browser engine and the specific transition property used.
When an element is transitioning its position or size, the stability check must determine if the element has reached a final state or is still in motion to avoid clicking the wrong coordinates.
34775 reputation · 23 Dec 2020, 15:08 UTC
Yes — Playwright's stability check treats an element as unstable while a CSS transition is changing its position or size, and it waits until the element's bounding box stops changing before clicking. No — there is no configurable stability threshold or duration knob; the wait is driven by observed geometry, not by a timer you can tune.
Before an action like click(), Playwright runs its actionability checks: visible, stable, enabled, and receiving events. "Stable" is defined geometrically: Playwright samples the element's bounding box across at least two consecutive animation frames and requires them to match. It does not subscribe to transitionend events or inspect transition-duration directly.
This distinction matters for your two questions:
transform, left, width, etc. changes the bounding box every frame, the element reads as unstable until the movement finishes (or stops changing). So effectively, yes, Playwright waits out the transition — but as a side effect of frame sampling, not because it parses the transition duration.@keyframes animation that moves the element will never produce two identical consecutive frames, so the stability check never passes and the action eventually times out. There is no threshold to relax.If you have a perpetually animating element (a pulsing badge, a sliding carousel), actions against it will hang until timeout. Your options are scoped:
page.addStyleTag({ content: '* { animation: none !important; transition: none !important; }' }).click({ force: true }) — but understand this skips all checks, not just stability.To confirm a transition is what's blocking you, check the computed style and bounding-box movement in a headed run or trace:
await page.waitForFunction(() => {
const el = document.querySelector('#target');
const cs = getComputedStyle(el);
return cs.transitionDuration === '0s' && cs.animationName === 'none';
});A Playwright trace (--trace on) will also show the action retrying with "element is not stable" messages, which confirms the diagnosis.
Behavior described here reflects Playwright's long-standing implementation (1.x line); verify against your installed version's release notes if you're on a recent release. Browser engines sample frames slightly differently, so borderline cases (very short transitions) can behave inconsistently across Chromium, Firefox, and WebKit. If you're seeing instability that doesn't match this model, the missing detail worth checking is whether the movement comes from a transform/position change (stability-relevant) versus a paint-only property like opacity or color, which does not affect the bounding box and is ignored by the stability check.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.