The other day, I was in the middle of running a Cypress test for my web app, as I often do. It seemed like a typical test scenario—I was navigating through the UI, looking for a specific element by its version number, and triggering a click event. The goal was simple: click on a promotion with a particular version, like “0”. But something unexpected happened.
I ran the test, and bam! I was greeted with an error that looked something like this:
Multiple Elements Found!
The error message was a bit of a shocker. According to Cypress, it was trying to click on multiple elements that matched the selector I was using. At first, this didn’t make sense to me because I was expecting it to click on just one specific promotion version with the value of “0”.
But the problem became obvious when I looked closer at the structure of the page. Here’s the catch: there were two elements with similar class names:
<div class="yw-listview-cell-label z-label">0</div>
<div class="yw-listview-cell-label z-label">10000</div>
Since both the value 0
and 10000
contained “0”, my Cypress test was attempting to click on both elements. In short, Cypress’s contains()
selector was too broad—it was treating “0” as a substring and matching it to “10000” as well. This explained the error!
The Problem: Matching vs. Exact Matching
The issue I was facing boiled down to how the Cypress contains()
command works. It performs a substring match, meaning it will select any element that contains the text, not just elements that match the text exactly. This is fine most of the time, but in my case, it was disastrous because I only wanted to target the element with an exact value of “0”, not something like “10000” or “1000000”.
The Solution: Filter for Exact Text Match
So how do you fix this?
I realized that to avoid this error, I needed to be more specific with my selector and ensure it only matched the element with the exact value of “0”. I did some research and found a solution using .filter()
. This allowed me to inspect the exact inner text of the elements I was targeting and filter out any that didn’t match perfectly.
Here’s how I solved the problem:
My Original Code:
cy.get(`.yw-listview-cell-label.z-label:contains("${promotionVersion}")`).click({ force: true });
The Improved Code:
I decided to use the .filter()
method to get more control over the text matching:
cy.get('.yw-listview-cell-label.z-label')
.filter((_, el) => el.innerText.trim() === promotionVersion)
.click({ force: true });
In this snippet, .filter()
allowed me to loop through the elements Cypress found and compare their exact text values to the value I sought. The el.innerText.trim() ensures that any extra spaces or characters around the version are ignored and the element’s inner text is compared directly to the promotionVersion
value.
Why This Works:
.filter()
is great because it applies a custom condition to each element in the result set.el.innerText.trim()
ensures we’re dealing with a clean text string, free of extra spaces or formatting issues.- This approach ensures Cypress only interacts with elements where the text is an exact match—no substring matching!
Another Way: Using .invoke()
for Exact Text
Alternatively, I could have used .invoke()
to pull out the text and conditionally click on the element if it matched the exact value:
cy.get('.yw-listview-cell-label.z-label')
.contains(promotionVersion)
.invoke('text')
.then((text) => {
if (text.trim() === promotionVersion) {
cy.wrap(text).click({ force: true });
}
});
In this case, the .invoke('text')
pulls out the text from the element that contains the promotion version. I then check if the text matches exactly before proceeding with the click. It’s another option to achieve the same result.
The Result: No More Errors!
After implementing the exact text match, I re-ran the Cypress tests. No more multiple elements error! Cypress was now correctly identifying and clicking the element with the exact promotion version of “0”, leaving the “10000” version untouched.
What felt like a frustrating debugging session quickly turned into a useful learning experience. It reminded me that sometimes our selectors must be smarter to avoid unexpected errors, especially when dealing with text-based comparisons.
Lessons Learned:
- Substring Matching vs Exact Matching: Be aware that Cypress’s
contains()
performs a substring match. This can lead to false positives if your text is part of another, longer string. - Using
.filter()
for Precision: The.filter()
method is an excellent way to get precise results, especially when working with text-based elements. You can apply any condition you want to make sure the right elements are selected. - Debugging in Cypress: Error messages in Cypress are usually quite informative. In this case, the error gave me a clear hint that there were multiple elements Cypress was trying to click, which made it easier to pinpoint the problem.
And just like that, my Cypress tests were back on track!