How to get selenium to wait for ajax response?

How can I make selenium wait for something like a calendar widget to load? Right now I am doing Thread.sleep(2500) after exporting the test program to the junit program.

+58
ajax unit-testing selenium
May 14 '10 at 15:04
source share
14 answers

I would use

 waitForElementPresent(locator) 

This will wait until the item appears in the DOM.

If you need to verify that the item is visible, you can better use

 waitForElementHeight(locator) 
+42
May 14, '10 at 15:15
source share

A more general solution than waiting for an item is to wait until all connections to the server are closed. This will allow you to wait for all ajax calls to complete even if they do not have a callback and thus do not affect the page. More information can be found here .

Using C # and jQuery, I created the following method to wait for all AJax calls to complete (if anyone has more direct ways to access JS variables from C #, comment):

 internal void WaitForAjax(int timeOut = 15) { var value = ""; RepeatUntil( () => value = GetJavascriptValue("jQuery.active"), () => value == "0", "Ajax calls did not complete before timeout" ); } internal void RepeatUntil(Action repeat, Func<bool> until, string errorMessage, int timeout = 15) { var end = DateTime.Now + TimeSpan.FromSeconds(timeout); var complete = false; while (DateTime.Now < end) { repeat(); try { if (until()) { complete = true; break; } } catch (Exception) { } Thread.Sleep(500); } if (!complete) throw new TimeoutException(errorMessage); } internal string GetJavascriptValue(string variableName) { var id = Guid.NewGuid().ToString(); _selenium.RunScript(String.Format(@"window.$('body').append(""<input type='text' value='""+{0}+""' id='{1}'/>"");", variableName, id)); return _selenium.GetValue(id); } 
+24
Feb 15 '11 at 7:40
source share

If you use python, you can use this function, which clicks a button and waits for the DOM to change:

 def click_n_wait(driver, button, timeout=5): source = driver.page_source button.click() def compare_source(driver): try: return source != driver.page_source except WebDriverException: pass WebDriverWait(driver, timeout).until(compare_source) 

(CREDIT: based on this answer )

+11
Apr 30 '14 at 8:15
source share

With webdriver aka selenium2, you can use an implicit wait configuration, as indicated at http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp#implicit-waits

Using Java:

 WebDriver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get("http://somedomain/url_that_delays_loading"); WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement")); 

Or using python:

 from selenium import webdriver ff = webdriver.Firefox() ff.implicitly_wait(10) # seconds ff.get("http://somedomain/url_that_delays_loading") myDynamicElement = ff.find_element_by_id("myDynamicElement") 
+6
Oct 15 '13 at 13:16
source share

I wrote the following method as my solution (I did not have a load indicator):

 public static void waitForAjax(WebDriver driver, String action) { driver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS); ((JavascriptExecutor) driver).executeAsyncScript( "var callback = arguments[arguments.length - 1];" + "var xhr = new XMLHttpRequest();" + "xhr.open('POST', '/" + action + "', true);" + "xhr.onreadystatechange = function() {" + " if (xhr.readyState == 4) {" + " callback(xhr.responseText);" + " }" + "};" + "xhr.send();"); } 

Then I use this method with the actual driver. More details in this post .

+3
Jul 23 '15 at 20:15
source share

This work is for me.

 public void waitForAjax(WebDriver driver) { new WebDriverWait(driver, 180).until(new ExpectedCondition<Boolean>(){ public Boolean apply(WebDriver driver) { JavascriptExecutor js = (JavascriptExecutor) driver; return (Boolean) js.executeScript("return jQuery.active == 0"); } }); } 
+2
Oct 11 '17 at 7:34 on
source share

I had a similar situation, I wanted to wait for ajax requests for the loading bar to disappear, I checked html before and after the requests, found that there is a div for the ajax loading bar, dix is ​​displayed during the ajax request and hides after the request is complete. I created a function to wait for the panel to appear, and then wait for it to hide

public void WaitForModalPanel() { string element_xpath = ".//*[@id='ajaxLoadingModalPanelContainer' and not(contains(@style,'display: none'))]"; WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 2, 0)); wait.Until(ExpectedConditions.ElementIsVisible(By.XPath(element_xpath))); element_xpath = ".//*[@id='ajaxLoadingModalPanelContainer' and contains(@style,'DISPLAY: none')]"; wait.Until(ExpectedConditions.ElementExists(By.XPath(element_xpath))); } 

More about this more

+1
Jun 17 '13 at 11:44
source share

As mentioned above, you can wait for active connections to close:

 private static void WaitForReady() { WebDriverWait wait = new WebDriverWait(webDriver, waitForElement); wait.Until(driver => (bool)((IJavaScriptExecutor)driver).ExecuteScript("return jQuery.active == 0")); } 

My observation is unreliable, since data transfer is very fast. Significantly more time is spent on processing and rendering data on the page, and even jQuery.active == 0 data may not yet be displayed on the page.

It is much wiser to use an explicit wait for the element that will be shown on the page, see some answers related to this.

Best of all, if your web application has some kind of custom loader or indicates that the data is being processed. In this case, you can just wait until this indication is hidden.

+1
Mar 21 '15 at 10:01
source share

Below is the code (C #) for displaying the target element:

  internal static bool ElementIsDisplayed() { IWebDriver driver = new ChromeDriver(); driver.Url = "http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp"; WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); By locator = By.CssSelector("input[value='csharp']:first-child"); IWebElement myDynamicElement = wait.Until<IWebElement>((d) => { return d.FindElement(locator); }); return myDynamicElement.Displayed; } 

If the page supports jQuery, it can be used by the jQuery.active function to ensure that the target element will be restored after all ajax calls have completed:

  public static bool ElementIsDisplayed() { IWebDriver driver = new ChromeDriver(); driver.Url = "http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp"; WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); By locator = By.CssSelector("input[value='csharp']:first-child"); return wait.Until(d => ElementIsDisplayed(d, locator)); } public static bool ElementIsDisplayed(IWebDriver driver, By by) { try { if (driver.FindElement(by).Displayed) { //jQuery is supported. if ((bool)((IJavaScriptExecutor)driver).ExecuteScript("return window.$ != undefined")) { return (bool)((IJavaScriptExecutor)driver).ExecuteScript("return $.active == 0"); } else { return true; } } else { return false; } } catch (Exception) { return false; } } 
+1
Feb 01 '16 at 10:15
source share

Here is a version of groovy based on Morten Christiansen.

 void waitForAjaxCallsToComplete() { repeatUntil( { return getJavaScriptFunction(driver, "return (window.jQuery || {active : false}).active") }, "Ajax calls did not complete before timeout." ) } static void repeatUntil(Closure runUntilTrue, String errorMessage, int pollFrequencyMS = 250, int timeOutSeconds = 10) { def today = new Date() def end = today.time + timeOutSeconds def complete = false; while (today.time < end) { if (runUntilTrue()) { complete = true; break; } sleep(pollFrequencyMS); } if (!complete) throw new TimeoutException(errorMessage); } static String getJavaScriptFunction(WebDriver driver, String jsFunction) { def jsDriver = driver as JavascriptExecutor jsDriver.executeScript(jsFunction) } 
+1
Mar 17 '16 at 18:59
source share

This works like a charm for me:

 public void waitForAjax() { try { WebDriverWait driverWait = new WebDriverWait(driver, 10); ExpectedCondition<Boolean> expectation; expectation = new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver driverjs) { JavascriptExecutor js = (JavascriptExecutor) driverjs; return js.executeScript("return((window.jQuery != null) && (jQuery.active === 0))").equals("true"); } }; driverWait.until(expectation); } catch (TimeoutException exTimeout) { // fail code } catch (WebDriverException exWebDriverException) { // fail code } return this; } 
+1
Feb 10 '17 at 10:39 on
source share

If the control you are expecting is an Ajax web element, the following code will wait for it or any other Ajax web element to complete the download or to do whatever it needs so that you can continue with your steps more safely.

  public static void waitForAjaxToFinish() { WebDriverWait wait = new WebDriverWait(driver, 10); wait.until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver wdriver) { return ((JavascriptExecutor) driver).executeScript( "return jQuery.active == 0").equals(true); } }); } 
0
Jul 12 '16 at 19:52
source share

Below is my code to receive. Took me during the study because jQuery.active does not work with fetch. Here is the answer that helped me get a proxy, but this is only for ajax, not for fetching a layout for selenium

 public static void customPatchXMLHttpRequest(WebDriver driver) { try { if (driver instanceof JavascriptExecutor) { JavascriptExecutor jsDriver = (JavascriptExecutor) driver; Object numberOfAjaxConnections = jsDriver.executeScript("return window.openHTTPs"); if (numberOfAjaxConnections instanceof Long) { return; } String script = " (function() {" + "var oldFetch = fetch;" + "window.openHTTPs = 0; console.log('starting xhttps');" + "fetch = function(input,init ){ " + "window.openHTTPs++; " + "return oldFetch(input,init).then( function (response) {" + " if (response.status >= 200 && response.status < 300) {" + " window.openHTTPs--; console.log('Call completed. Remaining active calls: '+ window.openHTTPs); return response;" + " } else {" + " window.openHTTPs--; console.log('Call fails. Remaining active calls: ' + window.openHTTPs); return response;" + " };})" + "};" + "var oldOpen = XMLHttpRequest.prototype.open;" + "XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {" + "window.openHTTPs++; console.log('xml ajax called');" + "this.addEventListener('readystatechange', function() {" + "if(this.readyState == 4) {" + "window.openHTTPs--; console.log('xml ajax complete');" + "}" + "}, false);" + "oldOpen.call(this, method, url, async, user, pass);" + "}" + "})();"; jsDriver.executeScript(script); } else { System.out.println("Web driver: " + driver + " cannot execute javascript"); } } catch (Exception e) { System.out.println(e); } } 
0
Jul 29 '19 at 19:10
source share

For those using primitives, just do:

 selenium.waitForCondition("selenium.browserbot.getCurrentWindow().$.active==0", defaultWaitingPeriod); 
-2
Apr 18 2018-12-18T00:
source share



All Articles