cypress: cy.get(el).should('match', regex) fails to compare regex against el's innnerText

Current behavior:

I’m not using the middle contains in my tests & I’ll use a more interesting regex to check something else. But, for a simple failing case, see:

cy.get('button').contains(/next/i).should('match', /next/i)

The above line of my e2e tests fails with the following output:

Command:     contains
Content:     /next/i
Applied To:  (3) [button.jss181.jss175.jss176, button.jss181.jss236, button.jss181.jss207.jss215.jss216.jss230.jss294]
Yielded:     <span class=​"jss208">​Next​</span>​
Elements:    1
Error:       CypressError: Timed out retrying: expected '<span.jss208>' to match /next/i

It looks like the contains yielded <span class=​"MuiButton-label-214">​Next​</span>​ But then the match assertion is only checking <span class=​"MuiButton-label-214">​ and not the inner text.

I don’t see anything in the assertion reference that suggests match should only be comparing against the element name & classes.

Desired behavior:

cy.get(element).should('match', regex) should compare the regex against the element’s inner text too, not just the element name & classes.

Alternatively, I’d like to have some way to assert that some element in an array has an inner text that matches some regex. See issue #3746 for another unsuccessful attempt I made at solving this problem.

Steps to reproduce: (app code and test code)

describe('Debug', () => {
  it('Should display an intro modal that can be closed', () => {
    cy.visit('https://daicard.io')
    cy.get('button').should('match', /next/i) // This fails
    cy.get('button').contains(/next/i).should('match', /next/i) // This fails too
  })
})

Versions

Cypress: 3.2.0 MacOS: 10.14.3 (18D109) Google Chrome: 72.0.3626.121 (Official Build) (64-bit)

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (2 by maintainers)

Most upvoted comments

You can use invoke('text') to already do this without a .then.

it('match text of DOM el', function () {
  cy.get('p').invoke('text').should('match', /Some text/)
})

There are some examples in our FAQ on how to get element’s text here https://docs.cypress.io/faq/questions/using-cypress-faq.html#How-do-I-get-an-element’s-text-contents

Would be nice to have a matcher like this:

cy.get(el).should('match.text', regex);

You have a bunch of other matchers for text (contain.text, have.text, include.text), but not one for regex 😞

Ok, figured it out: cy.contains('div', /regex/).should('exist') will do what I want.

cy.get('div').contains('text') will fail sometimes if there are divs present that let the first cy.get('div') succeed but the one containing text pops up later. The .contains('text') will repeatedly check the first collection of divs until timeout instead of running cy.get('div') again to get a new collection of divs to check.

But cy.contains('div', 'text') will retry both the div selection and the check that one contains text until either the correct div pops up or timeout.

Sounds like cy.get('div').contains('text') is actually never needed since it can always be replaced by the more robust version: cy.contains('div', 'text')

@jennifer-shehane can you accept this as a feature request? ☝️

// "match.text" assertion
cy.get(mySelector).should("match.text", myRegex)

Good news, @IMightGitIt, .contains() does work as an assertion, as answered above https://github.com/cypress-io/cypress/issues/3747#issuecomment-474292167

You can use both syntaxes: cy.get('span.number').contains(/\d+/) or cy.contains('span.number', /\d+/)

See for yourself running this example: https://github.com/rafawalter/cypress-contains

+1 to BBlackwo.

I currently end up with a “.then” to get the text and then run the RegEx assertion in an “expect” like:

cy.get(theThing).then(element => {
      const text = element.text()
      expect(text).to.match(myRegEx)
    })

With his suggestion, this would become so much cleaner like: cy.get(theThing).should('match.text',myRegEx)

I end up using RegEx quite a lot for me testing as we have some very dynamic labels. For example, a trend indicator for chart could either be “-1.2%” or “+123,234.5%”. So having to do this text conversion each time becomes quite a hassle in the long run.

Each command in our API documents what is yielded from the command. .contains() yields the entire DOM element, not just its innerText, so match will not work here since it’s looking for a string to compare.

There are many ways to access and assert on the innerText of an element as documented here: https://on.cypress.io/using-cypress-faq#How-do-I-get-an-element’s-text-contents

@pstephenwille When I was checking image hrefs I used and nested setup like this that worked perfectly.

cy.get('image.holder').invoke("attr", "href").should("not.match", /^(data\:image\/jpeg;base64,)/i)
    .then(() => { // some more things to check after the above runs })
});