1 package com.atlassian.webdriver.utils.element;
2
3 import com.atlassian.pageobjects.PageBinder;
4 import com.google.common.base.Function;
5 import org.openqa.selenium.TimeoutException;
6 import org.openqa.selenium.WebDriver;
7 import org.openqa.selenium.support.ui.WebDriverWait;
8
9 import javax.annotation.Nonnull;
10 import javax.inject.Inject;
11 import java.util.concurrent.TimeUnit;
12
13 import static com.google.common.base.Preconditions.checkArgument;
14 import static com.google.common.base.Preconditions.checkNotNull;
15
16 /**
17 * <p/>
18 * A component that can be used to wait for certain conditions to happen on the tested page.
19 *
20 * <p/>
21 * The conditions are expressed as a generic {@link Function} from {@link WebDriver} to {@code boolean}.
22 * {@link ElementConditions} contains factory methods to easily create some commonly used conditions.
23 *
24 * <p/>
25 * The {@link #DEFAULT_TIMEOUT} and {@link #DEFAULT_TIMEOUT_UNIT} specify the default timeout used when
26 * no explicit timeout is provided by the client, which is currently 30 seconds. Clients are encouraged to use
27 * their own timeout specific to the situation.
28 *
29 * <p/>
30 * NOTE: the default poll interval used by this class is as in the underlying {@link WebDriverWait} and is currently
31 * 500ms (subject to change as the underlying {@link WebDriverWait} implementation changes. This may be generally
32 * acceptable, but may not be granular enough for some scenarios (e.g. performance testing).
33 *
34 * <p/>
35 * Example usage:
36 * <pre>
37 * {@code
38 * @literal @Inject private WebDriverPoller poller;
39 *
40 * // ...
41 * // wait for 5s for a 'my-element' to be present on the page
42 * poller.waitUntil(ElementConditions.isPresent(By.id("my-element")), 5);
43 * }
44 * </pre>
45 *
46 * <p/>
47 * This component can be injected into page objects running within a {@link PageBinder} context.
48 *
49 * <p/>
50 * For more sophisticated polling/waiting toolkit, check the {@code PageElement} API in the
51 * atlassian-pageobjects-elements module.
52 *
53 * @since 2.2
54 * @see ElementConditions
55 * @see WebDriverWait
56 */
57 public final class WebDriverPoller
58 {
59 public static final long DEFAULT_TIMEOUT = 30;
60 public static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;
61
62 private final WebDriver webDriver;
63 private final TimeUnit timeUnit;
64 private final long timeout;
65
66 @Inject
67 public WebDriverPoller(@Nonnull WebDriver webDriver)
68 {
69 this(webDriver, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT);
70 }
71
72 public WebDriverPoller(@Nonnull WebDriver webDriver, long timeout, @Nonnull TimeUnit timeUnit)
73 {
74 checkArgument(timeout > 0, "Timeout must be >0");
75 this.webDriver = checkNotNull(webDriver, "webDriver");
76 this.timeout = timeout;
77 this.timeUnit = checkNotNull(timeUnit, "timeUnit");
78 }
79
80 public WebDriverPoller withDefaultTimeout(long timeout, TimeUnit timeUnit)
81 {
82 return new WebDriverPoller(webDriver, timeout, timeUnit);
83 }
84
85
86 /**
87 * Wait until {@literal condition} is {@literal true} up to the default timeout. The default timeout depends
88 * on the arguments supplied while creating an instance of this {@code WebDriverPoller}.
89 *
90 * @param condition condition that must evaluate to {@literal true}
91 * @throws TimeoutException if the condition does not come true before the timeout expires
92 * @see #DEFAULT_TIMEOUT
93 * @see #DEFAULT_TIMEOUT_UNIT
94 */
95 public void waitUntil(Function<WebDriver,Boolean> condition)
96 {
97 waitUntil(condition, timeout, timeUnit);
98 }
99
100 /**
101 * Wait until {@literal condition} up to the {@literal timeoutInSeconds}.
102 *
103 * @param condition condition that must evaluate to {@literal true}
104 * @param timeoutInSeconds timeout in seconds to wait for {@literal condition} to come true
105 * @throws TimeoutException if the condition does not come true before the timeout expires
106 */
107 public void waitUntil(Function<WebDriver,Boolean> condition, long timeoutInSeconds)
108 {
109 new WebDriverWait(webDriver, timeoutInSeconds).until(condition);
110 }
111
112
113 /**
114 * Wait until {@literal condition} up to the {@literal timeout} specified by {@literal unit}.
115 *
116 * @param condition condition that must evaluate to {@literal true}
117 * @param timeout timeout to wait for {@literal condition} to come true
118 * @param unit unit of the {@literal timeout}
119 * @throws TimeoutException if the condition does not come true before the timeout expires
120 */
121 public void waitUntil(Function<WebDriver,Boolean> condition, long timeout, TimeUnit unit)
122 {
123 waitUntil(condition, unit.toSeconds(timeout));
124 }
125 }