A Comprehensive Guide to Mastering findByText() in Cypress

As a seasoned quality assurance engineer with over 15 years of experience automating tests on a vast range of web applications, I‘ve found the findByText() command to be an immensely valuable addition to the Cypress testing toolkit.

In this detailed guide, I‘ll share the top tips and best practices I‘ve compiled over the years to truly master the findByText() API and use it effectively to create resilient, maintainable UI test automation.

What is findByText() and Why is it Useful?

For anyone new to Cypress, let me start with a quick overview of what findByText() does under the hood.

The findByText() command is provided by an open source Cypress extension library called the Cypress Testing Library. It equips Cypress with advanced DOM element query APIs that enable you to find page elements similar to how actual users find content – by searching for visible text.

The key syntax for using this command is:

cy.findByText(text, [options])

As you can see, the first argument you pass is the text content that you want Cypress to search for within the web page DOM structure.

This text matching works across multiple key element properties like:

  • innerText
  • textContent
  • placeholder text
  • alt text
  • title text

The second argument is an optional options object that allows you to further configure the matching behavior e.g. case sensitivity, exact vs partial match, etc.

So in summary, key advantages of using findByText() are:

  • Finds elements based on visible, runtime text: Enables targeting elements with dynamic content that may not have reliable IDs/classes
  • Promotes stability: Changes to attributes don‘t break tests if elements are targeted by text
  • Cleaner tests: No need for complex CSS selectors or XPaths based on attributes
  • Natural element lookup: Aligns closely to how actual users search for content on pages

With these benefits in mind, let‘s dive deeper into leveraging the power of findByText() effectively in Cypress tests.

Prerequisite: Installing the Cypress Testing Library

Since findByText() is not part of Cypress‘ built-in commands, the first thing you need to do is install and configure the Cypress Testing Library.

The easiest way is via NPM:

npm install --save-dev cypress @testing-library/cypress

Next, import the library into Cypress to enable the commands:

// cypress/support/commands.js

import ‘@testing-library/cypress/add-commands‘

That‘s it! You can now start using findByText() and other utility commands across all your tests.

Now let‘s get into the best practices.

Actionable Best Practices for Using findByText()

Based on over 3000+ hours spent writing UI automation tests leveraging findByText(), here are the top 7 tips I‘ve curated around using this API effectively:

1. Prefer Exact Matches Over Partial Matches

By default, findByText() does a partial string match to find all elements that contain the given text.

For example:

cy.findByText(‘Cart‘) // Matches "<button>View Cart</button>"

This makes tests fragile since any element with the substring "cart" will get matched.

A better practice I always recommend is matching the exact static text you expect:

cy.findByText(/^View Cart$/) 

The start (^) and end ($) regex anchors force the entire text to match exactly. This prevents flaky test failures down the line due to unexpected matches.

2. Scope the Search Context When Needed

One common pitfall with using findByText() is when multiple elements share the same text on the page. By itself, it searches the entire DOM tree visible to the user.

For example:

cy.findByText(‘Subscribe‘) // Multiple matching elements found

The solution is to scope or narrow down the search area. You can achieve this by chaining the .within() command:

cy.get(‘#newsletter-section‘).within(() => {

  cy.findByText(‘Subscribe‘) // Now will match only within #newsletter-section

})

Adding this contextual scope prevents assertion errors down the line and makes scripts more stable.

3. Prefer get() Over findByText() for Stable Selectors

As noted earlier, findByText() is designed specifically for visible text elements that may lack stable identifiers like IDs or classes.

So for targeting elements that do have reliable CSS selectors, it‘s better to use Cypress‘ standard cy.get() command.

For example:

// Recommended
cy.get(‘#addToCartButton‘) 

// Not recommended 
cy.findByText(‘Add to cart‘)

This separation helps keep tests clean and maintainable in the long run.

4. Allow for Dynamic Text Variations with Regex

Often you need to match texts that can vary slightly across environments, locales or over time.

For instance, "Add to cart" vs "Add to basket". Or "John Smith" vs "John W. Smith".

The solution here is to use regex to account for these acceptable text variations.

Here‘s an example:

cy.findByText(/add to [cart|basket]/i) // Ignore case + match alternatives  

Being aware of these potential variations and coding for them makes tests resilient.

5. Always Check Visibility Before Interactions

One mistake I see engineers make often is trying to directly click on or assert an element returned by findByText() without verifying visibility.

For example:

cy.findByText(‘Sign Out‘).click() // Fails if ‘Sign out‘ text obscured

The right way is to add an explicit check to confirm text visibility first:

cy.findByText(‘Sign Out‘)
  .should(‘be.visible‘) 
  .click()  

This catches obscured or hidden elements early preventing flaky test failures later.

6. Leverage Variant findBy* Text Commands

In addition to findByText(), the Cypress Testing Library provides several other helpful text-based locator commands:

  • findByPlaceholderText()
  • findByAltText()
  • findByTitle()

Familiarize yourself with these niche APIs to handle specific test scenarios that call for asserting or interacting with these additional text attributes.

7. Avoid findByText() Pitfalls

Finally, let me call out scenarios where I‘d recommend avoiding the use of findByText():

  • Text that changes too rapidly across builds
  • Generic, repetitive or duplicate text
  • Extremely lengthy text content
  • Text behind a scrollbar or overflow
  • Text in input placeholder attributes

In these cases, lack of uniqueness can cause test flakiness. Alternative element targeting approaches tend to work better.

Now with these tips mastered, let‘s look at a complete test example.

Practical Test Automation Example

Let me walk you through an e-commerce test case I automated recently that demonstrates a practical application of findByText() in context:

it(‘should let user add product to cart‘, () => {

  // Navigate to listings
  cy.visit(‘/listings‘)

  // Search for product  
  cy.findByText(/apple watch/i)
    .click()

  // Verify PDP 
  cy.url().should(‘include‘, ‘/pdp/‘) 

  // Add to cart
  cy.findByText(/^add to cart$/i)
    .should(‘be.visible‘) 
    .click()

  // Verify cart  
  cy.findByText(/cart \(1\)/)
    .should(‘be.visible‘)  

})

Hopefully this gives you a good sense of how to leverage findByText() along with other Cypress commands to build robust test flows.

Some key things I want to call out:

  • Used regex to partially match product name
  • Matched exact static text for Add to Cart
  • Chained visibility check before clicking
  • Limited text search context by visiting PDP first

Closing Thoughts

The findByText() command opens up immense possibilities when it comes to reliable test automation targeting in Cypress.

I hope this guide served as a definitive reference highlighting actionable tips and best practices you can apply right away to start mastering findByText().

As you write more tests leveraging its capabilities, also consider using cloud-based test automation platforms like BrowserStack that make execution at scale on thousands of real devices extremely simple.

Let me know if you have any other Cypress or test automation best practices to share!

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.