## 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.

```text
cypress "AssertionError: Timed out retrying after 4000ms: expected '[div]' to be 'visible'" flake in CI
```

## Steps
1. 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.
2. 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.
3. 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.
4. 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.
5. 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: none` toggled by JS after an API response needs a network wait (`cy.intercept` plus `cy.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
