/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.jboss.arquillian.graphene.wait.ElementBuilder;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.jboss.arquillian.graphene.Graphene.waitGui;
import static org.openqa.selenium.support.ui.ExpectedConditions.invisibilityOfAllElements;
import static org.openqa.selenium.support.ui.ExpectedConditions.javaScriptThrowsNoExceptions;
import static org.openqa.selenium.support.ui.ExpectedConditions.not;
import static org.openqa.selenium.support.ui.ExpectedConditions.urlContains;
/**
*
* @author Petr Mensik
* @author tkyjovsk
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/
public final class WaitUtils {
protected final static org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(WaitUtils.class);
public static final String PAGELOAD_TIMEOUT_PROP = "pageload.timeout";
public static final Integer PAGELOAD_TIMEOUT_MILLIS = Integer.parseInt(System.getProperty(PAGELOAD_TIMEOUT_PROP, "10000"));
public static final int IMPLICIT_ELEMENT_WAIT_MILLIS = 750;
// Should be no longer necessary for finding elements since we have implicit wait
public static ElementBuilder<Void> waitUntilElement(By by) {
return waitGui().until().element(by);
}
// Should be no longer necessary for finding elements since we have implicit wait
public static ElementBuilder<Void> waitUntilElement(WebElement element) {
return waitGui().until().element(element);
}
// Should be no longer necessary for finding elements since we have implicit wait
public static ElementBuilder<Void> waitUntilElement(WebElement element, String failMessage) {
return waitGui().until(failMessage).element(element);
}
public static void waitUntilElementIsNotPresent(WebDriver driver, By locator) {
waitUntilElementIsNotPresent(driver, driver.findElement(locator));
}
public static void waitUntilElementIsNotPresent(WebDriver driver, WebElement element) {
(new WebDriverWait(driver, IMPLICIT_ELEMENT_WAIT_MILLIS))
.until(invisibilityOfAllElements(Collections.singletonList(element)));
}
public static void pause(long millis) {
if (millis > 0) {
log.info("Wait: " + millis + "ms");
try {
Thread.sleep(millis);
} catch (InterruptedException ex) {
Logger.getLogger(WaitUtils.class.getName()).log(Level.SEVERE, null, ex);
Thread.currentThread().interrupt();
}
}
}
/**
* Waits for page to finish any pending redirects, REST API requests etc.
* Because Keycloak's Admin Console is a single-page application, we need to
* take extra steps to ensure the page is fully loaded
*
* @param driver
*/
public static void waitForPageToLoad(WebDriver driver) {
WebDriverWait wait = new WebDriverWait(driver, PAGELOAD_TIMEOUT_MILLIS / 1000);
try {
wait.until(not(urlContains("redirect_fragment")));
// Checks if the document is ready and asks AngularJS, if present, whether there are any REST API requests
// in progress
wait.until(javaScriptThrowsNoExceptions(
"if (document.readyState !== 'complete' "
+ "|| (typeof angular !== 'undefined' && angular.element(document.body).injector().get('$http').pendingRequests.length !== 0)) {"
+ "throw \"Not ready\";"
+ "}"));
} catch (TimeoutException e) {
// Sometimes, for no obvious reason, the browser/JS doesn't set document.readyState to 'complete' correctly
// but that's no reason to let the test fail; after the timeout the page is surely fully loaded
log.warn("waitForPageToLoad time exceeded!");
}
}
public static void waitForModalFadeIn(WebDriver driver) {
pause(500); // TODO: Find out how to do in more 'elegant' way, e.g. like in the waitForModalFadeOut
}
public static void waitForModalFadeOut(WebDriver driver) {
waitUntilElementIsNotPresent(driver, By.className("modal-backdrop"));
}
}