Cypress - How to Wait for an attribute value to be false in Cypress - cypress

I have a website which has everything in an iFrame. My scripts are failing because cypress is not able to wait for loading bar as cypress does not support iframes as of now. I want to write a custom command which wait until attributes 'ng-reflect-loading' value is changed to false.
I have tried with below code but its not working and halts cypress runner. Reference Thread 136
cy.get('iframe').iframeLoaded().its('document').getInDocument('.main >ng-component > :nth-child(1)').then(function($loading) {
while( $loading.attr('ng-reflect-loading')!='false')
{
cy.log('waiting')
}
})
Can anyone please help on this.

I don't have any insight of how iFrames work. But is 'ng-reflect-loading' eventually hidden?
In that case this check should work:
cy.get('.ng-reflect-loading')
.should('not.exist')
If it remains existing but the value should change you could either check on the first value not existing:
cy.get('.ng-reflect-loading')
.should('not.contain.attr', 'attr_name', 'first value')
Or if the value changes, you could check for the second value to be available:
cy.get('.ng-reflect-loading')
.should('contain.attr', 'attr_name', 'second value')

Related

Cypress: How to capture text from a selector on one page to use as text on another page

New cypress user here, I am aware that cypress does not handle variables like how testcafe and others do due to the asyn nature of it. Using the example given and what I could find I have this as an example:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed')
const txtneeded = this.text_needed
cy.log(txtneeded)
This looks at a given selector, takes what it finds and uses it as text and set it as a variable usable at any time in the test and outputs it to the log. The plan is to use that text in a search filter in another page to find the item it references.
The problem is that it fails with Cannot read properties of undefined (reading 'text_needed')
Is this because the content of the selector is not assigned to text properly, the outer html is <a data-v-78d50a00="" data-v-3d3629a7="" href="#">PO90944</a> The PO90944 is what I want to capture.
Your help would be appreciated!
You cannot save an alias and access it via this.* in the same execution context (callback) because it's a synchronous operation and your alias is not yet resolved at this time.
This is a correct way to go:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed').then(txtneeded => {
cy.log(txtneeded)
})
First, make sure to define it as traditional function, not as an arrow function as this context doesn't work as you'd expect there, more info here.
Next, typically in a single test you should use .then() callback to perform additional actions on elements, and use aliases when you need to share context between hooks or different tests, so please consider the following:
// using aliases together with this within the single test won't work
cy.get(<selector>).invoke('text').as('text_needed')
cy.get('#text_needed').should('contain', 'PO90944') // works fine
cy.log(this.text_needed) // undefined
// this will work as expected
cy.get(<selector>).invoke('text').then(($el) => {
cy.wrap($el).should('contain', 'PO90944'); // works fine
cy.log($el) // works fine
});
Setting alias in beforeEach hook for example, would let you access this.text_needed in your tests without problems.
Everything nicely explained here.
Edit based on comments:
it('Some test', function() {
cy.visit('www.example.com');
cy.get('h1').invoke('text').as('someVar');
});
it('Some other test', function() {
cy.visit('www.example.com');
cy.log('I expect "Example Domain" here: ' + this.someVar);
});
And here's the output from cypress runner:

Wait until element has disappeared in Cypress

please, tell me what methods to use to wait for a loading screen element to disappear? PS. I'm not using an API request.
I tried to use two methods, but it doesn't work properly:
1. cy.get('#loading', { timeout: 30000 }).should('not.be.visible');
I get the error: -- Timed out retrying after 30000ms: Expected to find element: #loading, but never found it.
2. Used plugin (cypress-wait-until) like so cy.waitUntil(() => {document.querySelector('#loading') === null};
This approach doesn't find the element at all.
If you are trying to retrieve an element that is not in the DOM, use not.exist instead:
cy.get('#loading').should('not.exist');
In cases where you do need to wait, you can try using cy.wait:
An example use case for this might be if Cypress has to route to your page first and you want to ensure the page loads before you start testing:
cy.wait(200);

How to validate Browser Error's message with cypress

For example if user dont fill this field and press "continue" button, this error message will pop up.
I wonder is there a way with Cypress that I check that error message was displayed?
Kind regards
You can make this assert : cy.get('input:invalid').should('have.length', 1)
See https://github.com/cypress-io/cypress-documentation/pull/1919/files how to assert the validation message
I know this is an older question but here is another solution.
cy.get(`[data-testid="XXXX"]`)
.invoke('prop', 'validationMessage')
.should((text: string) => {
expect(text).to.contain(YYYY);
});
Using the above code here is what happens:
You grab the input / textarea element using cy.get Note: it is recommended to use a data-testid or obtain the element by something less brittle so the test doesn't fail if the text changes etc.
Using the invoke method, you can check validationMessage against prop then then, obtain the inner text and use expect to check if it's valid. This is very handy if you use custom validation messages.

How to validate an element is gone using webdriverIO, Mocha and Chai

I'm working on some automated tests, using webdriverIO, Mocha and Chai. I keep running into the same problem when I want to verify if an element is deleted.
I'm working with a shoppingbasket where i delete an item and then verify that it is gone. It takes a while for the item to be gone though, so if I immediately go to the expect, the item is still there.
I have solved this by doing this:
browser.waitForExist(deletedProduct, 5000, true)
expect (boodschappenLijstPage.isProductPresent(SKU), 'the removed item was still there' ).to.equal(false)
The webdriverIO waitfor command waits for the product to dissapear, and after that the chai expect checks if it is gone.
The problem I have with this is that the expect will never fail. If the product is not properly deleted the waitfortimeout will throw an error before I get to the expect part, meaning that the expect part is only reached if the product is gone
I have read through the docs for chai, but I can't seem to find a way of doing this.
Can anyone show be a way of waiting for the product to be gone, without missing the expect (I don't want to use browser.pause for obvious reasons)
Refer this
webElement.waitForDisplayed({ reverse: true });
You can use try catch and basically wait for error. When element disappears from DOM selenium will throw NoSuchElementError and we can use it.
isNotPresent(element) {
try {
return !element.isVisible()
} catch (error) {
return true
}
}
// or wait for element to disappear from dom
waitForNotVisible(element) {
browser.waitUntil(() => {
try {
return !element.isVisible()
} catch (error) {
return true
}
})
}
If you're trying to validate that an element is gone, then using expect is the correct solution, but you should use the Webdriver-expect assertions instead of the chai expect assertions. While chai assertions check the state immediately, the WebdriverIO-expect assertions have the waitFor functionality built inside of it. Here is an example:
let deletedProduct = $(/* your xpath/CSS selector/*);
expect(deletedProduct).not.toBeDisplayed();
The difference between the assertion and using waitForDisplayed with the reverse flag is that some reporters, such as Allure, will report your test as broken when instead the test should be reported as failed. For example, when we ran tests and had the waitForDisplayed, all of our failing tests were marked in yellow. When we use expect, the tests are marked in red.
Here is the documentation for the WebdriverIO Expect matchers. They didn't document the .not method very clearly, but in my example you can see I added the .not before the toBeDisplayed call.
Again, this expect will wait for the timeout specified in the wdio.conf.js, just like the waitFors will.

Turn off FireFox driver refresh POST warning

I have inherited some GEB tests that are testing logging into a site (and various error cases/validation warnings).
The test runs through some validation failures and then it attempts to re-navigate to the same page (just to refresh the page/dom) and attempts a valid login. Using GEB's to() method, it detects that you are attempting to navigate to the page you are on, it just calls refresh - the problem here is that attempts to refresh the last POST request, and the driver displays the
"To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier"
message - as the test is not expecting this popup, it hangs and the tests timeout.
Is there a way to turn off these warnings in Firefox webdriver? or to auto-ignore/accept them via Selenium or GEB?
GEB Version: 0.9.2,
Selenium Version: 2.39.0
(Also tried with minor version above: 0.9.3 & 2.40.0)
Caveats:
I know about the POST/Re-direct/GET pattern - but am not at liberty to change the application code in this case
The warning message only causes an issue intermittently (maybe 1 in 5 times) - I have put this down to speed/race conditions whereby the test completes the next actions before the message appears - I know a possible solution is to update tests to wait for message to appear and then accept, but my question is, is there a global setting that can just avoid these being triggered/displayed?
That refresh() is there to work around an issue with IE driver which ignores calls to driver.get() with the same url as the current one.
Instead of monkey patching Browser class (which might bite you somewhere down the line or might not) I would change the url of your login page class. You might for example add an insignificant query string - I think that simply a ? at the end should suffice. The driver.currentUrl == newUrl condition will evaluate to false and you will not see that popup anymore.
If I understand you issue properly this might help. In Groovy you can modify a class on the fly.
We use Spock with Geb and I placed this in a Super class which all Spock Spec inherit from. Eg: QSpec extends GebSpec.
It is the original method slightly modified with the original code commented out so you know what has been changed. I use this technique in several required places to alter Geb behaviour.
static {
Browser.metaClass.go = { Map params, String url ->
def newUrl = calculateUri(url, params)
// if (driver.currentUrl == newUrl) {
// driver.navigate().refresh()
// } else {
// driver.get(newUrl)
// }
driver.get(newUrl)
if (!page) {
page(Page)
}
}
}

Resources