Cypress:Finding parent element - cypress

I got a tree of elements and each element got a toggle icon to expand it -My intention is to click on the toggle icon corresponding to the element have a text for ex "TIME PERIODS"
Currently i write my code like below , Is there a better way to do this?
Please see the screenshot for my element structure.
cy.get('.tree-node',{ timeout: 60000 }).contains('TIME PERIODS',{force: true}).parent().parent().find('.tree-node-collapsed').click()

each() method is available in Cypress.io. Using which we can travell through tree of elements and can filter using text. Please follow below code approach:
Code
cy
.get('.tree-node')
.each(($el, index, $list) => {
// $el is a wrapped jQuery element
$el.get('.tree-item').contains('TIME PERIODS').siblings('.tree-node-
collapsed').click();
});

I have fixed issues -working code given below
cy.get('.tree-node').each(($el, index, $list) => {
// $el is a wrapped jQuery element
cy.wrap($el).get('.tree-item').contains('TIME PERIODS').parent().siblings('.tree-node-collapsed').click();

We can do like shown below also with out using .each
cy.get('.tree-node').get('.tree-item').contains('Header').parent().siblings('.tree-node-collapsed').click();

Related

Cypress assert label and checkbox child elements

Issue I'm having is I have a list of items (all with the same selector)and I want to loop through these items and assert a text label on one child and a checkbox on another child of the same parent element match what I expect. I can easily solve this solution in Selenium, but struggling to find the answer in Cypress.
I found the answer to this myself, essentially using filters, which I hadn't used before, to find the parent with the child text I wanted, before checking the checkbox of another child. Ignore the If as it's not necessary for the solution
if (parentSelector) {
cy.get(parentSelector).filter((_, element) => {
return element.querySelector('h2').textContent === labelValue
}).then( element => {
cy.wrap(element).find(selector).should('not.be.checked')
})

Click on an element which has a specific attribute value in Cypress

I am writing this code for an element that has an attribute value "123". Since there are many products on that page with the wishlist button. But I want to click on the wishlist button for this specific product id(123)
but I recieve an error saying
cy.click() can only be called on a single element.
Your subject contained 53 elements.
Pass { multiple: true } if you want to serially click each element.
Can someone help here?
cy.xpath('//div[#id="filterProducts"]//div[#data-wish-list-entry-number]').then(thisProduct => {
if (
(cy.wrap(thisProduct)
.invoke('attr', 'data-wish-list-entry-number')
.should('eq', '123') ))
{
cy.wrap(thisProduct)
.click()
}
You don't need the if(), just add the attribute value 123 in the selector.
Same way as you have in [#id="filterProducts"]
with XPath
cy.xpath('//div[#id="filterProducts"]//div[#data-wish-list-entry-number="123"]')
.click()
with Cypress get
cy.get('div[id="filterProducts"] div[data-wish-list-entry-number="123"]')
.click()
also
cy.get('div#filterProducts div[data-wish-list-entry-number="123"]')
.click()
If it is the first of the list you can use first:
cy.get("value").first().click();
If is not the first but you know the element number use eq:
cy.get("value").eq(40).click();

How to test the text of the second element in cypress?

I can test the first element of the Dom element but I don't know how to get the second element?
it('should display highlight', () => {
const highlights = cy.get(`.${pageClass} .page_highlight`);
highlights.should('have.length', 2);
highlights.first().should('contain.text', translations.highlight);
});
There are two options for your case.
Since the total number of elements is just two in your case, you can use something called last. You can read more here.
If the number of elements is dynamic, you can use something called eq and pass the order of element as an index. You can read more here.

How to select elements with same ID but in different shadow DOMs

So I'm working at a co. as a summer intern and have been tasked with writing tests for their application in cypress.
The application extensively uses shadow DOMs and nested shadow DOMs even. I used the includeShadowDom property true to traverse more easily. But I am facing an issue.
I need to type in 2 input boxes having the same ID and same class but they are in separate shadows. Is there a way I can distinguish between them i.e First occurrence of element with id= and nth occurrence of element with id=?
I can't share any code because it goes against company policy
Assuming you have added includeShadowDom: true in your cypress config file then you can use the eq method to get the respective elements.
E.g. eq(0) for first occurrence of the element, eq(1) for the second and so on.
So your code should look like this:
cy.get('input').eq(0).type('some text')
First possible solution is to select every input with class = something and loop over each.
let words = ['First input', 'second input']
cy.get(`input[class="something"]) // this returns x number of Inputs
.each( ($el, index) => {
cy.get($el)
.type(words[index])
})
Second possible solution is to target the parent element incasing the single input.
cy.get('table') //I don't know what is incasing your inputs but lets assume its a table
.within( () => {
cy.get(`input[class="something"`] //trying to get this to return 1 element
.type('words')
})
Without seeing your HTML markup I can't offer up a more exact solutions. Hope this helps. Look up parent() and parentsUntil() cypress commands if you try the second option.
With inputs there's usually some text that allows the user to distinguish them.
Try targeting the input label or placeholder text, finding the input with "Traversal" commands.
<div>
<label>User name</label>
<input type="text" placeholder="Enter user name" />
<div>
Some basic approaches:
cy.contains('label', 'User name')
.next() // move to next element in the DOM
.type('something')
cy.contains('div', 'User name') // go to common parent of label and input
.find('input') // gives just the input inside parent
.type('something')
cy.get('input[placeholder="Enter user name"]') // use unique placeholder attribute
.type('something')
With shadow DOM be aware you can configure it in the test header
it('searches inside all shadow dom roots', {includeShadowDom: true}, () => {
...
})

Finding xpath for an element loaded by Ajax-json response using class and text

I have an element like
<td class="google-visualization-table-th gradient google-visualization-table-sorthdr">
Project Name
<span class="google-visualization-table-sortind">▼</span>
</td>
I tried
driver.findElement(By.xpath("//td[contains(#class, 'google-visualization-table-th') and normalize-space(text()) = 'Project Name']")
But its not working. Basically its code for Column header and I need to recognize each column header and print if the heading exist or not.
We do not know which version of XPath you are using, but depending on the exact version, text() means different things.
I suspect that the text content of span(the weird character ▼) is also part of td/text(). This is because text() does not mean:
Return the rext nodes of the context node
In this case it means:
Return the text nodes of the context node and the text nodes of all its decendants.
Use contains() also in the second half of the predicate:
//td[contains(#class, 'google-visualization-table-th') and contains(.,'Project Name')]
Its resolved now, element was not getting identified because they were getting loaded in an iframe. I used the below code o switch to iframe and then did usual operations to track the elements.
WebDriverWait wait = new WebDriverWait(driver, 200);
By by = By.id("iframe id");
try {
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(by));
Thanks everyone for the help.

Resources