Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →For most Cypress tests, use a dedicated data-* attribute such as data-cy for a stable interaction locator. Use cy.contains() when the visible wording is part of the requirement, and use accessible role or label queries when that semantic meaning is what the test should verify. Then scope the query to the relevant container so it identifies the intended element.
Choose a selector based on what the test should protect
A selector is part of a test’s contract with the page. Choose one that expresses the behavior under test without making the test depend on unrelated implementation details. Cypress’s guidance is: “Use data-* attributes to provide context to your selectors and isolate them from CSS or JS changes.”
| Selector approach | Use it when | Main trade-off |
|---|---|---|
Dedicated test attribute, such as data-cy |
The test needs to locate an element reliably for interaction, independently of styling or incidental text. | The application markup needs an explicit test hook. |
Visible text with cy.contains() |
The wording itself matters and should cause a test failure if it changes. | The test intentionally depends on copy and on Cypress’s text matching and element preference behavior. |
| Accessible role or label query | The role or accessible name is the user-facing meaning the test is intended to exercise. | A role or label query alone does not make the test a complete accessibility evaluation. |
| CSS class, generic tag, or implementation-specific selector | Only when that detail is genuinely part of the behavior being tested or no better contract is available. | Styling and implementation changes can break the selector without changing the user-visible behavior. |
Use a test hook for stable interaction
Add an explicit attribute to the element, for example <button data-cy="submit">Submit</button>, and query it with cy.get('[data-cy="submit"]'). Keep the attribute meaningful and specific enough to distinguish the control from other elements.
Use text when copy is the assertion
If changing “Submit” to “Save” should fail the test, select the button by its text: cy.contains('button', 'Submit'). If wording can change without changing the behavior, use a test hook for the interaction and assert any important rendered content separately.
Use semantic queries for user-facing meaning
With Cypress Testing Library installed, a role/name query such as cy.findByRole('button', { name: 'Save' }) can make the intended accessible control explicit. A label query is similarly useful for a form field when its accessible label is the behavior you want to verify. These queries do not replace broader accessibility checks.
Build selectors that are scoped and readable
Even a good selector can match the wrong element if it is used too broadly. Start from the meaningful container when a page has repeated controls, and make the selection intent clear to the next person maintaining the test.
// Stable interaction hook, with a separate assertion for rendered content
cy.get('[data-cy="submit"]').click()
cy.get('[data-cy="status"]').should('contain', 'Saved')
// Make the visible wording itself part of the test
cy.contains('button', 'Submit').click()
// Use a semantic query when role/name is the intended contract
cy.findByRole('button', { name: 'Save' }).click()
// Scope a repeated control to its form
cy.get('[data-cy="profile-form"]').within(() => {
cy.get('[data-cy="save"]').click()
})
The role-query example requires Cypress Testing Library. These examples illustrate selector choices; they are not claims about executed tests.
cy.get(), .find(), .within(), and .filter()
cy.get(selector)queries from the document root, except when called inside an active.within()context. It can also retrieve aliases. Aliased DOM elements are re-queried by default, so the query reflects the current page state. See thecy.get()API..within()makes commands inside its callback relative to the selected container. Use it when a form, dialog, or repeated component provides a clear boundary..find(selector)searches descendants at any depth and must be chained from a command that yields DOM elements. See the.find()API..filter(selector)narrows an existing DOM subject; it is useful when the original query is intentionally broad and a subsequent condition identifies the desired element. Cypress documents it as a retryable query. See the.filter()API.
Understand what cy.contains() yields
cy.contains() can start from cy or from a yielded DOM element. It yields at most one matching element, and an optional selector can limit candidate elements—for example, cy.contains('button', 'Submit'). When nested elements contain the same text, Cypress’s matching and element-preference rules affect which element is yielded; consult the cy.contains() API if the result is surprising.
Free tools Windows power users keep installed
One-click scans. No signup required.
Prefer clear positional intent
When selecting from a collection, chain .first() or .eq(index) when that makes the intent easier to read than embedding positional syntax in a selector. Positional selection still depends on the collection’s order, so prefer a more meaningful scope or identifying attribute if the order itself is not part of the behavior.
Let Cypress retry queries instead of adding arbitrary waits
Cypress retries chained queries while it waits for elements and assertions to pass. A query that describes the desired element or state is usually clearer than a fixed delay inserted to give the page time to settle. For example, wait on the selector or assertion that represents readiness rather than adding a guessed timeout. See the Cypress documentation for query retry behavior and filter retries.
Rank #4
Generated selectors are useful, but treat their priorities as version-sensitive
Cypress.ElementSelector.defaults() configures selector priorities used by tools including Cypress Studio and cy.prompt(). Cypress attempts the configured priorities while ensuring a generated selector is unique; it may skip or combine lower-priority options when needed. The API marks selectorPriority as under active development and subject to change, so use generated selectors as a starting point and review their meaning and uniqueness in your project. See the ElementSelector API.
Troubleshoot selectors that fail or match the wrong element
- The query times out: Check that the element exists in the current page state and that the selector matches the rendered markup. Prefer a retryable query tied to the expected condition over an arbitrary wait.
- A query finds the wrong repeated control: Scope it with
.within(), or chain.find()from the intended container. Check that the container selector is itself unique. cy.contains()returns an unexpected element: Add an element selector such as'button'to narrow candidates, or use a dedicated attribute if text is not the contract.- A class-based selector breaks after a visual change: Replace it with a dedicated
data-*attribute unless the class itself is relevant to the test. findByRoleorfindByLabelTextis unavailable: These examples depend on Cypress Testing Library. Install and configure that package for the project, or use Cypress’s built-in commands.- A generated selector changes or looks unexpectedly complex: Check the configured priorities and uniqueness requirement; generated-selector priority behavior is explicitly subject to change.
Or skip the browser setup
For a website screenshot rather than a Cypress test, ScreenshotNeo can return an image or PDF with one GET request. See the ScreenshotNeo API documentation for options.
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides screenshot and PDF tools for AI agents. The free plan includes 1,000 screenshots per 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.
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.

