For most Cypress end-to-end tests, select an element with a dedicated test attribute such as data-cy. Use cy.contains() when the visible text itself is part of what the test must verify. Then scope the query to the right container so it cannot match an unintended element elsewhere on the page.
Start with a stable test attribute
Add a dedicated attribute to the application element you need to target:
<button data-cy="submit">Submit</button>
Then query it and assert or interact with the result:
cy.get('[data-cy="submit"]')
.should('be.enabled')
.click()
Cypress recommends data-* attributes because they can identify an element without depending on its CSS classes, tag name, or incidental text. Its best-practices guidance says: “Best Practice: Use data-* attributes to provide context to your selectors and isolate them from CSS or JS changes.” Cypress Documentation: Selecting Elements.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
This approach requires maintaining test attributes in your markup, but it helps keep a test focused on behavior when styles or copy change. It is not a rule that IDs are always wrong: Cypress treats IDs as a possible option when used deliberately, while warning that generic tags and style-bound classes are brittle.
Choose a locator that tests the right thing
Locator choice is a test-design decision: should the test fail if the element’s visible wording changes, or only if the underlying behavior changes?
| Locator | Use it when | Tradeoff |
|---|---|---|
[data-cy="..."] or another dedicated data-* hook |
The test needs a stable hook independent of styling or incidental copy. | You must add and maintain the attribute in application markup. |
cy.contains(...) |
The visible content is important to the behavior being tested. | Copy and localization changes can change the locator; it yields at most one element. |
findByRole or findByLabelText through Cypress Testing Library |
You want to find a control through familiar accessibility-oriented semantics. | The query alone does not establish complete accessibility conformance. |
| CSS tag, class, or ID selector | The selector is intentionally tied to that attribute or no better hook is available. | Generic tags and styling classes are often brittle; an ID may be coupled to application behavior. |
Use text when the text is the behavior
If the test should fail when a button’s label changes, select by that label:
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
cy.contains('button', 'Submit').click()
The element argument constrains candidates to buttons, which is useful if the same text appears elsewhere or inside nested markup. By default, matching is case-sensitive. To ignore case, pass the matchCase option:
cy.contains('button', 'submit', { matchCase: false }).click()
cy.contains() yields at most one element and can yield a hidden element. If visibility matters to the test, make it explicit:
cy.contains('button', 'Submit').should('be.visible').click()
Use a stable hook when copy should not matter
If the test is about submitting a form rather than testing the exact label, use a test attribute. For translated interfaces, decide whether the test covers a specific localized string or the underlying control; text queries vary with locale.
Rank #3
Use accessibility-oriented queries deliberately
Cypress documents support for Cypress Testing Library methods such as findByRole and findByLabelText. These can help a test locate controls through semantics familiar to users of assistive technology, but choosing such a query does not by itself prove the page is accessible.
Scope queries to the intended part of the page
A common source of false matches is querying the whole document when the element should be inside a specific form, dialog, or page region. Outside a .within() callback, a fresh cy.get() starts from the application document. .find(), by contrast, searches below the current subject.
PC 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 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteUse .within() for several queries in one container
cy.get('[data-cy="account-form"]').within(() => {
cy.get('[data-cy="email"]').type('[email protected]')
cy.get('[data-cy="save"]').click()
})
Inside the callback, Cypress queries are scoped to the matched form. This is useful when several interactions belong to the same region.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Use .find() for a single descendant query
cy.get('[data-cy="account-form"]')
.find('[data-cy="email"]')
.type('[email protected]')
Do not replace .find() with a fresh cy.get() unless you intend to search from the document or the active .within() subject. When several elements match and position is genuinely part of the test, Cypress recommends clearer chains such as .first() or .eq(index) instead of jQuery positional selector extensions.
Understand retries and DOM boundaries
Cypress queries retry while waiting for elements, and chained assertions are retried until they pass or the command times out. This gives an element time to render; it does not make a selector cross every DOM boundary. The cy.get() documentation describes query scope and retry behavior.
- Iframes:
cy.get()does not search inside an iframe document. A selector that works in the main document will not automatically locate an element inside a frame. - Shadow DOM: Shadow roots require an explicit traversal such as
.shadow(), or the documentedincludeShadowDomoption for supported queries. Seecy.contains()options and scope. - Timeouts: A query that does not find a matching element before its configured command timeout fails with the selector and timeout information.
Generated selectors from Cypress Studio or cy.prompt() can use Cypress.ElementSelector.defaults() to configure priority. The selector-priority API is described as under active development, so check the documentation for the Cypress version installed in your project before relying on generated-selector behavior: Cypress.ElementSelector.
Best Value
Troubleshoot a selector that fails
| Symptom | Likely cause | What to check or change |
|---|---|---|
| The query times out without finding an element. | The selector is misspelled, the element has not rendered, or the query starts from the wrong scope. | Check the markup and spelling, confirm the element renders, and scope the query to the right container with .within() or .find(). |
| The element is visible in an iframe but Cypress cannot find it. | cy.get() does not descend into iframe documents. |
Recognize the iframe boundary; a normal document query will not reach its contents. |
| The element is inside a shadow root. | The query has not traversed the shadow DOM. | Use an explicit .shadow() traversal or a documented includeShadowDom option where applicable. |
cy.contains() matches text with different capitalization incorrectly, or finds a hidden result. |
Matching is case-sensitive by default, and the query can yield hidden elements. | Pass { matchCase: false } if appropriate and assert be.visible when visibility is part of the requirement. |
A second chained cy.contains() cannot find its target. |
The first result changed the scope, so the next text query searches beneath an unintended subject. | Select the relevant container explicitly, then query within it. |
| A locator breaks after a visual redesign. | It depends on a styling class or generic structure that changed. | Use a dedicated test attribute unless the styling or structure itself is what the test intends to verify. |
Or skip the browser setup
If what you need is a screenshot of a page rather than an end-to-end interaction test, ScreenshotNeo offers a website screenshot API and MCP server. A single GET request can return a PNG, JPEG, WebP, or PDF. For example, the cURL request below saves a WebP screenshot of Stripe:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for setup and options. Cookie banners are accepted before capture and 60+ known consent platforms, newsletter popups, and chat widgets are removed; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots.
Sign up for 1,000 free screenshots a month—no card required.
Frequently Asked Questions
Does Cypress automatically wait for a selector to match?
Yes. Cypress queries retry while waiting for matching elements, subject to the configured command timeout.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Can a selector choice alone prove an interface is accessible?
No. Accessibility-oriented queries can help target controls through semantics, but the locator strategy alone is not a complete accessibility test.
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.




