Most Cypress test failures start with one common problem, elements not being found when the test expects them.
Dynamic UIs, changing selectors, and timing issues can make element selection unreliable, leading to flaky tests and confusing errors during execution.
The cy.get() command in Cypress is the foundation of element selection and plays a critical role in test stability.
This guide explains how cy.get() works, how to use it correctly, and how to avoid common pitfalls when selecting elements, helping you write more reliable and maintainable Cypress tests.
What is cy.get() in Cypress?
cy.get() is a core Cypress command used to locate and select DOM elements on a web page. It is typically the starting point for interacting with elements, such as clicking buttons, typing into inputs, or making assertions about UI behavior.
Unlike traditional selector methods that run once, cy.get() automatically retries until the element is found or a timeout is reached. This built-in retry mechanism helps handle dynamic content and reduces flaky test failures caused by timing issues.
When cy.get() successfully finds an element, it yields the matched DOM element(s) to the next command in the chain. This allows testers to perform actions or assertions directly on the selected element, making cy.get() a foundational command for writing stable and readable Cypress tests.
Basic Syntax of cy.get()
The cy.get() command is used with a selector to locate elements in the DOM. Once an element is selected, you can chain additional Cypress commands or assertions to interact with it or validate its state.
Basic Usage
cy.get() accepts a selector as its first argument. The selector can target one or more elements on the page.
Typical usage follows this pattern:
- Select an element
- Perform an action or assertion on it
Chaining Commands
After selecting an element with cy.get(), you can chain commands such as:
- click() to interact with the element
- type() to enter text
- should() to make assertions
Each chained command runs only after cy.get() successfully finds the element.
Yielded Subject
When cy.get() resolves, it yields:
- A single DOM element if one match is found
- A collection of elements if multiple matches exist
This yielded subject becomes the input for the next command in the chain
Best Practices for Using cy.get()
Using cy.get() correctly is key to writing stable and maintainable Cypress tests. Following these best practices helps reduce flakiness and makes tests easier to debug and scale.
- Use Stable, Test-Friendly Selectors: Prefer attributes like data-cy or data-testid because they are less likely to change with UI or styling updates, making tests more reliable.
- Keep Selectors Simple and Readable: Use the shortest selector that uniquely identifies an element. Complex selectors are harder to maintain and more likely to break when the UI changes.
- Rely on Cypress’s Built-in Retries: Let cy.get() handle waiting automatically instead of adding hard waits, which often lead to flaky and slow tests.
- Avoid Selecting Multiple Elements Unintentionally: Ensure your selector targets only the intended element. If multiple elements are expected, explicitly assert their count or behavior.
- Scope Element Searches When Needed: Limit the search context to a specific section of the page to improve accuracy and avoid matching unintended elements.
- Chain Actions and Assertions Thoughtfully: Perform actions only after the element is resolved and ready, and add assertions to validate its state before interaction.
- Avoid Using cy.get() for Text-Based Selection: cy.get() is meant for selector-based queries, not locating elements by visible text, which can lead to unreliable tests.
cy.get() vs Other Cypress Commands
Each Cypress command serves a different purpose, and understanding how cy.get() compares to others helps you choose the right one.
cy.get() vs cy.find()
- cy.get() searches from the entire document by default, making it ideal for grabbing a top-level element.
- cy.find() searches within an already selected element, so it’s best for locating child elements inside a specific container.
cy.get() vs cy.contains()
- cy.get() selects elements using CSS selectors (IDs, classes, attributes), which is best for stable, test-friendly locators.
- cy.contains() finds elements based on visible text, making it useful for validating UI content or clicking buttons/links by their labels.
When to Use Which
- Use cy.get() when you have a stable selector and need reliable element targeting.
- Use cy.find() when narrowing down elements inside a specific section.
- Use cy.contains() when text is the most meaningful identifier, such as buttons, menus, or messages.
Handling Dynamic Elements with cy.get()
Dynamic elements are common in modern web applications and often appear or update based on user actions, API responses, or animations.
Cypress is designed to handle these scenarios, and cy.get() plays a key role in making dynamic element selection reliable.
cy.get() automatically retries until the element appears in the DOM or the configured timeout is reached. This built-in retry mechanism helps handle delayed rendering without requiring manual waits.
To work effectively with dynamic elements, cy.get() is often combined with assertions. Assertions such as checking visibility or existence ensure Cypress waits for the correct state before moving forward.
For elements that update after network calls, pairing cy.get() with network intercepts provides more control. Waiting for the relevant request to complete before asserting on the element improves stability and reduces flaky failures.
By relying on retries, assertions, and proper synchronization, cy.get() can reliably handle dynamic UI behavior without slowing down tests.
Common Mistakes with cy.get()
The following common mistakes often lead to flaky tests or confusing failures when using cy.get().
- Adding hard waits instead of relying on retries: Using fixed waits hides timing issues and slows tests, even though cy.get() already retries automatically.
- Using brittle selectors: Deep CSS paths, auto-generated IDs, or styling classes break easily when the UI changes.
- Selecting multiple elements unintentionally: When a selector matches more than one element, actions and assertions can behave unpredictably.
- Interacting with elements too early: Performing actions before elements are visible or ready leads to flaky failures.
- Using cy.get() for text-based selection: cy.get() is meant for selector-based queries, not for locating elements by visible text.
Debugging cy.get() Failures
When cy.get() fails, it usually means Cypress could not find the element within the default timeout, or the element exists but isn’t in an interactable state. The steps below help pinpoint the exact cause quickly.
- Verify the selector is correct and stable: UI changes often break selectors tied to classes, layout, or auto-generated IDs; prefer data-* attributes for stability.
- Check whether the element is actually in the DOM: The element may not be rendered yet, may be conditionally displayed, or may only appear after a user action or API response.
- Confirm visibility and interactability: Sometimes the element exists but is hidden, disabled, covered by another element, or not yet ready for interaction.
- Use the Cypress Command Log and snapshots: Inspect the command log to see exactly where the test diverged, then click the failed command to view the DOM snapshot at that step.
- Look for re-renders causing detached elements: In dynamic apps, elements can re-render after being selected; if you see “detached from the DOM,” re-query the element before interacting.
- Sync with network calls when UI depends on API responses: If UI appears after API data loads, intercept the request and wait for it before running cy.get() or assertions.
- Avoid “fixing” failures with hard waits: Hard waits slow tests and hide the root cause; rely on Cypress retries and state-based assertions instead.
Using cy.get() with Assertions
Assertions are commonly chained with cy.get() to verify element state and ensure Cypress waits for the expected condition before moving forward. This combination improves test reliability and reduces flaky failures.
- Assert element existence: Use assertions to confirm that an element is present in the DOM before interacting with it. This helps validate that rendering has occurred as expected.
- Assert visibility before actions: Checking that an element is visible ensures it’s ready for user interaction and not hidden, disabled, or covered by another element.
- Validate text and content: Assertions can confirm that elements display the correct text or values, which is especially useful for dynamic UI updates.
- Check element state: Use assertions to verify states such as enabled, disabled, checked, or selected before performing actions.
- Leverage assertions for automatic waiting: Cypress retries both cy.get() and the attached assertion until it passes or times out, making tests more stable without manual waits.
- Keep assertions specific and meaningful: Clear, focused assertions make failures easier to understand and debug.
Advanced Usage of cy.get()
Beyond basic element selection, cy.get() can be combined with other Cypress commands to handle more complex scenarios and improve test clarity.
- Using aliases with cy.get(): Aliases allow you to store a selected element or value and reuse it later in the test, reducing repeated queries and improving readability.
- Scoping selections with within():When working inside a specific section of the page, scoping cy.get() queries limits the search area and prevents accidental matches elsewhere in the DOM.
- Working with collections of elements: cy.get() can return multiple elements, which can then be iterated over or filtered to validate lists, tables, or repeated UI components.
- Accessing element properties and attributes: After selecting an element, you can inspect properties such as text, attributes, or CSS values to validate UI behavior more precisely.
- Chaining with custom commands: Combining cy.get() with custom commands helps encapsulate repeated logic and keeps tests clean and reusable.
- Using cy.get() with retries and timeouts: For elements that take longer to appear, adjusting timeouts or combining cy.get() with state-based assertions improves stability without hard waits.
Conclusion
The cy.get() command is at the core of how Cypress interacts with web applications. When used with stable selectors, proper assertions, and Cypress’s built-in retry mechanisms, it helps create reliable and maintainable tests even in dynamic UI environments.
Understanding common mistakes and advanced usage patterns further reduces flakiness and improves test clarity.
As Cypress test suites grow and are executed across multiple browsers and environments, consistent element behavior and visibility become even more important.
Platforms like BrowserStack Automate help teams run Cypress tests in parallel on real browsers and analyze failures using detailed logs and recordings, making it easier to validate cy.get() interactions at scale without managing test infrastructure.
Try BrowserStack Now