Подтвердить что ты не робот

Как получить селен, чтобы ждать ответа ajax?

Как я могу заставить селен ждать чего-то вроде виджета календаря для загрузки? Прямо сейчас я делаю Thread.sleep(2500) после экспорта тестовой программы в программу junit.

4b9b3361

Ответ 1

Я бы использовал

waitForElementPresent(locator)

Это будет ждать, пока элемент не появится в DOM.

Если вам нужно проверить, что элемент виден, вы можете лучше использовать

waitForElementHeight(locator)

Ответ 2

Более общее решение, чем ожидание элемента, - это подождать, пока все соединения с сервером будут закрыты. Это позволит вам дождаться завершения всех вызовов ajax, даже если они не имеют обратного вызова и, таким образом, не влияют на страницу. Более подробную информацию можно найти здесь.

Используя С# и jQuery, я создал следующий метод, чтобы дождаться завершения всех вызовов AJax (если у кого-то есть более прямые способы доступа к переменным JS из С#, прокомментируйте):

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);
}

Ответ 3

Если вы используете python, вы можете использовать эту функцию, которая нажимает кнопку и ждет изменения DOM:

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: на основе этот ответ)

Ответ 4

С webdriver aka selenium2 вы можете использовать неявную конфигурацию ожидания, как указано на http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp#implicit-waits

Использование 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"));

Или используя 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")

Ответ 5

Я написал следующий метод в качестве своего решения (у меня не было индикатора нагрузки):

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();");
}

Затем я использую этот метод с фактическим драйвером. Подробнее в этом post.

Ответ 6

Эта работа для меня

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");
        }
    });
}

Ответ 7

У меня была аналогичная ситуация, я хотел дождаться запросов ajax, чтобы панель загрузки исчезла, я проверил html до и после запросов, обнаружил, что есть div для панели загрузки ajax, dix отображается во время запроса ajax и скрывается после завершения запроса. Я создал функцию, чтобы ждать отображения панели, а затем дождаться ее скрытия

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)));
}

Подробнее о этом подробнее

Ответ 8

Как уже упоминалось выше, вы можете ждать, пока активные соединения закрываются:

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

Мое наблюдение это ненадежно, так как передача данных происходит очень быстро. Значительно больше времени потребляется на обработку и рендеринг данных на странице, и даже jQuery.active == 0 данные могут еще не отображаться на странице.

Гораздо разумнее использовать явное ожидание для элемента, который будет показан на странице, см. некоторые ответы, связанные с этим.

Лучше всего, если ваше веб-приложение имеет какой-то пользовательский загрузчик или указывает, что данные обрабатываются. В этом случае вы можете просто ждать, пока это указание не скроется.

Ответ 9

Ниже приведен код (С#), обеспечивающий отображение целевого элемента:

        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;
        }

Если страница поддерживает jQuery, она может использоваться jQuery.active function, чтобы гарантировать, что целевой элемент будет восстановлен после завершения всех вызовов ajax:

 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;
        }
    }

Ответ 10

Здесь приведена версия groovy, основанная на Мортен Кристиансен.

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)
}

Ответ 11

Это работает как очарование для меня:

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;
}

Ответ 12

Если элемент управления, который вы ожидаете, является веб-элементом "Ajax", следующий код будет ждать его или любой другой веб-элемент Ajax, чтобы завершить загрузку или выполнить все, что ему нужно, чтобы вы могли более безопасно продолжать с вашими шагами.

    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);
        }
    }); 

}

Ответ 13

Ниже мой код для получения. Взял меня во время исследования, потому что jQuery.active не работает с fetch. Вот ответ помог мне получить прокси, но это только для ajax, а не для извлечения макет для селена

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);
    }
}

Ответ 14

Для тех, кто использует примитивы, просто выполните:

selenium.waitForCondition("selenium.browserbot.getCurrentWindow().$.active==0", defaultWaitingPeriod);