Java tutorial
/* * 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.htmlunit.HtmlUnitDriver; import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.FluentWait; import org.openqa.selenium.support.ui.WebDriverWait; import java.time.Duration; import java.util.logging.Level; import java.util.logging.Logger; import static org.jboss.arquillian.graphene.Graphene.waitGui; import static org.keycloak.testsuite.util.DroneUtils.getCurrentDriver; 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.urlToBe; /** * * @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(By locator) { waitUntilElement(locator).is().not().present(); } public static void waitUntilElementIsNotPresent(WebElement element) { waitUntilElement(element).is().not().present(); // (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 */ public static void waitForPageToLoad() { WebDriver driver = getCurrentDriver(); if (driver instanceof HtmlUnitDriver) { return; // not needed } String currentUrl = null; // Ensure the URL is "stable", i.e. is not changing anymore; if it'd changing, some redirects are probably still in progress for (int maxRedirects = 4; maxRedirects > 0; maxRedirects--) { currentUrl = driver.getCurrentUrl(); FluentWait<WebDriver> wait = new FluentWait<>(driver).withTimeout(Duration.ofMillis(250)); try { wait.until(not(urlToBe(currentUrl))); } catch (TimeoutException e) { break; // URL has not changed recently - ok, the URL is stable and page is current } if (maxRedirects == 1) { log.warn("URL seems unstable! (Some redirect are probably still in progress)"); } } WebDriverWait wait = new WebDriverWait(getCurrentDriver(), PAGELOAD_TIMEOUT_MILLIS / 1000); ExpectedCondition waitCondition = null; // Different wait strategies for Admin and Account Consoles if (currentUrl.matches("^[^\\/]+:\\/\\/[^\\/]+\\/auth\\/admin\\/.*$")) { // Admin Console // Checks if the document is ready and asks AngularJS, if present, whether there are any REST API requests in progress waitCondition = javaScriptThrowsNoExceptions("if (document.readyState !== 'complete' " + "|| (typeof angular !== 'undefined' && angular.element(document.body).injector().get('$http').pendingRequests.length !== 0)) {" + "throw \"Not ready\";" + "}"); } else if (currentUrl.matches("^[^\\/]+:\\/\\/[^\\/]+\\/auth\\/realms\\/[^\\/]+\\/account\\/.*$") // check for Account Console URL && driver.getPageSource().contains("patternfly-ng") // check for new Account Console (don't use this strategy with the old one) ) { waitCondition = javaScriptThrowsNoExceptions( "if (!window.getAngularTestability(document.querySelector('app-root')).isStable()) {" + "throw 'Not ready';" + "}"); } if (waitCondition != null) { try { wait.until(waitCondition); } catch (TimeoutException e) { log.warn("waitForPageToLoad time exceeded!"); } } } public static void waitForModalFadeIn() { pause(500); // TODO: Find out how to do in more 'elegant' way, e.g. like in the waitForModalFadeOut } public static void waitForModalFadeOut() { waitUntilElementIsNotPresent(By.className("modal-backdrop")); } }