I am struggling with something at work. I am a newbie, so excuse me if I ask something easy. I coulnd't find it personally on the internet, so I hope you can provide me from (easily understandable) information.
I am building an automated test. I am using Cypress.
At my work we have the following situation;
1) There is 1 file. We want to copy this. So we have to count the initial state first (1 file)
2) We will copy this file
3) We now have 2 files. We want to count that there are indeed 2 files
I have the following code for this;
// count initialstate (1 file) =
let InitialStateCopy =
cy.getScoped('catalog-> item:case_type:link').contains('filename').should('have.length', 1 )
// press copy
// copy the file, execute actions here
// check if file is copied correctly (2 files)
let NewState =
cy.getScoped('catalog-> item:case_type:link').contains('filename').should('have.length', 2 )
I get the message
CypressError: cy.contains() cannot be passed a length option because it will only ever return 1 element.
And I see that Cypress only finds 1 element.
Does somebody know how I can count how many objects there are? Which code should I use for this ? Basically, I just want to know how I can count elements on a page.
cy.contains('blah') will automatically assert that the element containing blah exists:
.contains() will automatically retry itself until the element(s) exist in the DOM.
So you don't need to do a .should('have.length', 1) to assert this. The .contains itself performs an implicit assertion.
Cypress is trying to warn you that .contains only returns 1 element, so you might be doing something wrong if you're trying to assert on the length of it. In this case, you're trying to assert that length is 2, which is impossible.
I don't know what your .getScoped is, but this just uses regular CSS syntax. To do what you're trying to do, try this JQuery selector, which works because Cypress uses JQuery's selector engine:
cy.get(".catalog .item:contains('filename')").should('have.length', 2)
I want to be able to click on a check box and test that an element is no longer in the DOM in Cypress. Can someone suggest how you do it?
// This is the Test when the checkbox is clicked and the element is there
cy.get('[type="checkbox"]').click();
cy.get('.check-box-sub-text').contains('Some text in this div.')
I want to do the opposite of the test above.
So when I click it again the div with the class check-box-sub-text should not be in the DOM.
Well this seems to work, so it tells me I have some more to learn about .should()
cy.get('.check-box-sub-text').should('not.exist');
You can also search for a text which is not supposed to exist:
cy.contains('test_invite_member#gmail.com').should('not.exist')
Here you have the result in Cypress: 0 matched elements
Reference: Docs - Assertions, Existence
Use .should('not.exist') to assert that an element does not exist in the DOM.
Do not use not.visible assertion. It would falsely pass in < 6.0, but properly fail now:
// for element that was removed from the DOM
// assertions below pass in < 6.0, but properly fail in 6.0+
.should('not.be.visible')
.should('not.contain', 'Text')
Migration Docs here: Migrating-to-Cypress-6-0
Cypress 6.x+ Migration
According to cypress docs on Existence
The very popular attempt which is a bit naive will work until it doesn't and then you'll have to rewrite it again... and again...
// retry until loading spinner no longer exists
cy.get('#loading').should('not.exist')
This doesn't really work for the title problem which is what most people will be looking for.
This works for the case that it is being removed. but in the case that you want it to never exist... It will retry until it goes away.
However, if you want to test that the element never exists in our case.
Yes lol. This is what you really want unless you want to just have your headache again another day.
// Goes through all the like elements, and says this object doesn't exist ever
cy.get(`img[src]`)
.then(($imageSection) => {
$imageSection.map((x, i) => { expect($imageSection[x].getAttribute('src')).to.not.equal(`${Cypress.config().baseUrl}/assets/images/imageName.jpg`) });
})
cy.get('[data-e2e="create-entity-field-relation-contact-name"]').should('not.exist');
might lead to some false results, as some error messages get hidden. It might be better to use
.should('not.visible');
in that case.
Here's what worked for me:
cy.get('[data-cy=parent]').should('not.have.descendants', 'img')
I check that some <div data-cy="parent"> has no images inside.
Regarding original question, you can set data-cy="something, i.e. child" attribute on inner nodes and use this assertion:
cy.get('[data-cy=parent]').should('not.have.descendants', '[data-cy=child]')
You can use get and contains together to differentiate HTML elements as well.
<button type='button'>Text 1</button>
<button type='button'>Text 2</button>
Let's say you have 2 buttons with different texts and you want to check if the first button doesn't exist then you can use;
cy.get('button').contains('Text 1').should('not.exist')
Could be done also using jQuery mode in cypress:
assert(Cypress.$('.check-box-sub-text').length==0)
I closed an element and checked should('not.exist') but the assertion failed as it existed in the DOM. It just that it is not visible anymore.
In such cases, should('not.visible') worked for me. I have just started using cypress. A lot to learn.
No try-catch flow in cypress
In java-selenium, we usually add the NoSuchElementException and do our cases. if UI is not displaying element for some Role based access cases.
You can also query for the matched elements inside the body or inside the element's parent container, and then do some assertions on its length:
cy.get("body").find(".check-box-sub-text").should("have.length", 0);
In case anyone comes across this, I was having the issue that neither .should('not.exist') nor .should('have.length', 0) worked - even worse: If the element I was querying was actually there right from the get-go, both asserts still returned true.
In my case this lead to the very strange situation that these three assertions, executed right after each other, were true, even though asserts 1+2 and 3 contradict each other:
cy.get('[data-cy="foobar"]').should('not.exist')
cy.get('[data-cy="foobar"]').should('have.length', 0)
cy.get('[data-cy="foobar"]').should('have.text', 'Foobar')
After extensive testing, I found out that this was simply a race condition problem. I was waiting on a backend call to finish before running the above 3 lines. Like so:
cy.wait('#someBackendCall')
cy.get('[data-cy="foobar"]').should('not.exist')
However once the backend called finished Cypress immediately ran the first two assertions and both were still true, because the DOM hadn't yet caught up rerendering based on the backend-data.
I added an explicit wait on an element that I knew was gonna be there in any case, so my code now looks something like this:
cy.wait('#someBackendCall')
cy.get('[data-cy="some-element"]').should('contain', 'I am always here after loading')
cy.get('[data-cy="foobar"]').should('not.exist')
You can also use below code
expect(opportunitynametext.include("Addon")).to.be.false
or
should('be.not.be.visible')
or
should('have.attr','minlength','2')
Voted element is correct but I highly recommend not to using anti-pattern saving you from a lot of headaches. Why? Yes, because;
Your application may use dynamic classes or ID's that change
Your selectors break from development changes to CSS styles or JS behavior
Luckily, it is possible to avoid both of these problems.
Don't target elements based on CSS attributes such as: id, class, tag
Don't target elements that may change their textContent
Add data-* attributes to make it easier to target elements
Example:
<button id="main" name="submission" role="button" data-cy="submit">Submit</button>
And if you want to be more specific and want to indentify more than one selector, it is always good to use .shouldchainer.
Example:
cy.get("ul").should(($li) => {
expect($li).to.be.visible
expect($li).to.contain("[data-cy=attribute-name]")
expect($li).to.not.contain("text or another selector")
})
If there is no element, we can use simple line like:
cy.get('[type="checkbox"]').should('not.exist')
In my case, Cypress was so fast, that simple .should('not.be.visible') was passing the test and after that, loader appears and test failed.
I've manage to success with this:
cy.get('.loader__wrapper')
.should('be.visible')
cy.get('.loader__wrapper', { timeout: 10000 })
.should('not.be.visible')
Also nice to set the timeout on 10 seconds when your application loads more than 4s.
I would use :
cy.get('.check-box-sub-text').should('not.be.visible');
This is safer than
cy.get('.check-box-sub-text').should('not.exist');
( The element can be present in the DOM but not visible with display: none or opacity: 0 )
I've noticed that you when writing jasmine unit tests usually the format is:
expect($('#foo')).toHaveValue('#bar');
But recently I've discovered by accident that the following also works:
expect('#foo').toHaveValue('#bar');
Is this expected behaviour? This seems like a better way to write my expects but I have never seen this notation before and I want to be sure I am not abusing something.
Could anyone confirm this is the way to go or direct me to any documentation of this?
(I am using the jasmine jquery library)
I've played around a bit with that. Looks like it really does work, having some peculiarities, though.
I've tried things like:
expect('.search-form').toBeInDOM();
expect('.search-form').toEqual('div');
expect('.search-form').toContainElement('.search-form__footer');
the first one passes and truely fails when changing to
.not.toBeInDOM();
the third one looks same -- it truely fails is changing to some
bad selector for toContainElement
the second one is a problem because of ambiguity: '.search-form' can be treated both as string and a selector.
Had a very brief look into source code, it looks likes matchers really do resolve expectation actual as a selector (example from):
toBeInDOM: function () {
return {
compare: function (actual) {
return { pass: $.contains(document.documentElement, $(actual)[0]) }
}
}
},
Although I could not find any sign of such abilities in their docs, too. Still, source code is source code ))) and it says what it says. And now it says it will treat the actual for expect as a selector.
In my page there is 2 ng-repeat, 'widget in widgets', 'widget in widgetsOnPage'. When I try to locate a elements by element.all(by.repeater('widget in widgets')); it finds elements from both of the repeats.
I try also, on the protractor example test ("\node_modules\protractor\example\example_spec.js") to change the 'todo in todos' repeater to:
todoList = element.all(by.repeater('to'));
And the test pass.
How can I locate the repeats that equals exactly to the string?
That behavior is a defect on protractor or a feature?
Thanks.
by.repeater locator is based on findRepeaterElement() function. According to it's implementation, it is searching for a passed in the repeater substring inside the ng-repeat attribute value, see this indexOf call inside the loop:
for (var i = 0; i < repeatElems.length; ++i) {
if (repeatElems[i].getAttribute(attr).indexOf(repeater) != -1) {
rows.push(repeatElems[i]);
}
}
Since widget in widgets is a substring of widget in widgetsOnPage, there is a match.
Since the behavior is a bit surprising, I'd submit an issue to the protractor github issue tracker.
You could always try for a css selector, which could include the extra text:
$$('[ng-repeat="widget in widgets"]');
$$('[ng-repeat="widget in widgetsOnPage"]');
This would restrict the output to just the one you want.
In this scenario, I would probably just make my own locator! See protractor's documentation
I would like to count the number of, let's say, div elements with 'nice' class. I've got the selector div.nice, but don't know which casperjs class/method to use.
There is a tester.assertElementCount method in fact, but is there anything that simply returns the number of elements?
Just
document.querySelectorAll("div.nice").length
If you can use jquery its fairly simple:
var count = $('div.classname').length;
Found an SO Post that seems to explain using jquery with casperjs, I have no experience with casperjs so I can't help much there.
One of the examples for CasperJS 1.1-beta3 involves checking the number of Google search results for CasperJS. It references __utils__.findAll(), which takes a selector as its argument. It allows you to check the number of items returned using the length property available to any JS object:
test.assertEval(function() {
return __utils__.findAll("h3.r").length >= 10;
}, "google search for \"casperjs\" retrieves 10 or more results");
I've never tried it, but it seems like this utility function can be used outside a conditional, and it will allow you to report the number of elements without using jQuery, as a previous answer recommended.
Casper provides getElementsInfo, you can use the attribute length to get the number of elements.
e.g.
casper.getElementsInfo('myElement').length
you also can use assertElementCount to assert the count of the elment
test.assertElementCount("div.nice", 1)
I did not find the answers above to be helpful to my cause.
I think the goal was to count the number of elements without having to evaluate the js code in the page context, which could be frustrating overtime and have conflicting variables and functions.
Instead, it would be nice to leverage the casper automation context. This can be done with a combination of ".exists()" and the css psuedo-selector ":nth-of-type(i)"
The code below does this...
var counter = 1; //set to one, for css selector setup
casper.then(function() { //wait your turn
//loop through our element
while(casper.exists( 'div span:nth-of-type(' + counter + ')' )) {
counter++; //count the results
}
});
You could make this a function and pass in all the arguments, or just copy and paste it as a step.
Best part, you could follow it with a repeat statement for a pretty cool loop.
casper.then(function(){
this.repeat(counter, function() {
console.log("Another one - item #" + counter);
});
});