In Cypress I can match an attribute's value by exact text like this:
cy.get("my-element")
.should("have.attr", "title", "Exact title")
But, is there a way to match the attribute's value by a substring or a regular expression? something like:
cy.get("my-element")
.should("have.attr", "title", /Partial title/)
So far, this is the best I have:
cy.get("my-element")
.should("have.attr", "title")
.then(title => expect(title).to.match(/Partial title/));
Per the Cypress docs, have.attr comes from chai-jquery:
attr(name[, value])
Assert that the first element of the selection has the given attribute, using .attr(). Optionally, assert
a particular value as well. The return value is available for
chaining.
$('#header').should.have.attr('foo');
expect($('body')).to.have.attr('foo', 'bar');
expect($('body')).to.have.attr('foo').match(/bar/);
It only takes an exact value for the attribute directly. However, because the return value changes the subject, you can use chaining as also shown in the Cypress docs:
cy
.get('nav') // yields <nav>
.should('be.visible') // yields <nav>
.should('have.css', 'font-family') // yields 'sans-serif'
.and('match', /serif/)
In your case that would be
cy.get("my-element")
.should("have.attr", "title")
.and("match", /Partial title/);
Related
I have a scenario, where i need to put Assertion on an element's text which could be true OR pass the test case, if the any 1 value is present out of many.
Let say, an element can contain multiple status' : 'Open', 'Create', 'In Progress' any of these could be true.
How can i implement this scenario and Assert with OR logical operator or any other way?
cy.get('element').should('have.text', 'Open' | 'Create')
It sounds like a one-of assertion, something like the following:
cy.get('element')
.invoke('text')
.should('be.oneOf', ['Open', 'Create'])
To do it you need to extract the text before the assertion.
For reference see chaijs oneOf
Asserts that the target is a member of the given array list. However, it’s often best to assert that the target is equal to its expected value.
These both Worked:
cy.get('element')
.invoke('text')
.should('satisfy', (text) => text === 'option1' || text === 'option2')
OR
cy.get('element')
.invoke('text')
.should('be.oneOf', ['option1', 'option2']);
Wodens answer is most valuable if you wish to make an assertion and have the test fail if one of them doesn't exist
However, if you want to check the text of the element that is visible and do separate things based on which one is available:
cy
.get('element')
.filter(':visible')
.invoke('text')
.then((text) => {
if(text.includes('Open')){
// Things that only occur when Open is present
} else if (text.includes('Create')){
// Things that only occur when Create is present
} else if (text.includes('In Progress')){
// Things that only occur when In Progress is present
} else {
// Things that happen when the options are exhausted
}
});
I want to assert that a component contains a string without caring about the string case.
For example, I want
cy.get('#label').should('contain.text', 'integrator');
to pass even if the label contains "Integrator."
What is the best way I can make this assertion?
You can also use cy.contains() with a regular expression
cy.contains('#label', /integrator/i) // should is implied in this command
or as an option
cy.contains('#label', 'integrator', {matchCase:false})
With should() you get retry of the expect()
cy.get('#label')
.should($el => {
expect($el.text().toLowerCase()).to.eq('integrator') // exact
// or
expect($el.text().toLowerCase()).to.contain('integrator') // partial
})
What you need is Regular expressions.
You can use the match assertion:
cy.get('#label')
.invoke('text')
.should('match', /integrator/i) //i = case sensitive
You can do like this as well:
cy.get('#label').then(($ele) => {
expect($ele.text().toLowerCase()).to.contain('integrator')
})
When testing a complex component, I want to assign multiple whitespace-separated values to data-cy attribute, for example
<div data-cy="my-component disabled" />
and use the ~= attribute selector to query for the element:
cy.get('[data-cy~="my-component"]')
Now, having already queried for my-component, how can I further assert that it:
does contain "disabled" in data-cy
does not contain "disabled" in data-cy
in broader sense, does or does not satisfy a css selector?
I know I can explicitly re-query with all parameters for each assertion, eg.:
cy.get('[data-cy~="my-component"]:not([data-cy~="disabled"])').should('exist')
but this feels overly complicated and doesn't read very well - I want to query the element first, and further assert against it in a later step - for example:
cy.get('...').should(el => {
// assert here
})
The approach seems like a good one. If you used individual attributes, likely they would clash with other "native" attributes.
For example if data-cy="disabled" means the "Person" has a disability, but used unwrapped the browser would disable the element.
Ref Using data attributes
data-* attributes allow us to store extra information on standard, semantic HTML elements without other hacks such as non-standard attributes, or extra properties on DOM.
Also some frameworks (React) are fussy about the attributes allowed on an element.
You might be looking for a function to provide the selector for the test.
const asDataCy = (attrs) => {
return attrs.split(' ').map(attr => {
let op = '~'
if (item.charAt(0) === '!') {
op = '!'
attr = attr.slice(1)
}
return `[data-cy${op}="${attr}"]`
).join('')
}
cy.get(asDataCy('my-component !disabled'))
// [data-cy~="my-component"][data-cy!="disabled"])
The Chai-jQuery assertion expect($el).match(selector) does exactly that!
// should form
cy.get('[data-cy~="my-component"]')
.should('match', '[data-cy~="some-value"]')
.should('match', ':not([data-cy~="something-else"])')
// expect form
cy.get('[data-cy~="my-component"]')
.then(el => expect(el).to.match('[data-cy~="some-value"]'))
.then(el => expect(el).to.match(':not([data-cy~="something-else"])'))
I have this following element which contain a string for Practitioner, its value is 1- zzz. How to validate after - it shouldn't be null. Even if there is a string or empty. It shouldn't print null. Also want to select the value under Practitioner (currently hard coded the position of the element as 2)
<div class="styles__container___BfTYi">
<div class="styles__subHeader___18Yg1">Practitioner</div>
<div class="styles__data___1senX">1- zzz</div>
</div>
I have the following code to retrieve the text,
cy.get(pageSelector.practitionerValidator).eq(2).then(function($getText) {
let practitionerName = $getText.text();
var validateLastName = practitionerName.split(' ');
cy.log(validateLastName[1]);
expect(validateLastName[1]).to.not.equal('null');
})
You can directly check that the entire string is not null like this:
cy.get('.styles__data___1senX').then(($ele) => {
expect($ele.text()).to.not.be.null
})
Or if you want to check that your inner text is not empty you can do:
cy.get('.styles__data___1senX').then(($ele) => {
expect($ele.text()).to.not.be.empty
})
You can find the selector from the text Practitioner like this:
cy.contains('Practitioner')
.parent()
.within(() => {
cy.get('div[class*="styles__data__"]').then(($ele) => {
expect($ele.text()).to.not.be.null
})
})
Appreciate the level of detail you gave.
I will be going off this assumption.
the Practitioner string will be random can spaces or no spaces after the - (ie 34- sdfwe, 3- , 1- )
I would use a regex to check the format of the string to check the string starts with a digit followed by a dash and a space with either a string, spaces, or nothing. /\d+\-\s(\w+|\s+)?/
Your code would look a bit like this.
cy.get(pageSelector.practitionerValidator)
.eq(2)
.invoke('text') // get text
.should('match', /\d+\-\s(\w+|\s+)?/) // use regex assertion
How can I get the first button which has type, class, id or ANYTHING containing text (have a substring equal to) close or Close or CLOSE? I tried this:
//button[contains(text(),'close')]
but it doesn't work.
Your predicate was testing whether any text() nodes contained "close". However, attributes are not text() nodes.
You can adjust your predicate to match on any attribute, then use a predicate on those attributes to test whether it's name() is "type", "class" or "id" and that it's lower-case() value contains "close":
With XPath 2.0 you could use this:
//button[#*[ name() = ('type','class','id') and contains(lower-case(.), 'close') ]]
With XPath 1.0, it takes a little more work. You can translate the upper-case letters into lower-case letters:
//button[
#*[name() = 'type' or name() = 'class' or name() = 'id']
[contains(translate(.,'CLOSE','close'), 'close')]]