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.
Antworten
Zu viele Anzeigen?Hier ist eine groovige Version, die auf der Antwort von Morten Christiansen basiert.
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)
}
Wenn das Steuerelement, auf das Sie warten, ein "Ajax"-Web-Element ist, wartet der folgende Code darauf oder auf jedes andere Ajax-Web-Element, um das Laden oder die Ausführung der erforderlichen Aktionen zu beenden, so dass Sie mit Ihren Schritten sicher fortfahren können.
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);
}
});
}
In meinem Fall schien das Problem auf Ajax-Verzögerungen zurückzuführen zu sein, war aber mit internen Iframes innerhalb der Hauptseite verbunden. In seleminum ist es möglich, mit auf interne Frames umzuschalten:
driver.switchTo().frame("body");
driver.switchTo().frame("bodytab");
Ich benutze Java. Danach konnte ich das Element ausfindig machen
driver.findElement(By.id("e_46")).click();
Nachfolgend ist mein Code für fetch. Nahm mich während der Forschung, weil jQuery.active nicht mit Fetch funktioniert. Hier ist die Antwort half mir Proxy Fetch, aber seine nur für Ajax nicht Fetch Spott für Selen
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);
}
}
- See previous answers
- Weitere Antworten anzeigen