How do I wait for an element to disappear in Cypress? - automation

I'd like to preface this by saying that I really tried looking here and anywhere else for an answer but without a succes.
Here is the problem:
I'm trying to automate a test for a web application that is loading a bigger amount of data and therefore has to be loading for a while. I have to wait for the page to load to do the next step and I'm trying to figure how to wait for the loading gif to be complete so that my tests can continue. The gif is a basic spinning thingy.
I would like to avoid using implicit wait time (cy.wait()) that is really only the last resort if noone is able to solve this.
What I found o far are these two functions:
cy.waitFor - this seems to be used mostly in situations, where you are waiting for an element to apper - I've tried this in different scenarios and works perfcetly but I havent been able to apply it here.
cy.waitUntil - this seems to be the thing I'm looking for but there is one huge problem. This function seems to have a timeout and I haven't been able to change it any other way than by changing timeouts globally for all the functions. If I set the global timeout to some longer period (minute +), then it works exactly how I would want it to work but obviously I dont really want to have such a long timeout for everything.
The way I see it, there are two possible solutions to this problem>
to change/turn off the timeout for the waitUntil function.
2)Or to somehow make it work with waitFor, because there seems to be no implicit timeout there and it just kind of waits forever for something to happen.
here is the code snippet of the situation:
cy.get('#load-data-button').click() // this clicks the button that stars the loading proces
cy.waitUntil(() => cy.get('body > div > my-app > billing > div > div > div.text-center > img').should('not.be.visible',) ) // this is the function that waits until the loading gif is invisible
I would be eternaly grateful for a solution, because unfortunatelly no one at my company is really a Cypress expert so they are not able to help.

Could you try something like:
cy.get([loading-spinner-identifier]).should("not.be.visible", { timeout: 60000 });
cy.get([an element that should now be visible]).should("be.visible");
It's a bit rough and ready, but I've used it when waiting for spinners to finish up. This waits a minute to see the spinner isn't there and then checks to see that something I'm expecting is there. I'd had varying success with this, but it has helped in some situations.

You can indeed use cy.waitUntil(). As you can see in the documentation of that package (https://www.npmjs.com/package/cypress-wait-until#arguments), the timeout that the function has is just the default (5000 ms) of an argument you can change it. You can even change how often cypress checks the condition you want, so if you do something like:
cy.waitUntil(() => cy.get('body > div > my-app > billing > div > div > div.text-center > img').should('not.be.visible'), {
errorMsg: 'The loading time was too long even for this crazy thing!',
timeout: 300000,
interval: 5000
});
...it will try for 300 seconds (5 minutes) each 5 seconds (just an example with very long timeout).
Also, maybe you can consider to wait until some element is visible after that loading spinner, instead of checking if it dissapeared. If you want to specifically test it, is fine, but if some element appears or becomes interactable after the loading, it could happen that is still not in the state you want, for a fraction of a second, after the spinner is not visible. If that is the case, I would avoid the checking of the spinner dissapearing in first place, unless it adds value to your test, and I would just wait for that element to be in the state you want (for example wait until some input is not disabled, element is visible, text appeared somewhere...).

Add positive and negative assertion to make sure loading spinner is visible.
Default Time is 4s for assert statement.
You can increase defaultTime to wait for assertion to validate by adding configuration in cypress.json
{
...
"defaultCommandTimeout": 4000,
...
}
const waitForSpinner = () => {
// First, make sure the loading indicator shows up (positive assertion)
cy.get('[data-qa="qa-waiting-spinner"]').should('be.visible')
// Then Assert it goes away (negative assertion)
cy.get('[data-qa="qa-waiting-spinner"]').should('not.be.visible')
}

Related

How to change timeout in JDI Test Automation Framework

I need to change timeout for waiting particular webElements. For all of others default is pretty fine. Default timeout could be changed in settings:
timeout.wait.element=10
How to change timeout only for given elements?
For setting specific timeout on element you can use
textField.setWaitTimeout(10);
textField.input("TEXT");
But if you also has some waiting criteria and want to do something after it becomes true you can use
String text = textField.wait(w -> w.getText(), t -> t.equals("test"), 10);
or textField.wait(w -> w.getText().equals("test"), 10); if you just want to wait something
For setting specific implicit timeout on element you can use #WaitTimeout(sec)
#WaitTimeout(sec) — set sec seconds implicit wait for the element
or if you just want to wait until element is present in DOM:
someWebElement.waitFor(10).displayed();

In EarlGrey, what's the non-polling way to wait for an element to appear?

Currently I wait for an element to appear like this:
let populated = GREYCondition(name: "Wait for UICollectionView to populate", block: { _ in
var errorOrNil: NSError?
EarlGrey().selectElementWithMatcher(collectionViewMatcher)
.assertWithMatcher(grey_notNil(), error: &errorOrNil)
let success = (errorOrNil == nil)
return success
}).waitWithTimeout(20.0)
GREYAssertTrue(populated, reason: "Failed to populate UICollectionView in 20 seconds")
Which polls constantly for 20 seconds for collection view to populate. Is there a better, non-polling way of achieving this?
EarlGrey recommends using its synchronization for waiting for elements rather than using sleeps or conditional checks like waits wherever possible.
EarlGrey has a variable kGREYConfigKeyInteractionTimeoutDuration value in GREYConfiguration that is set to 30 seconds and states -
* Configuration that holds timeout duration (in seconds) for action and assertions. Actions or
* assertions that are not scheduled within this time will fail due to timeout.
Since you're waiting for 20 seconds for your check, you can instead simply change it to -
EarlGrey().selectElementWithMatcher(collectionViewMatcher)
.assertWithMatcher(grey_notNil(), error: &errorOrNil)
and it'll be populated without a timeout.
I like to connect Earl Grey with basic XCTest and I've come up with this simple solution to problem of waiting for elements:
app.webViews.buttons["logout()"].waitForExistence(timeout: 5)
app.webViews.buttons["logout()"].tap()

GML Alarm event not working second time

I have my game setup so that it starts and goes back to a loading screen room for 45 steps after which the next room is randomized. So at alarm[0] the following code activates:
randomize();
chosenRoom = choose(rm_roomOne, rm_roomTwo, rm_roomThree, rm_roomFour);
room_goto(chosenRoom);
The code here works fine the first time, but when it goes back from the randomly chosen room to the loading screen room it stays there and doesn't execute the code again.
Any help would be very much appreciated.
This may sound stupid but did you remember to set the alarm again after it's gone off? I know I've done this several times without thinking. Without seeing your code, I assume that after the alarm goes off it's not being set again, so it won't go off again.
I'm guessing the control object is "persistant", thus the Control Object only exists once and will remain forever (also after swithcing rooms) - thus thie create event only gets fired once - thus the alarm only gets set once.
Try to move your code to the event "Room Start" in your controller and it will work.
you can use event_perform(ev_alarm,0);.
The code here performs alarm[0] after 45 steps. after 45 steps again it triggers alarm[0]. Note that you have to put it in step event. And you have to initialize wait variable and times to zero in create event.
times is the repeat and wait is distance between events.
if(wait == 45 && times !=2){
event_perform(ev_alarm,0);
times++;
wait = 0;
}
else{
wait++;
}

Will the Implicit wait will move on if findElement action is complete?

Implicit Wait : If wait is set, it will wait for specified amount of time for each findElement/findElements call. It will throw an exception if action is not complete.
Assume we set implicit wait to 10 secs. My question is will selenium move on to next step if findElement action is complete before 10 secs?
Yes. Setting implicit wait causes the driver object to wait for the set time if the element it is looking for is not found immediately. The driver object keeps polling the DOM every 500 milliseconds until it finds the element or the time-out expires.
This is the explanation from official Selenium documentation page:
An implicit wait is to tell WebDriver to poll the DOM for a certain
amount of time when trying to find an element or elements if they are
not immediately available. The default setting is 0. Once set, the
implicit wait is set for the life of the WebDriver object instance.
So, to answer your question in short, yes it continues with executing next steps as soon as it finds the element(s) it is looking for. You may also understand that to be the case from a simple experiment like #sircapsalot has shown in his answer.
Answer:
Yes. It will continue with the next step if it finds the element before the implicit timeout is hit.
Proof of concept:
#Test
public void test29800926() {
driver.get("http://ddavison.io/tests/getting-started-with-selenium.htm");
driver.manage().timeouts().implicitlyWait(30000, TimeUnit.MILLISECONDS);
System.out.println(driver.findElement(By.id("click")).getText());
}
Instead of waiting the total of 30 seconds that I set the implicit wait to (30000ms / 1000 = 30sec), it found it immediately and continued to print the text of the element.

jmeter stop current iteration

I am facing the following problem:
I have multiple HTTP Requests in my testplan.
I want every request to be repeated 4 times if they fail.
I realized that with a BeanShell Assertion, and its already working fine.
My problem is, that I don't want requests to be executed if a previous Request failed 5 times,
BUT I also dont want the thread to end.
I just want the current thread iteration to end,
so that the next iteration of the thread can start again with the 1st request (if the thread is meant to be repeated).
How do I realize that within the BeanShell Assertion?
Here is just a short extract of my code where i want the solution to have
badResponseCounter is being increased for every failed try of the request, this seems to work so far. Afterwards, the variable gets resetted.
if (badResponseCounter = 5) {
badResponseCounter = 0;
// Stop current iteration
}
I already checked the API, methods like setStopTest() or setStopThread() are given, but nothing for quitting the current iteration. I also need the preference "continue" in the thread group, as otherwise the entire test will stop after 1 single request failed.
Any ideas of how to do this?
In my opinion the easiest way is using following combination:
If Controller to check ${JMeterThread.last_sample_ok} and badResponseCounter variables
Test Action Sampler as a child of If Controller configured to "Go to next loop iteration"
Try this.
ctx.setRestartNextLoop(true);
if the thread number is 2, i tried to skip. I get the below result as i expected (it does not call b-2). It does not kill the thread either.