How to get multiple elements with data-cy attributes - cypress

I have a table with all cells marked with the data-cy attribute as so: [data-cy="cell-${row}-${column}].
Individually I have no trouble to get each cell with the classic cy.get, for example cy.get("[data-cy=cell-2-17]").click(), but I try to test the click on multiple cells holding the control key but I couldn't achieve that.
In this answer it says to simply concat the selectors passed to cy.get but it didn't work for me, I tried with and without the " around the data-cy names:
cy.get('[data-cy="cell-2-17"][data-cy="cell-4-10"]').click({multiple: true, ctrlKey: true})`
Could you tell me how to get multiple elements using the data-cy attribute?

If you concatenate selectors (without space or + between), it means the element must have all those selectors.
There's not really a concise way to provide a list of required attributes.
Two things that help are wildcards and filters
const cellsWanted = ['cell-2-17', 'cell-4-10']
cy.get('[data-cy^="cell-"]') // wildcard anything that starts with "cell-"
.filter((index, el) => cellsWanted.some(cell => el.getAttribute('data-cy') === cell))
.click({multiple: true, ctrlKey: true})`
Multiple selectors with comma between
Just found an easier way using jquery multiple selectors
cy.get('[data-cy="cell-2-17"], [data-cy="cell-4-10"]')
.should('have.length', 2)
.click({multiple: true, ctrlKey: true})

Related

How to check either the headline or the content should contain "FIFA" keyword?

How do I write this test in Cypress?
enter image description here
I have to confirm that either the headline or paragraph should contain the same keyword.
It's better to have JQuery elements in hand before the assertion so that you can use JQuery methods on them. cy.get() acts just like $(...) in JQuery, it will be enough to have the elements. (more here)
Once u have the elements, i.e. $el1 and $el2 below, then you can get their text via .text() method (more here) and then you can write your assertion.
Instead of a separate assertion, below I used a single one and checked if either of them includes the desired text by using || operator.
cy.get('first-el').then($el1 => {
cy.get('second-el').then($el2 => {
const inEl1 = $el1.text().includes('FIFA');
const inEl2 = $el2.text().includes('FIFA');
expect(inEl1 || inEl2).to.be.true;
});
});

Cypress: testing that nothing more than asserted exists

Is it possible to test that nothing more than asserted exists? E.g. I have elements A, B and C. I'm asserting that
cy.get('element-a').should('exist');
cy.get('element-b').should('exist');
cy.get('element-c').should('exist');
Then I remove A and assert that
cy.get('element-a').should('not.exist');
But is there any way to test that no other elements e.g. D or Q, of which I might not even be aware, exist on the page?
You can get every descendent element (child, grandchild, great-grandchild, etc) using .find('*').
For example,
cy.visit('http://example.com');
cy.get('body')
.find('*')
.then(descendents => {
return [...descendents].map(d => d.tagName)
})
.should('deep.eq', ['DIV', 'H1', 'P', 'P', 'A'])
Note the tagNames are allcaps.
But it seems doubtful that you have ONLY tags such as element-a in your HTML. You can apply a filter, the exact code depends on what your selectors are (tagNames, classes, ids, data-cy attributes).
You may be better off using cypress snapshot or similar package listed on that page.

How to query data-attribute for a whitespace-separated value in Cypress component tests?

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"])'))

Cypress - counting number of elements in an array that contain a specific string

Attempting to confirm that of all the schema in the head of a page exactly 3 of them should have a specific string within them. These schemas have no tags or sub classes to differentiate themselves from each other, only the text within them. I can confirm that the text exists within any of the schema:
cy.get('head > script[type="application/ld+json"]').should('contain', '"#type":"Product"')
But what I need is to confirm that that string exists 3 times, something like this:
cy.get('head > script[type="application/ld+json"]').contains('"#type":"Product"').should('have.length', 3)
And I can't seem to find a way to get this to work since .filter, .find, .contains, etc don't filter down the way I need them to. Any suggestions? At this point it seems like I either need to import a custom library or get someone to add ids to these specific schema. Thanks!
The first thing to note is that .contains() always yields a single result, even when many element match.
It's not very explicit in the docs, but this is what it says
Yields
.contains() yields the new DOM element it found.
If you run
cy.get('head > script[type="application/ld+json"]')
.contains('"#type":"Product"')
.then(console.log) // logs an object with length: 1
and open up the object logged in devtools you'll see length: 1, but if you remove the .contains('"#type":"Product"') the log will show a higher length.
You can avoid this by using the jQuery :contains() selector
cy.get('script[type="application/ld+json"]:contains("#type\": \"Product")')
.then(console.log) // logs an object with length: 3
.should('have.length', 3);
Note the inner parts of the search string have escape chars (\) for quote marks that are part of the search string.
If you want to avoid escape chars, use a bit of javascript inside a .then() to filter
cy.get('script[type="application/ld+json"]')
.then($els => $els.filter((index, el) => el.innerText.includes('"#type": "Product"')) )
.then(console.log) // logs an object with length: 3
.should('have.length', 3);

using an expression to show or hide rectangle based on a parameter value (SSRS)

Trying to show/hide a couple of rectangles in SSRS based on an expression which uses the value of a parameter in the report. See the screenshots for more details. When the '-Cover pages' label is picked I want it to display the rectangle but I consistently get the following errors. It can't seem to convert and read the parameter expression no matter what I do.
The expression I'm trying to use is:
=iif(Parameters!specparam.Value="-Cover Pages",true,false)
It looks like the label of your parameter is what you're looking for based on the image provided and your expression. Try to switch instead to:
=IIF(Parameters!specparam.Label="-Cover Pages",TRUE,FALSE)
(Note: I switched specparam.Value to specparam.Label.
Your comment is very close. Apply this expression to the Hidden property of the rectangle:
=IIF( Parameters!specparam.Label.Equals("-Cover Pages"), FALSE, TRUE )
You'll notice I have switched around the FALSE and TRUE as you don't want the rectangle to hide when the parameter matches.
Edit:
As you're dealing with a multivalue parameter, you can use a combination of Array.IndexOf and Split to check if your value is one of the selected parameters.
Apply this expression to the Hidden property of your rectangle:
=IIF( Array.IndexOf( Split( Parameters!specparam.Value, "," ), "-Cover Pages" ) > -1, FALSE, TRUE )

Resources