cypress "AssertionError: Timed out retrying after 4000ms: expected '[div]' to be 'visible'" flake in CI
Fixes the Cypress flake where an element assertion times out after 4000ms in CI because the element is still animating or rendering. Shows how to target the element with a stable test id, extend the assertion timeout, and neutralize animations in test runs. Use when a visibility assertion passes locally but flakes in CI. Not for elements that never appear, wrong selectors, or failures outside Cypress.
TL;DR
The element exists, but on a slow CI runner it is still animating or rendering when the default 4-second retry window expires. Point the assertion at a stable [data-testid] selector, give it an explicit longer timeout, and disable CSS animations in your test config so the check never races a transition. That combination turns the flake into a deterministic pass.
cypress "AssertionError: Timed out retrying after 4000ms: expected '[div]' to be 'visible'" flake in CISteps
- Watch the CI run video or screenshot to confirm the element appears but late, often mid fade-in or slide-in after the assertion already failed. Expected: you can see the element arriving after the 4s mark.
- Replace the fragile selector with a stable one:
cy.get('[data-testid=submit-panel]'). Expected: the selector matches exactly one element and does not depend on markup or CSS classes. - Give the assertion room on slow runners:
cy.get('[data-testid=submit-panel]', { timeout: 15000 }).should('be.visible'). Expected: the retry loop now waits up to 15 seconds and the assertion passes. - Stop animations from racing the test: add a test-only stylesheet or config that disables CSS transitions and animations during Cypress runs. Expected: elements reach their final state immediately, so visibility is deterministic.
- Rerun the spec several times in CI (or use a repeat plugin). Expected: consecutive green runs with no visibility flakes.
Use this when
- A
should('be.visible')assertion flakes in CI but passes locally - The CI video shows the element animating in late
- The selector works, the element just is not visible within 4000ms
Not for this skill when
- The element never appears at all (missing data, broken API, wrong page)
- The selector matches zero or multiple elements (fix the selector first)
- The flake is in a different runner (Playwright, Selenium)
Variant phrasings
- cypress element is not visible flake in CI
- cypress timed out retrying expected to be visible
- cypress visibility assertion fails only in CI pipeline
Why it happens
Cypress retries assertions for 4 seconds by default, which is generous on a fast local machine and tight on a loaded CI runner where rendering and animations run slower. A fade-in or slide-in transition can easily outlast the window, so the assertion fails on an element that was about to become visible.
Edge cases
- If the element is inside a virtualized list, it may never render until scrolled into view. Scroll first, then assert.
display: nonetoggled by JS after an API response needs a network wait (cy.interceptpluscy.wait) rather than a longer timeout alone.- Do not raise the global defaultCommandTimeout to mask this. Scoped timeouts on the flaky assertion keep the rest of the suite fast.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_UTaLZOKXa3uJIo0eQlDAVw