Cypress: Check if an element contains a specific other element - cypress

I need to check a div to see if it contains an 'a' (link). I've been looking at similar questions here, but none seem to do exactly what I'm trying.
Example markup:
<div if='description>
blablablabla
blablablabla
blablablabla
</div>
<div id='description'>
blablablabla
The link
blablablabla
</div>
<div id='description>
blablablabla
blablablabla
blablablabla
</div>
The ids are duplicated, and there's nothing I can do about that. However, using .eq() in these cases seems to work fine.
What I need to do, is to check, for instance, cy.get('#description').eq(0) to see if there is an 'a' within it, and click it if there is. If there is no 'a', do nothing.
I've tried things like this, without success:
if (cy.get('#description').eq(0).contains('a')) {
cy.get('#description').eq(0).within( () => {
cy.get('a').click();
});
Probably incorrect code anyway, with regards to the use of within.
This, too:
if (cy.get('#description').eq(0).children().contains('a')) {
cy.get('#description').eq(0).within( () => {
cy.get('a').click();
});
All help and/or hints are, as allways, appreciated. (Man, I miss Selenium sometimes, where I could use Java or Kotlin code with near full freedom.)

You can use children for this as mentioned by #lbsn and then add click().
cy.get('#description').eq(0).children('a').click()
You can also look into this, like when you get the a then click on it and exit each() and if there is no child element, the test continues and doesn't fail.
cy.get('div#description').each(($ele) => {
if ($ele.children('a').length > 0) {
cy.wrap($ele).children('a').click()
return false //Remove if you want to continue the loop even after finding the child element
}
})

Related

Cypress assert item in table related to it's title

On my page I have multiple tables with this structure:
<div class="box"><h4>Service 1</h4></div>
<div class="container"><ag-grid-table>items in the table</ag-grid-table><div>
<div class="box"><h4>Service 2</h4>
<div class="container"><ag-grid-table>items in the table</ag-grid-table><div>
</div>
<div class="scope-header"><h5>Service 3</h5></div>
<div class="scope-grid"><ag-grid-table>items in the table</ag-grid-table><div>
As you can see, all sections have different structure, and there are even more on the page.
What I want to achieve is to assert that the Service 3 table contains the correct item.
I was thinking about using cy.get('div.scope-header').contains('Service 3') and then using next() or sibling() but the ag-grid-table is neither directly next or sibling.
The only idea I have is to check ag-grid-table:nth(n), this should work, but is there a solution that selects the table according the header title text?
I mean select the table e.g. belonging to Service 3 only.
If you want to continue from cy.get('div.scope-header')
cy.contains('div.scope-header', 'Service 3') // this returns div.scope-header
// not <h5>Service 3</h5> which
// cy.get().contains() would do
.next() // next() moves you to <div class="scope-grid">
.find('ag-grid-table') // table is within that
You can do something like this with .sibling()
cy.contains('div.scope-header', 'Service 3')
.sibling('div.scope-grid') // move to specified sibling
.find('ag-grid-table') // within that element
.should(...)
From what I understood from your question, You can do something like this:
cy.contains('div.scope-header', 'Service 3')
.next() //goes to .scope-grid
.within(() => {
// scopes search within .scope-grid
cy.contains('ag-grid-table', 'some text').should('be.visible')
//OR
cy.get('ag-grid-table').find('item selector').should('be.visible')
//OR
cy.get('ag-grid-table')
.find('item selector')
.should('have.text', 'some text')
})
Something like this, you can do use Traversal commands.
Adding selectors to next() and sibling() is more robust when page layout changes.
cy.contains('h5', 'Service 3')
.parent('div.scope-header')
.next('div.scope-grid')
.children('ag-grid-table')
.find('div.ag-row').eq(2)
...

Cypress Assertions, verify class exists for certain text

Afternoon Stack community.
Pretty new to cypress, what I'm looking to do is identify some text on a page and chain that there should be a particular class with that text. Able to retrieve the text fine but not the class.
From my spec file:
cy.contains('some text').should('have.css', 'fa-pencil')
Page source
<h2 class="module__header big-right" style="text-transform: none;">
some text
<span class="push-right">
<a target="_new" class="fa fa-question-circle-o" href="{env details}" aria-hidden="true"></a>
If the page source shown is accurate, "some text" is outside the element that has the class you seek.
It's on the first child of <h2>, so adding .children() to the test will allow you to test it with have.class
cy.contains('some text') // this will give the parent <h2> element
.children().eq(0)
.should('have.class', 'fa-pencil')
When Cypress runs cy.contains('some text') it finds the closest containing element going upwards in the hierarchy from the text.
In this case it's the <h2> since is closed off before the text occurs, so that can't be the containing parent.
You can still verify the class of <a.fa.fa-pencil> by using a navigational command children() to go inside the <h2>.
You could also specify the child with that particular class like this
cy.contains('some text') // this will give the parent <h2> element
.children('.fa-pencil') // child with the class
.should('have.class', 'fa-pencil') // not really needed, gets tested in line above
In case of an exact match with the text:
cy.get('selector')
.should('have.text', 'some text')
.and('have.class', 'fa fa-pencil')
In case of partial match with the text:
cy.get('selector')
.should('contain', 'some text')
.and('have.class', 'fa fa-pencil')

Cypress picks up the wrong element?

I am trying to find and click this element using Cypress:
<input class="form-control btn btn-primary" type="button" value="Log out">
I have tried several variations, but the closest is this:
cy.get("input[type='button']").filter('.btn-primary').should('have.value','Log out').click()
So when I run this, I get the following response:
expected [ <input.form-control.btn.btn-primary>, 1 more... ] to have value Log out, but the value was Edit.
Sure, there is a button there called Edit, but it is not the one I want. I have specified what I want with the should('have.value','Log out') clause.
So - why does it insist on trying to use the wrong element & failing?
Update: I finally got this working.
This is the solution I went with in the end:
cy.get("input[type='button']").filter('.btn-primary').eq(1)
.should('have.value','Log out').then(($btn) => {
$btn.click()
})
can you try
cy.get('input').find("[value='Log out']").click()
or
cy.get("[value='Log out']").click()
Obviously you need your developers to add ids, but I know your situation.
You could also try if there is only one btn-primary
cy.get('.btn-primary').click()
This was the solution that worked for me:
cy.get("input[type='button']").filter('.btn-primary').eq(1)
.should('have.value','Log out').then(($btn) => {
$btn.click()
})
How about to set an unique testID for that button and get it as simple as it can be.
Something like:
data-test-id= "log-out-button" //put that in your button code
and then in Cypress:
cy.get('[data-test-id="log-out-button"]')
.click()
even though you can set a function to get those testID's more effectively:
Command.Cypress.add('getTestID', (testID) => {
cy.get(`[data-test-id="${testId}"]`)
})
and now everything you do for getting that button (or every element with testID is: cy.getTestID('log-out-button')

nightwatch select current element's inner div

i'm new to nightwatch and was wondering if there's any good way to select the inner element of a current element and then get the text? Assuming i have the following..and i'm trying to retrieve the text inside (a) tags of each (li).
so i would like to get 'text to retrieve' and 'text to retrieve 2'.
...
<div class="mywrapperhere">
<ul>
<li>
<a>.....
<div>text to retrieve</div>
</a>
</li>
<li>
<a>.....
<div>text to retrieve 2</div>
</a>
</li>
<li>...
...
</div>
I'm thinking along these lines..
module.exports = {
'Demo test 1' : function (browser) {
....
//some sort of selector then gets from the anchor list
...'.mywrapperhere li a') : {
..
//for each element of the anchor..
{
//is there anyway to get it through something like
element.('div').innerHTML eg..
//or am i forced to use browser.execute( ...getElementsByTag method
//to achieve this?
}
}
browser.end();
}
};
Looking at the nightwatch api, i couldn't find anything allows me to do that. I'm particularly looking at the 'Element State' examples that doesn't seem to have a way for me to select the current element state's child element :
http://nightwatchjs.org/api/elementIdAttribute.html
The reason why i had to loop through the anchor tag level is because i'll need to retrieve a few more data besides the one from div tag, thanks!
You can use elementIdElement and elementIdText to get text from a child element. First you can get all the li elements by using .elements(). Then you use elementIdElement to get a child element. Then you can use elementIdText to get the text of this child element. Here is an example that will allow you to get the text of both list items in your snippet and log the values to the console.
browser.elements('css selector', 'li', function(listItems) {
listItems.value.forEach(function(listItem) {
browser.elementIdElement(listItem.ELEMENT, 'css selector', 'a', function(anchor) {
browser.elementIdText(anchor.ELEMENT, function(text) {
console.log(text.value);
});
});
}, browser); //have to pass in browser for scoping
});

Getting farthest (oldest) ancestor by class name with Prototype

I've wasted way too much time on this today. Let's assume I have something like this:
<div id="p1" class="hit">
<div id="p2" class="no-hit">
<div id="p3" class="hit">
<div id="p4" class="no-hit">
<div id="p5" class="hit">
el
</div></div></div></div></div>
So my element is being passed to a function, and if it's a descendant of a .hit element, I want el to equal the oldest ancestor with the hit class (in this case #p1).
In jQuery, it would be as simple as using el.parents(".hit") and pointing to the last one, but I'm working on legacy code and have to use prototype. The following code works on jsfiddle, but causes an illegal token error on production:
if(item.up('.hit') != undefined){
while(item.up('.hit') != undefined){
item = item.up('.hit');
}
}
Please prototype, tell me you have an easy way to accomplish this.
Prototype and jQuery are similar in this regard (at least, in my interpretation of the documentation). You should be able to use the .up method in Prototype as well.
The code you provided should work with Prototype as well. You can see an example here.
If not, you could always try the .previous method.
if(typeof item.up('.hit') != 'undefined') {
while(typeof item.up('.hit') != 'undefined') {
item = item.up('.hit');
}
}

Resources