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