How to implement wait for angularjs page in Serenity

1,884 views
Skip to first unread message

rphanik...@gmail.com

unread,
Aug 11, 2015, 1:02:59 AM8/11/15
to Serenity BDD Users Group
Hello team,

Can anyone help with me with a piece of code to handle wait for an angularjs page in Serenity. I see this release as part of 2.39.0.
But i couldnt find any example for the implementation.
 
Thanks in advance for your help!

Theo

unread,
Aug 11, 2015, 4:48:48 AM8/11/15
to Serenity BDD Users Group
If I'm not mistaken, the waitForAngularRequestsToFinish() in Serenity wraps the JS code used also in Protractor's waitForAngular().

You don't need to do anything special, write your Serenity code which will trigger an Angular call (i.e. click on a button which will make an Angular request and need to wait for some results to be rendered on the screen) and then add waitForAngularRequestsToFinish().

Nothing special about its use.
Search on Google waitForAngular and/or notifyWhenNoOutstandingRequests and you'll get more info about how this works.

Theo

Theo

unread,
Aug 11, 2015, 8:01:46 AM8/11/15
to Serenity BDD Users Group
Hi John,

I had the same method implemented myself in my framework, before you decided to add it to Serenity.

I remember that in the beginning I ran into this issue:

"asynchronous script timeout: result was not received in 0 seconds
Command duration or timeout: 9 milliseconds"

Apparently the default script timeout is 0 seconds. I remember I needed to add the following line before calling executeAsyncScript() in waitForAngularRequestsToFinish():

    getDriver().manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS);

How can we deal with that Serenity's wait for Angular? I would like to start using the one coming with Serenity.

Theo

John Smart

unread,
Aug 12, 2015, 2:38:47 AM8/12/15
to Theo, Serenity BDD Users Group
That's not currently supported and probably should be. Do you want to look at the current code and propose a pull request?

--
You received this message because you are subscribed to the Google Groups "Serenity BDD Users Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thucydides-use...@googlegroups.com.
To post to this group, send email to thucydid...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
___________________________________________________
John Smart | Wakaleo Consulting  |  +61 407 247 642
Optimizing your software development process
http://www.wakaleo.com  |  john....@wakaleo.com
___________________________________________________

We love breaking down silos and helping smart teams collaborate better! Ask about our tailored on-site workshops in Agile Requirements Discovery, Behaviour Driven Development, Agile Development Practices, and Test Automation!
___________________________________________________

shashi kumar

unread,
Jan 11, 2016, 6:48:41 AM1/11/16
to Serenity BDD Users Group, itheo...@gmail.com
Hi John

Even i am facing the same issue and want this code to be used in my tests.

Can you please share the code location and i will try to fix it from my side.

One more issue that i observed is "resetImplicitTimeout()" is not setting the timeout back to original property file value. Its always displaying "0" only.

Regards,
Shashi Kumar S
Message has been deleted

Sampathkumar S

unread,
Jan 20, 2016, 1:22:27 AM1/20/16
to Serenity BDD Users Group, itheo...@gmail.com
Best Practices for AngularJS applications with Serenity BDD and Selenium:

1.     Dynamic wait for AngularJS element using isElementVisible method.    

  I found a method which is implemented in PageObject.class of serenity BDD library, with help of this method I have performed actions on AngualarJS elements.

In below example, State dropdown is populated depends on Country selected. I need to select particular State from angular dropdown. Here I am iterating for every 300ms until I found the expected angular element.

This is working like a charm for me.

     public void selectState(String State) {
       
boolean isPresent = isElementVisible (By.cssSelector("select[ng-model$='context.state.stateID]"));
             
boolean isStateFound = false;
             
for (int i=0; i<=35; ++i) {
                     
System.out.println(i);
                     
if (isPresent==true){
                           find
(selectState).selectByVisibleText(State);
                           isStateFound
= true;
                           
break;
                     
}
                     waitABit
(300);
                 
}
       
Assert.assertTrue("Unable to find State list in 10 seconds", isPresent);
       
Assert.assertTrue("The School "+State+ " is not found in the list", isStateFound);
   
}


 

2.     Use JavascriptExecutor selenium interface to perform actions on AngularJS elements wherever we are unable to locate elements.

 

              JavascriptExecutor jsExecuter = (JavascriptExecutor) driver;
             
WebElement addItem = driver.findElement(By.xpath("//*[text()='Add Item']"));
              jsExecuter
.executeScript("arguments[0].click();",addItem);

3.      Add the following line before calling executeAsyncScript() in waitForAngularRequestsToFinish();

 

  getDriver().manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS);


Thank you!

Sampath S

Andy Orahood

unread,
Aug 29, 2016, 2:38:46 PM8/29/16
to Serenity BDD Users Group, itheo...@gmail.com
I would also benefit from having the timeout extended by default so that Serenity could wait for Angular to finish, still getting the

adi....@outlook.com

unread,
Sep 6, 2016, 4:37:34 AM9/6/16
to Serenity BDD Users Group
If you need to you can define your own methods to wait for angular to finish. What you will need to know first if the application uses Angular 1.x or 2.x and then use one of the appropriate methods:

public void waitForAngularV1ToFinish(WebDriver driver) {
final String query =
"window.angularFinished;" + "waitForAngular =function() {"
+ " window.angularFinished = false;"
+ " var el = document.querySelector('body');"
+ " var callback = (function(){window.angularFinished=1});"
+ " angular.element(el).injector().get('$browser')."
+ " notifyWhenNoOutstandingRequests(callback);};";
try {
((JavascriptExecutor) driver).executeScript(query);
((JavascriptExecutor) driver).executeScript("waitForAngular()");

ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
Object noAjaxRequests = ((JavascriptExecutor) driver).executeScript("return window.angularFinished;");
return "1".equals(noAjaxRequests.toString());
}
};
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(pageLoadCondition);
} catch (Exception e) {
fail("Unable to load the page correctly");
}
}

public void waitForAngularV2ToFinish(WebDriver driver) {
try {
ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
return Boolean.valueOf(((JavascriptExecutor) driver).executeScript(
"return (window.angular !== undefined) "
+ "&& (angular.element(document).injector() !== undefined) "
+ "&& (angular.element(document).injector().get('$http').pendingRequests.length === 0)").toString());
}
};
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(pageLoadCondition);
} catch (Exception e) {
System.out.print(e);
fail("Unable to load the page correctly");
}
}

Note: Angular2 seems to be completely different then 1 and so only the specific wait method will work. The other will timeout. Also if 30 seconds is to much a wait you can change that or pull it out of the method as a parameter
Reply all
Reply to author
Forward
0 new messages