All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ru.stqa.selenium.wait.ActionRepeater Maven / Gradle / Ivy

/*
 * Copyright 2013 Alexei Barantsev
 *
 *  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 ru.stqa.selenium.wait;

import com.google.common.base.Throwables;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Clock;
import org.openqa.selenium.support.ui.Duration;
import org.openqa.selenium.support.ui.Sleeper;
import org.openqa.selenium.support.ui.SystemClock;

import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

/**
 * Each ActionRepeater instance defines the maximum amount of time to attempt to perform an action,
 * as well as the frequency with which to call the action.
 *
 * 

* Sample usage: * // Try to look for an element to be present on the page, checking
* // for its presence once every 5 seconds until timeout of 30 seconds is expired.
* ActionRepeater<WebDriver> repeater = new ActionRepeater<WebDriver>(driver)
* .withTimeout(30, SECONDS)
* .pollingEvery(5, SECONDS);
*
* WebElement foo = repeater.tryTo(new AbstractRepeatableAction<SearchContext, WebElement>() {
* public WebElement apply(SearchContext context) {
* return driver.findElement(By.id("foo"));
* }
* public boolean shouldIgnoreException(Throwable t) {
* return t instanceof NoSuchElementException;
* }
* }); *
* *

* This class makes no thread safety guarantees. * * @param The action execution context type. */ public class ActionRepeater { public static ActionRepeater with(WebDriver driver) { return new ActionRepeater(driver); } public static ActionRepeater with(WebDriver driver, long timeOutInSeconds) { return new ActionRepeater(driver, timeOutInSeconds); } public static ActionRepeater with(WebDriver driver, long timeOutInSeconds, long sleepInMillis) { return new ActionRepeater(driver, timeOutInSeconds, sleepInMillis); } public static ActionRepeater with(WebDriver driver, Clock clock, Sleeper sleeper, long timeOutInSeconds, long sleepInMillis) { return new ActionRepeater(driver, clock, sleeper, timeOutInSeconds, sleepInMillis); } public static ActionRepeater with(WebElement element) { return new ActionRepeater(element); } public static ActionRepeater with(WebElement element, long timeOutInSeconds) { return new ActionRepeater(element, timeOutInSeconds); } public static ActionRepeater with(WebElement element, long timeOutInSeconds, long sleepInMillis) { return new ActionRepeater(element, timeOutInSeconds, sleepInMillis); } public static ActionRepeater with(WebElement element, Clock clock, Sleeper sleeper, long timeOutInSeconds, long sleepInMillis) { return new ActionRepeater(element, clock, sleeper, timeOutInSeconds, sleepInMillis); } public static Duration FIVE_HUNDRED_MILLIS = new Duration(500, MILLISECONDS); private final T context; private final Clock clock; private final Sleeper sleeper; private Duration timeout = FIVE_HUNDRED_MILLIS; private Duration interval = FIVE_HUNDRED_MILLIS; private String message = null; public final static long DEFAULT_SLEEP_TIMEOUT = 500; public ActionRepeater(T context) { this(context, DEFAULT_SLEEP_TIMEOUT); } public ActionRepeater(T context, long timeOutInSeconds) { this(context, timeOutInSeconds, DEFAULT_SLEEP_TIMEOUT); } public ActionRepeater(T context, long timeOutInSeconds, long sleepInMillis) { this(context, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, sleepInMillis); } /** * @param context The execution context to pass to the action * @param clock The clock to use when measuring the timeout * @param sleeper Object used to make the current thread go to sleep. * @param timeOutInSeconds The timeout in seconds when an expectation is * @param sleepTimeOut The timeout used whilst sleeping. Defaults to {@link #FIVE_HUNDRED_MILLIS}. */ protected ActionRepeater(T context, Clock clock, Sleeper sleeper, long timeOutInSeconds, long sleepTimeOut) { this.context = checkNotNull(context); this.clock = checkNotNull(clock); this.sleeper = checkNotNull(sleeper); withTimeout(timeOutInSeconds, TimeUnit.SECONDS); pollingEvery(sleepTimeOut, TimeUnit.MILLISECONDS); } /** * Sets how long to wait for the action to return a result that should not be ignored. * The default timeout is {@link #FIVE_HUNDRED_MILLIS}. * * @param duration The timeout duration. * @param unit The unit of time. * @return A self reference. */ public ActionRepeater withTimeout(long duration, TimeUnit unit) { this.timeout = new Duration(duration, unit); return this; } /** * Sets how often the action should be repeated. * *

* In reality, the interval may be greater as the cost of actually evaluating the action * is not factored in. The default polling interval is {@link #FIVE_HUNDRED_MILLIS}. * * @param duration The timeout duration. * @param unit The unit of time. * @return A self reference. */ public ActionRepeater pollingEvery(long duration, TimeUnit unit) { this.interval = new Duration(duration, unit); return this; } /** * Repeatedly attempts to perform the action until one of the following occurs: *

    *
  1. the function returns a value that should not be ignored,
  2. *
  3. the function throws a exception that should not be ignored,
  4. *
  5. the timeout expires, *
  6. *
  7. the current thread is interrupted
  8. *
* * @param action the action to be performed repeatedly * @param The action's expected return type. * @return The action' return value if the action returned a result that should not be ignored. * @throws org.openqa.selenium.TimeoutException If the timeout expires. */ public V tryTo(RepeatableAction action) { long end = clock.laterBy(timeout.in(MILLISECONDS)); Throwable lastException = null; while (true) { try { V result = action.apply(context); if (! action.shouldIgnoreResult(result)) { return result; } } catch (Throwable e) { if (! action.shouldIgnoreException(e)) { throw Throwables.propagate(e); } else { lastException = e; } } // Check the timeout after evaluating the function to ensure conditions // with a zero timeout can succeed. if (!clock.isNowBefore(end)) { String toAppend = message == null ? " trying to perform action " + action.toString() : ": " + message; String timeoutMessage = String.format("Timed out after %d seconds%s", timeout.in(SECONDS), toAppend); throw new TimeoutException(timeoutMessage, lastException); } try { sleeper.sleep(interval); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new WebDriverException(e); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy