69 Stimmen

Wie kann man Selenium dazu bringen, auf eine Ajax-Antwort zu warten?

Wie kann ich Selenium dazu bringen, darauf zu warten, dass z. B. ein Kalender-Widget geladen wird? Im Moment mache ich nur eine Thread.sleep(2500) nach dem Exportieren des Testfalls in ein Junit-Programm.

2voto

Hrabosch Punkte 1451

Ich habe die nächste Methode als meine Lösung geschrieben (ich hatte keinen Lastindikator):

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

Dann rufe ich einfach diese Methode mit dem aktuellen Treiber auf. Mehr Beschreibung in diesem Beitrag .

2voto

George Kargakis Punkte 4013

Der unten stehende Code (C#) stellt sicher, dass das Zielelement angezeigt wird:

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

Wenn die Seite jQuery unterstützt, kann es mit dem jQuery.active-Funktion um sicherzustellen, dass das Zielelement abgerufen wird, nachdem alle Ajax-Aufrufe beendet sind:

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

2voto

neonidian Punkte 1087

Das funktioniert bei mir wie ein Zauber:

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

1voto

Amir Shenouda Punkte 2055

Ich hatte eine ähnliche Situation, ich wollte für Ajax-Anforderungen warten, so dass die Lade-Panel verschwunden wäre, habe ich die html vor und nach den Anforderungen untersucht, festgestellt, dass es ein div für die Ajax-Lade-Panel, das dix während der Ajax-Anforderung angezeigt wird, und versteckt, nachdem die Anforderung endet. Ich habe eine Funktion erstellt, um zu warten, bis das Panel angezeigt wird, und dann zu warten, bis es ausgeblendet wird

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

Siehe este für weitere Einzelheiten

1voto

llatinov Punkte 104

Wie bereits erwähnt, können Sie warten, bis aktive Verbindungen geschlossen werden:

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

Meiner Beobachtung nach ist dies nicht zuverlässig, da die Datenübertragung sehr schnell erfolgt. Viel mehr Zeit wird für die Datenverarbeitung und das Rendering auf der Seite verbraucht und sogar jQuery.active == 0 Die Daten sind möglicherweise noch nicht auf der Seite.

Viel klüger ist es, eine ausdrückliches Warten für das Element, das auf der Seite angezeigt werden soll, siehe einige der diesbezüglichen Antworten.

Am besten ist es, wenn Ihre Webanwendung über einen benutzerdefinierten Lader verfügt oder anzeigt, dass Daten verarbeitet werden. In diesem Fall können Sie einfach warten, bis diese Anzeige ausgeblendet wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X