Cypress: should('have.text', ...) should ignore leading and trailing whitespace

Created on 4 Apr 2019  路  12Comments  路  Source: cypress-io/cypress

If your HTML happens to have whitespace in the tag, e.g., <div> foo </div>, that text will not impact how the user sees the page, unless it is a <pre> element. I don't think that the 'have.text' assertion should fail just because it found ' foo ' when it was expecting 'foo'.

If you're not willing to change this (since it is technically a breaking change), maybe there should be a have.text.trimmed?

Current behavior:

should('have.text', ...) fails if the HTML contains whitespace, even if that whitespace doesn't impact the rendered content.

Desired behavior:

should('have.text', ...) should ignore leading and trailing whitespace for elements that won't render it. Elements like pre (and elements with certain white-space css values) should still consider leading and trailing whitespace.

Versions

3.2.0

existing workaround pkdriver proposal 馃挕 breaking change enhancement

Most helpful comment

I also encountered the same issue so I use:

cy.get('.message').should('contain.text', message)

All 12 comments

There's a related feature request here for making cy.contains() strip newlines: #92

Recently I added a .text() command to https://github.com/Lakitna/cypress-commands .

.text() will trim whitespace and provides some whitespace options.

It is nice to have the text() trim the string but is it possible to chain assertions with text()?

What I did was to add a custom command like:

Cypress.Commands.add(
    'shouldHaveTrimmedText',
    {
        prevSubject: true,
    },
    (subject, equalTo) => {
        if (isNaN(equalTo)) {
            expect(subject.text()).to.eq(equalTo);
        } else {
            expect(parseInt(subject.text())).to.eq(equalTo);
        }
        return subject;
    },
);

And now I can do:

cy
 .get('.some-class')
 .shouldHaveTrimmedText('whatever');

One way to go about it is:

cy.get('...').should($el => expect($el.text().trim()).to.equal('...'));

It is nice to have the text() trim the string but is it possible to chain assertions with text()?

Yes, .text() as it exists in cypress-commands awaits all its upcoming assertions via the same API as the default Cypress commands. This way it has the same behaviour as commands you're familiar with like .get().

cy.get('...')
  .text()
  .should('equal', 'foo');

I also encountered the same issue so I use:

cy.get('.message').should('contain.text', message)

the same issue as above - cypres 4.x

The problem with contains is it matches any substring.

Given:
<div> Tag1, Tag2 </div>

cy.get('div').should('have.text', 'Tag1, Tag2'); should pass (trims whitespace)
cy.get('div').should('have.text', 'Tag1'); should fail because of the extra text

Given that the cypress matchers are Chai, I'm not sure if we'd have to extend Chai or cypress to implement this.

This seems to work:

cy.get("div").invoke("text").then((text) => text.trim()).should("equal", "Tag1");

I'm not sure how to turn that into a custom command though.

We try to keep the number of external packages as low as possible in our project so we can add our own custom commands but are not likely to use third party command packages.

This seems to work as a slight modification on https://github.com/cypress-io/cypress/issues/3887#issuecomment-522962482 but I don't think it's as flexible since it doesn't have the jQuery helper, but I can't figure out how to use invoke in the custom command.

Cypress.Commands.add(
    "shouldHaveTrimmedText",
    { prevSubject: true },
    (subject, equalTo) => {
        expect(subject.text().trim()).to.eq(equalTo);
        return subject;
    },
);

It shouldn't be difficult to copy .text() from cypress-commands. Why reinvent the wheel?

Was this page helpful?
0 / 5 - 0 ratings