Cypress get vs find vs contains: Which Locator Method to Use

A
Artem Bondar
7 min read

Cypress gives you three methods to locate web elements on the page: cy.get(), cy.find(), and cy.contains(). They look similar, but they behave very differently. Use the wrong one and your test will find too many elements, the wrong element, or nothing at all.

Let's review all three and see how they work in practice.

The three Cypress locator methods at a glance

Here's the quick version:

  • cy.get() finds elements on the page globally. It always searches the entire DOM.

  • cy.find() finds child elements only. It searches within a parent element.

  • cy.contains() finds elements by text. It returns only the first match on the page.

Now let's look at each one in depth.

cy.contains(): find elements by text

cy.contains() is probably the most interesting of the three because it comes with several nuances that catch people off guard.

Basic usage

At its simplest, cy.contains() takes a text string and finds the first element on the page that contains that text.

1
cy.contains('Sign In')

If your page has two "Sign In" buttons, cy.contains() will match the first one in the DOM. Unlike cy.get(), which returns all matching elements, cy.contains() always gives you a single element.

Case sensitivity

cy.contains() is case sensitive. It looks for the exact text as it appears in the DOM, not as it appears visually on the page.

Why does this matter? Because CSS can transform how text looks. A button might display "SIGN IN" in all caps on the screen, but if you inspect the DOM, the actual HTML text is "Sign In" with mixed case. The CSS text-transform: uppercase property does the visual transformation.

So if you write:

12
// This will FAIL if the DOM text is "Sign In"cy.contains('SIGN IN')

You get: Expected to find content 'SIGN IN' but never did.

To disable case sensitivity, pass an options object:

1
cy.contains('sign in', { matchCase: false })

Now Cypress finds the element regardless of case. Yes, that simple :)

Partial text match

You don't need to provide the full text. cy.contains() works with partial matches too.

12
// Finds an element containing "Sign In"cy.contains('Sign')

If the element's text is "Sign In", searching for just "Sign" will match it. Be careful though. A short partial match can accidentally grab an element you didn't intend.

HTML text vs attribute text

This one trips up a lot of people. cy.contains() only finds HTML text nodes, not attribute values.

Say you have an input field with a placeholder:

1
<input placeholder="Email" />

You see "Email" on the page, but cy.contains('Email') will not find this input field. "Email" here is a placeholder attribute, not actual text content in the DOM.

Compare that with:

1
<label>Remember me</label>

"Remember me" is actual HTML text. cy.contains('Remember me') finds it no problem.

So if cy.contains() can't find something you can clearly see on the page, check whether that text lives inside an HTML attribute rather than as a text node.

Two arguments: locator + text

Now here's the really cool part. You can pass two arguments to cy.contains(): a CSS selector and a text string. Cypress finds the element that matches both.

1
cy.contains('[status="warning"]', 'Sign In')

Say you have two "Sign In" buttons on the page. One has status="primary", the other has status="warning". By combining the selector with the text, you target the exact button you need.

You can also use this pattern to find a parent container by its heading text:

1
cy.contains('nb-card', 'Horizontal Form')

This finds the nb-card element that contains the text "Horizontal Form". Now you have a reference to the entire form and can chain further commands to interact with elements inside it.

This two-argument pattern is one of the most useful features of cy.contains(). It lets you build precise, readable locator strategies without relying on brittle CSS selectors alone.

cy.find(): search within a parent element

cy.find() is for locating child elements within a parent. You cannot use it standalone, it must be chained from another command.

Say you already found the "Horizontal Form" container using cy.contains():

1
cy.contains('nb-card', 'Horizontal Form').find('button')

This finds the button element inside the Horizontal Form only. Even if the page has dozens of buttons, cy.find() it limits the search to the children of that parent element.

You can also chain cy.contains() after finding a parent to search within it by text:

1
cy.contains('nb-card', 'Horizontal Form').contains('Sign In')

This works because cy.contains(), when chained from a parent, searches within that parent's subtree first.

The key point: cy.find() respects the scope of the parent element. It only looks at descendants.

You can't chain the find() method from cy.. Method find() can only be chained from another Cypress command.

cy.get(): always searches globally

cy.get() is the most commonly used locator method in Cypress. It accepts standard CSS selectors and returns all matching elements from the entire page.

123
cy.get('button')        // All buttons on the pagecy.get('#email')        // Element with id "email"cy.get('.btn-primary')  // All elements with class "btn-primary"

But here's what catches most beginners. Even if you chain cy.get() from a parent element, it still searches the entire page.

1234
// You might expect this to find buttons only inside the formcy.contains('nb-card', 'Horizontal Form').get('button')// But cy.get() ignores the parent and finds ALL buttons on the page

If the page has 8 buttons, chaining cy.get('button') from a parent container still returns all 8. The parent context is completely ignored.

If you need scoped search, use cy.find() instead.

TIP The only way to make cy.get() respect a parent boundary is the .within() command: cy.get('form').within(() => { cy.get('input') }).

Cypress get vs find vs contains: quick comparison

So what do we have so far? Here's the summary of all three methods side by side:

Feature

cy.get()

cy.find()

cy.contains()

Search scope

Entire page (global)

Child elements only

First text match on page

Locator type

CSS selectors

CSS selectors

Text (or selector + text)

Returns

All matching elements

All matching children

Single element (first match)

Can be standalone?

Yes

No (must chain)

Yes

Case sensitive?

N/A

N/A

Yes (configurable)

Partial match?

No

No

Yes

So when do you use which? If you have a stable CSS selector and need to find elements anywhere on the page, go with cy.get(). If you already have a parent element and need to drill down into its children, cy.find() is the right pick. And if text content is the most reliable way to identify the element, cy.contains() has you covered.

Final Thoughts

Once you understand the scope rules, Cypress locator methods are pretty straightforward. cy.get() is global. cy.find() is scoped to children. cy.contains() matches by text with a few quirks you need to know.

The biggest gotcha? Chaining cy.get() from a parent and expecting scoped results. Now you know better. Use cy.find() for scoped searches, and reach for cy.contains() with two arguments when you need precise targeting without complex selectors.

If you're working with Cypress and considering what the right framework for your project is, check out this detailed comparison of Playwright vs Cypress to make an informed decision.

Cypress is a wonderful framework. In my opinion, it is the easiest UI automation scripting framework on the market. Get new skills at Bondar Academy with the Cypress UI Testing Mastery program. Start from scratch and become an expert to increase your value on the market!

Frequently Asked Questions

What is the difference between cy.get() and cy.find() in Cypress?

cy.get() always searches the entire page globally, regardless of chaining. cy.find() only searches within the children of the parent element it is chained from. Use cy.find() when you need scoped element selection.

Is cy.contains() case sensitive?

Yes, cy.contains() is case sensitive by default. It matches text exactly as it appears in the DOM. You can disable this by passing { matchCase: false } as an options argument.

Can cy.contains() find HTML attribute values?

No. cy.contains() only finds actual HTML text nodes in the DOM. Attribute values like placeholder, value, or title are not matched. Use cy.get('[placeholder="Email"]') to target elements by attribute.

How do I use cy.contains() with two arguments?

Pass a CSS selector as the first argument and the text as the second: cy.contains('.my-class', 'Button Text'). This finds an element matching both the selector and the text content.

Why does cy.get() ignore the parent when chained?

By design, cy.get() always queries from the document root. Chaining it from a parent does not limit its scope. If you need scoped queries, use cy.find() or wrap the parent with .within().

Can cy.contains() match partial text?

Yes. If an element's text is "Sign In", using cy.contains('Sign') will match it. Be cautious with very short partial strings as they may match unintended elements.

Artem Bondar

About the Author

Hey, this is Artem - test engineer, educator, and the person behind this academy.

I like test automation because it drastically reduces the workload of manual testing. Also, it's a lot of fun when you build a system that autonomously does your job.

Since 2020, I have been teaching how to use the best frameworks on the market, their best practices, and how to approach test automation professionally. I enjoy helping QAs around the world elevate their careers to the next level.

If you want to get in touch, follow me on X, LinkedIn, and YouTube. Feel free to reach out if you have any questions.