How to test the text of the second element in cypress? - 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.

Related

Getting the number of a specific elements inside a div on Cypress

How to get the number of divs that contain 'userid' from the div with id="chatListHolder"
https://i.stack.imgur.com/QzzLh.png
If a command that yields an element finds more than one element, it will yield all of them. So, we can then check the yielded array of element's length.
cy.get('#chatListHolder')
.should('have.length', 1); // we can change that 1 to whatever number we'd like
// or if we need to do something with that
cy.get('#chatListHolder')
.its('length').should('be.gt', 1);
// or another possibility
cy.get('#chatListHolder')
.its('length')
.then((length) => {
// whatever needs to be done with the length variable
});

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}, () => {
...
})

JQuery aproach to count elements before and after: always same value

I have a table with columns and below, an icon upon clicking, I can modify the table columns.
Now I want to count the columns before and after. I have a solution which works, where I call the the following before and after and then use the wrapped alias (via parseInt) to compare:
cy.get('body').then(($el) => {
// eslint-disable-next-line #typescript-eslint/no-unsafe-assignment
const countColsNr = $el.find('th[e2e-tag-header]').length;
cy.wrap(**to be named**).as(`${s}`);
});
This counts the actual columns and saves it in the variable to be named.
However, if I use a JQuery approach, it always gets the same column number, which is at the beginning of the test:
const beforetColsNr = Cypress.$('th[e2e-tag-header]').length;
log(beforetColsNr.toString());
... column handling code
... also tried with wait inbetween steps for debug
const afterColsNr = Cypress.$('th[e2e-tag-header]').length;
log(afterColsNr.toString());
Before number and after, are the same! When I look at the state of the browser (screenshot), I can see different columns amount at time of counting in after. This JQ-approach does not count properly the second time or uses the first value.
Is this something which is expected? Or is something I have to investigate?
cypress is asyncrhonous, so beforetColsNr and aftterColsNr are initialized at the same moment.
In the "cypress" mode in your first code block it works because of the usage of the .then().

Cypress:Finding parent element

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();

xpath: check if current elements position is second in order

Background:
I have an XML document with the following structure:
<body>
<section>content</section>
<section>content</section>
<section>content</section>
<section>content</section>
</body>
Using xpath I want to check if a <section> element is the second element and if so apply some function.
Question:
How do I check if a <section> element is the second element in the body element?
../section[position()=2]
If you want to know if the second element in the body is named section then you can do this:
local-name(/body/child::element()[2]) eq "section"
That will return either true or false.
However, you then asked how can you check this and if it is true, then apply some function. In XPath you cannot author your own functions you can only do that in XQuery or XSLT. So let me for a moment assume you are wishing to call a different XPath function on the value of the second element if it is a section. Here is an example of applying the lower-case function:
if(local-name(/body/child::element()[2]) eq "section")then
lower-case(/body/child::element()[2])
else()
However, this can simplified as lower-case and many other functions take a value with a minimum cardinality of zero. This means that you can just apply the function to a path expression, and if the path did not match anything then the function typically returns an empty sequence, in the same way as a path that did not match will. So, this is semantically equivalent to the above:
lower-case(/body/child::element()[2][local-name(.) eq "section"])
If you are in XQuery or XSLT and are writing your own functions, I would encourage you to write functions that will accept a minimum cardinality of zero, just like lower-case does. By doing this you can chain functions together, and if there is no input data (i.e. from a path expression that does not match anything), these is no output data. This leads to a very nice functional programming style.
Question: How do I check if a element is the second element
in the body element?
Using C#, you can utilize theXPathNodeIterator class in order to traverse the nodes data, and use its CurrentPosition property to investigate the current node position:
XPathNodeIterator.CurrentPosition
Example:
const string xmlStr = #"<body>
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
</body>";
using (var stream = new StringReader(xmlStr))
{
var document = new XPathDocument(stream);
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator nodes = navigator.Select("/body/section");
if (nodes.MoveNext())
{
XPathNavigator nodesNavigator = nodes.Current;
XPathNodeIterator nodesText =
nodesNavigator.SelectDescendants(XPathNodeType.Text, false);
while (nodesText.MoveNext())
{
if (nodesText.CurrentPosition == 2)
{
//DO SOMETHING WITH THE VALUE AT THIS POSITION
var currentValue = nodesText.Current.Value;
}
}
}
}

Resources