Reputation: 830
Let's assume I have such html:
<div class="my_class" id="first_case">
<a href="/foo/bar/123"></a>
</div>
<div class="my_class" id="second_case">
<a href="/foo/bar/1234567"></a>
</div>
I want to make assertion that there is an item with href, which ends with '/123'.
const test_id = '123'
cy.get('.my_class').find('a').should("have.attr", "href").and("contain", '/' + test_id);
It works, however I don't know how to make sure that the assertion is true only for href with exact ending ('/123', as shown in #first_case in first code snippet) and that it is false for other strings starting with such number, for example ('/1234567', as shown in #second_case in first code snippet).
In other words, the assertion should be true for #first_case, but false for #second_case.
I tried using end of string symbol or making new RegExp object, however couldn't make it work. Any help would be appreciated!
Upvotes: 10
Views: 16655
Reputation: 133
Out of the box, ChaiJs provides the satisfy
keyword which is followed by a predicate.
The predicate can use any Javascript expression, so for example using String.prototype.endsWith()
cy.get('.my_class')
.find('a')
.should('have.attr', 'href')
.and('satisfy', href => href.endsWith('/' + test_id))
This is almost the same as Brendan's example, except he uses .then()
with variations of href.endsWith(test_id)
. This IMO is a mistake since then()
does not have any retry capability.
Using .should()
or .and()
for assertions is always preferable to avoid flaky tests due to asynchronous loading of items.
Chainer | Example |
---|---|
satisfy (method) | .should('satisfy', (num) => num > 0) |
Aliases: satisfies | expect(1).to.satisfy((num) => num > 0) |
Upvotes: 10
Reputation: 714
Out-of-the box Chai does not have an 'endsWith' assertion so I added my own to support/e2e.ts
as follows:
// Custom Chai assertion "endsWith" to check if a string ends with another string
// See for more details:
// https://docs.cypress.io/app/references/assertions#Adding-New-Assertions
// https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/extending-cypress__chai-assertions
// https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/extending-cypress__chai-assertions/cypress/support/e2e.js
//
const customAssertionEndsWith = (_chai) => {
function assertEndsWith(options) {
this.assert(
typeof this._obj === 'string' && this._obj.endsWith(options),
'expected #{this} to be string that ends with #{exp}',
'expected #{this} to not be string that ends with #{exp}',
options, // expected
this._obj, // actual
);
}
_chai.Assertion.addMethod('endsWith', assertEndsWith);
};
// registers our assertion function "customAssertionEndsWith" with Chai
chai.use(customAssertionEndsWith);
which I then use in my tests like
cy.url().should('endsWith', '/settings/terms');
Upvotes: 0
Reputation: 96959
I think there's even easier way to do this. You can use a single cy.get()
and single should()
because Cypress selectors should behave the same way as jQuery selectors do.
cy.get('.my_class a[href$="/123"]').should('have.length', 1);
$=
will match only attributes that end with /123
.
Upvotes: 7
Reputation: 4659
.should()
will yield you the href so you can use it in a .then()
block however you like (see https://stackoverflow.com/a/48451157/2883129), so you can use .endsWith()
:
const test_id = '123'
cy.get('.my_class')
.find('a')
.should("have.attr", "href")
.then(href => {
expect(href.endsWith(test_id)).to.be.true;
});
Or to make it a bit more readable and a failure message to be clearer, you could use https://www.chaijs.com/plugins/chai-string/:
const test_id = '123'
cy.get('.my_class')
.find('a')
.should("have.attr", "href")
.then(href => {
expect(href).to.endWith(test_id);
});
Upvotes: 8
Reputation: 68933
In vanilla JS, you can try with querySelector()
and attribute ends with selector ([name$="value"
). Please note, you forgot to close the a
element.
const test_id = '123'
var el = document.querySelector(`[href$="${test_id}"]`);
console.log(el);
<div class="my_class" id="first_case">
<a href="/foo/bar/123"></a>
</div>
<div class="my_class" id="second_case">
<a href="/foo/bar/1234567"></a>
</div>
Upvotes: 2