I want to use assertion for this checkbox. It depends on duration. If it's checked duration = forever, if not = a month.
cy.wrap(cy.get('span.ant-checkbox').should('have.class','ant-checkbox-checked')).then((a) => {
if a == true {
cy.log('Forever')
}
})
A few thoughts:
You don't need to cy.wrap() your entire statement. cy.wrap() would primarily be used to wrap a JQuery yielded from cy.get() or a similar command, and insert it back into the Cypress command chain.
Your assertion that the element has a certain class will fail and stop your test before even getting to the .then() part of the command if the element does not have the ant-checkbox-checked class.
Instead, if we get the element, we can use JQuery functions (in this case, .hasClass())to determine if it has the class we want.
cy.get('span.ant-checkbox').then(($el) => {
// cy.get yields a JQuery<HTMLElement>
if ($el.hasClass('ant-checkbox-checked')) {
cy.log('Forever');
} else {
cy.log('A month');
}
});
Related
I just want to ask how to properly conditional testing? I have this code here
cy.get('[data-slug="add-to-any"] > .plugin-title > strong').then(($slug) => {
if (expect($slug).not.to.exist){
//It will passed
}else if (expect($slug).to.exist){
cy.get('#deactivate-add-to-any').should('not.exist')
}
I assert the element to not.to.exist, but it gives me this error
Expected to find element: [data-slug="add-to-any"] > .plugin-title > strong, but never found it.
I am really lost what assertions I need to use.
The ideal way (if it works in your scenario) is to shift the last selector inside the .then()
cy.get('[data-slug="add-to-any"] > .plugin-title')
.then(($pluginTitle) => {
const $slug = $pluginTitle.find('strong'); // this finds with jQuery
// which won't fail the test
// if not found
if ($slug.length === 0) { // not found
} else {
cy.get('#deactivate-add-to-any').should('not.exist')
}
})
It's not 100% fool-proof, if $slug is loaded asynchronously (say via fetch) it won't be there immediately and the test might pass when in fact the $slug turns up 100 ms after the test runs.
You need to understand the way the app works to really be sure.
Cypress docs show this pattern, using <body> as the "stable" element (always present after page load).
cy.get('body').then($body => {
const slug = $body.find('[data-slug="add-to-any"] > .plugin-title > strong')
if ($slug.length) {
...
It's less than ideal because the page might have <body> but still be fetching elements inside it.
Best practice IMO is to try the immediate parent element of the conditional one. If that is also conditional, move up the element tree until you find an element that is stable/present at that point in you test.
Or add a guard condition that waits for page fetch to complete. A cy.intercept() is useful for that, or even just this
cy.get('[data-slug="add-to-any"] > .plugin-title')
.should('be.visible') // retries until .plugin-title is showing
.then(($pluginTitle) => {
const $slug = $pluginTitle.find('strong')
if ($slug.length === 0) {
...
Simple example
cy.get("body").then($body => {
if ($body.find('[data-slug="add-to-any"] > .plugin-title').length > 0) {
cy.get('[data-slug="add-to-any"] > .plugin-title').then($title => {
if ($title.is(':visible')){
//you get here only if it EXISTS and is VISIBLE
}
});
} else {
//you get here if the it DOESN'T EXIST
cy.get('#deactivate-add-to-any').should('not.exist')
}
});
In selenium we can handle exception. If any exception occur in any testcase it will then jump onto next testcase we can did in selenium. But i an confused that how can we did this in Cypress. Taking below example
it('Test Case 1', function () {
cy.visit('https://habitica.com/login')
cy.get('form').find('input[id="usernameInput"]').click().type("username")
cy.get('form').find('input[id="passwordInput"]').click().type("password")
**cy.get('.btn-info').click()**
cy.get('.modal-dialog').find('button[class="btn btn-warning"]').click()
cy.get('.start-day').find('button').click({force:true})
})
it('Test Case 2', function () {
cy.visit('https://habitica.com/login')
cy.get('form').find('input[id="usernameInput"]').click().type("username")
cy.get('form').find('input[id="passwordInput"]').click().type("password")
cy.get('.btn-info').click()
cy.get('.modal-dialog').find('button[class="btn btn-warning"]').click()
cy.get('.start-day').find('button').click({force:true})
})
Lets say browser unable to find click element (Highlighted with bold) in testcase 1 then it will jump onto Testcase 2.
How can we do it in Cypress?
Please help me on this
Exceptions like Unable to fine element or similar others.
Other than this example how can we handle exceptions or error.
Although Cypress team is saying that we need to avoid conditional test as much as possible (and maybe a need to change your approach). However, in you case, you can include a conditional test:
cy.get('.btn-info').then((body) => {
if (body.length > 0) { // continues if the element exists
cy.get('.btn-info').click();
cy.get('.modal-dialog').find('button[class="btn btn-warning"]').click()
cy.get('.start-day').find('button').click({force:true})
} // if the above condition is not met, then it skips this the commands and moves to the next test
});
Thanks alot for your response. Please have a look at this. I have used your code. "'.btn-info'" does not exist so exception occur which is fine. but problem is it do not move onto else statement. I mean If statement gets failed then it must execute else but it do not. Why it is doing so?
it('First Test Case', function() {
cy.visit('http://pb.folio3.com:9000/admin/#/login');
cy.get('.btn-info').then((body) => { // **THIS ELEMENT NOT EXIST**
if (body.length > 0) { // continues if the element exists
cy.get('.btn-info').click();
cy.get('.modal-dialog').find('button[class="btn btn-warning"]').click()
cy.get('.start-day').find('button').click({force:true})
}
else
{
**cy.visit('https://www.facebook.com/');**
}
});
it('Second Test Case', function() {
cy.visit('https://www.google.com/');
})
I'm using Cypress for my automated tests. I'm trying to find a product on a page and click on it. If the product not displayed on the page, go to the next one until it is found.
I've been trying a lot of things already: while loop, each loop, simple cy.get but none of them work. Can anyone help me to solve this?
You'll need a recursive command, implementation of which will depend on your specific scenario. There's no one-size-fits-all solution, but generally it will look something like this:
function findElem ( targetSelector ) {
// first, we need to query a container (could be table, or a generic item
// container). The important thing is, this container must exist on every
// page you'll traverse.
cy.get('.someContainer').then( $container => {
// synchronously find the target element, however you want. In this
// example I use an attribute selector, but you can do whatever you
// want.
if ( $container.find(targetSelector).length ) {
return true;
} else {
return false;
}
}).then( found => {
if ( found ) {
return cy.log(`found elem "${targetSelector}"`);
} else {
// synchronously check if there's a next page/table
if ( Cypress.$('.nextPageButton').length ) {
// when know that there is a next page, click it using cypress
cy.get('.nextPageButton').click();
// here, assert that next page/table is loaded, possibly by
// asserting that current page/table is removed from DOM
// then, recurse
return findElem(targetSelector);
} else {
throw new Error(`Couldn't find elem "${targetSelector}" on any page`);
}
}
});
}
it('test', () => {
findElem(`[data-id="42"]`);
});
The crux of the solution is using a combination of commands to query a container, and synchronous inspection (using jQuery or whatever) to find the actual element. Learn more at Conditional Testing.
For a concrete implementation, you can refer to an older answer I gave to a similar question.
How do I get an element in Cypress without it asserting that it is present?
cy.get('.something')
Sometimes my element might not be there and I don't want it to fail the test.
Is there a different command I should be using?
You can use cy.$$('selector') to synchronously query for an element (jquery).
If you want this to happen after a cypress command, you'll need a .then:
cy.visit('/')
cy.get('element-one').then(() => {
const $el2 = cy.$$('element-two')
if ($el2.length) {
// do this
} else {
// do that
}
})
You might want to check this section of the docs in Cypress
https://docs.cypress.io/guides/core-concepts/conditional-testing.html#Element-existence
I need to check if the pop up exists, if it does then I need to check if its displayed then perform certain action on it.
I have implemented the below. I was wanting to know if there is any better way of achieving this.
licenseUpdate.isPresent().then(function (item) {
if (item == true) {
licenseUpdate.isDisplayed().then(function (res) {
if (res == true){
licenseUpdate.click();
};
});
}
});
If you are using page object (you should) you can write something like this:
clickLicenseUpdate() {
const licenseUpdate = $(licenseUpdateCssSelector);
return licenseUpdate.isPresent()
.then((isPresent) => {
if (!isPresent) { return false; }
return licenseUpdate.isDisplayed();
})
.then((isDisplayed) => {
if (!isDisplayed) { return false; }
return licenseUpdate.click().then(() => true);
})
}
Note that if you are using and old JS version (you shouldn't) you need to replace arrow functions with traditional anonymous functions.
Some helpful links about Page Object Design Pattern:
PageObjects
Martin Fowler PageObject
Code explained (or at least, that is the plan):
Using $ to locate an element but you can use any strategy
supported by Protractor.
browser.findElement(by.className('license')) equivalent to
$('license'), browser.findElement(by.id('license')) equivalent to
$('#license'). Check Protractor documentation for more examples.
Once you a have found a web element that match your locator, you can
use isPresent method to determine whether the element is present on
the page. isPresent returns a promise that resolve to a boolean
value.
then always return a promise. You can return a primitive value from
onFulfilled callback and that value would be cast to a promise with
resolve with same value. That is what is done here: if (!isPresent) { return false; }; or you can return another promise
from onFulfilled callback and the promise returned by then will be resolved or rejected with same value of returned promise.
That is what is done here: return licenseUpdate.isDisplayed();. isDisplayed() also return a
promise that will resolve with whether this element is currently
visible on the page.
This can be a bit overwhelming if you are not
used to deal with promises. Check this out Promises/A+
Finally, if the element is present and is displayed, click the element with theclick method that, surprise, also return a
promise (WebDriverJS API is based on promises).
Note that if element is not present, isPresent is false in this
line if (!isPresent), returning false immediately bypass
licenseUpdate.isDisplayed() execution and resolve with a false value. In that
case isDisplayed value is false and again false is returned
immediately bypassing the licenseUpdate.click() execution.
Also note that clickLicenseUpdate return a promise that will
resolve to false if the element is not present or if is present but not
displayed. To keep clickLicenseUpdate returned value consistent, I recommend you to wait for licenseUpdate.click() and then return a boolean value as it is done here: return licenseUpdate.click().then(() => true); (using implicit return from arrow functions) because promise returned by click() resolve with a void value.
That is harmless but is considered a good practice maintain a consistent return value, always a boolean value, not sometime a boolean and others a void value.