In most Cypress tests, you do not need a separate wait before clicking. Query the element and call .click(); Cypress retries the query and waits for the element’s actionability checks to pass before attempting the click.
cy.get('[data-cy="submit"]').click()
What Cypress waits for before a click
“Clickable” is a convenient shorthand, not a separate Cypress assertion. Before clicking, Cypress checks whether it can interact with the element: among other conditions, it must not be hidden, disabled, detached, readonly, animating, or covered by another element. Cypress also scrolls it into view when needed. A visible element can therefore still fail because, for example, an overlay covers it. See Cypress’s interaction and actionability checks.
As an Amazon Associate I earn from qualifying purchases.
The query and action can usually be written together:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11cy.get('[data-cy="submit"]').click()
Cypress retries the query and checks actionability until the element is ready or the command times out. It then attempts the click once; it does not repeatedly click the element. See Retry-ability in Cypress and the cy.click() API.
#1 Best Overall
When to add an assertion before clicking
Add an assertion when the state is part of what the test needs to verify, such as a submit control becoming enabled:
cy.get('[data-cy="submit"]')
.should('be.enabled')
.click()
Assertions retry until they pass or time out. A .should('be.visible') used only as a pre-click pause is usually unnecessary: visibility does not prove the element is uncovered, and .click() performs its own actionability checks. Use an assertion to express a meaningful requirement, not as a substitute for click readiness. See cy.should() and the interaction guide.
Rank #2
Allow more time for a genuinely slow element
Cypress documents a 4-second default defaultCommandTimeout for retrying commands. If a particular element legitimately takes longer to become ready, set a timeout locally on its query:
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →cy.get('[data-cy="submit"]', { timeout: 10000 }).click()
The .click() timeout covers waiting for the action to resolve, including actionability. Prefer a local override for the exceptional slow step rather than raising the global timeout for every command. Choose a value based on the behavior being tested; a longer timeout will not fix an element that stays disabled, covered, or absent. See retry-ability and timeout guidance and click options.
Rank #3
Wait for the condition you actually need
For UI readiness, query or assert the UI state
A fixed pause such as cy.wait(3000) does not check whether the element is ready. It wastes time when the UI is ready early and may still be too short when it is slow. Prefer a retryable query or assertion for the state the next step requires:
cy.get('[data-cy="results"]').should('be.visible')
Cypress recommends waiting on an observable condition instead of guessing a delay. See Optimizing test performance.
Rank #4
For a request, wait on a network alias
If the click triggers a request and the test must verify that request’s completion, register an intercept before clicking and wait on its alias:
cy.intercept('POST', '/api/todos').as('createTodo')
cy.get('[data-cy="save"]').click()
cy.wait('@createTodo').its('response.statusCode').should('eq', 201)
This waits for a matching request and checks its response; it is not a wait for the button to become actionable. The intercept must be registered before the click so Cypress can observe the request. An assertion directly chained to cy.wait('@alias') runs once against the yielded interception; using a query such as .its() creates a retryable chain for the property assertion. See cy.wait().
Keep clicks safe across rerenders
Queries and assertions can retry; action commands such as .click() are not retried because they may change the application. Keep the click at the end of its chain, then start a fresh query for the resulting state:
cy.get('[data-cy="open-modal"]').click()
cy.get('[data-cy="modal"]').should('be.visible')
This avoids relying on the original subject if the click causes a rerender or removes the element. Cypress cautions that chaining commands which depend on the subject after .click() can be unsafe in that situation. Similarly, a .then() callback does not retry: capturing an element there may leave the test with a stale reference after a rerender. Prefer linked queries and retryable assertions for changing conditions. See Retry-ability in Cypress and cy.click().
Why not use force as a wait?
{ force: true } disables Cypress’s normal actionability waiting and checks. It does not wait for an element to become clickable; it bypasses those checks. Use it only when bypassing them is deliberate and matches the behavior the test is intended to cover. See the cy.click() API.
Recommended Free Tools
Common failures and what to check
- Element is covered: identify the overlay, loading layer, or other element intercepting the click. Wait for the relevant UI state to change or assert the overlay is gone before clicking.
- Element is disabled: determine whether the application should enable it. If enabled state is the requirement, assert
.should('be.enabled'); do not use force to hide a real readiness problem. - Element is missing or appears late: confirm the selector matches the intended control, then use a retryable query. Add a local timeout only if the delay is expected.
- Element is detached or the test uses a stale subject: query it again after the rerender rather than reusing an element captured in
.then()or chaining off a click that replaced it. - Test waits for the wrong thing: use a DOM assertion for UI state and a request alias for network completion. A fixed-duration wait establishes neither condition.
Or skip the browser setup
If you need a website screenshot rather than a Cypress interaction test, ScreenshotNeo can capture a URL in one GET request. Its API accepts consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. It also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents.
Example using cURL; see the ScreenshotNeo API documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo is a screenshot API, not a replacement for Cypress assertions or browser interaction tests. Its free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. See ScreenshotNeo for product details and sign up for 1,000 free screenshots a month with no card.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




