1 package com.atlassian.pageobjects.elements;
2
3 import com.atlassian.annotations.Internal;
4 import com.atlassian.pageobjects.elements.timeout.DefaultTimeouts;
5 import com.atlassian.util.concurrent.Nullable;
6 import com.google.common.base.Preconditions;
7 import org.openqa.selenium.By;
8 import org.openqa.selenium.NoSuchElementException;
9 import org.openqa.selenium.SearchContext;
10 import org.openqa.selenium.WebDriver;
11
12 import javax.annotation.Nonnull;
13 import java.util.concurrent.TimeUnit;
14
15 /**
16 * <p/>
17 * A {@code SearchContext} that can be located by WebDriver, capable of re-locating. A locatable consists of locator
18 * used to locate itself, and the parent locatable that forms a search context, in which we locate this locatable.
19 *
20 * <p/>
21 * Locatables form a list representing the parent-child relationship of SearchContexts. The root locatable
22 * is always the locatable for WebDriver itself (think of it as a global search context).
23 * To locate a SearchContext, first the parent is located then the locator is applied to it.
24 *
25 * @since 2.0
26 */
27 @Internal
28 public interface WebDriverLocatable
29 {
30 /**
31 * Gets the WebDriver locator for this SearchContext.
32 *
33 * @return Locator, null if root.
34 */
35 @Nullable
36 By getLocator();
37
38 /**
39 * The parent of this SearchContext.
40 *
41 * @return The locatable for the parent, null if root.
42 */
43 @Nullable
44 WebDriverLocatable getParent();
45
46 /**
47 * Wait until this SearchContext represented by this locatable is located.
48 *
49 * @param driver the {@link WebDriver} instance.
50 * @param timeoutInSeconds timeout to wait until located, must be >= 0.
51 * @return SearchContext
52 * @throws NoSuchElementException if context could not be located before timeout expired
53 * @deprecated use {@link #waitUntilLocated(WebDriver, WebDriverLocatable.LocateTimeout)} instead. Scheduled for
54 * removal in 3.0
55 */
56 @Deprecated
57 @Nonnull
58 SearchContext waitUntilLocated(@Nonnull WebDriver driver, int timeoutInSeconds) throws NoSuchElementException;
59
60 /**
61 * Whether this SearchContext is present by given <tt>timeout</tt>.
62 *
63 * @param driver the {@link WebDriver} instance.
64 * @param timeoutInSeconds timeout to wait until parent is located, must be >= 0
65 * @return <code>true</code> if SearchContext is located before the timeout expires, <code>false</code> otherwise.
66 * @deprecated use {@link #isPresent(WebDriver, WebDriverLocatable.LocateTimeout)} instead. Scheduled for removal
67 * in 3.0
68 */
69 @Deprecated
70 boolean isPresent(@Nonnull WebDriver driver, int timeoutInSeconds);
71
72 /**
73 * Wait until the {@link SearchContext} represented by this locatable is located.
74 *
75 * @param driver the {@link WebDriver} instance.
76 * @param timeout LocateTimeout instance specifying the time to wait until located, must be >= 0.
77 * @return SearchContext
78 * @throws NoSuchElementException if context could not be located before timeout expired
79 * @see LocateTimeout
80 * @see SearchContext
81 * @since 2.2
82 */
83 @Nonnull
84 SearchContext waitUntilLocated(@Nonnull WebDriver driver, @Nonnull LocateTimeout timeout)
85 throws NoSuchElementException;
86
87 /**
88 * Whether this {@link SearchContext} is present, given its parent is located by {@code timeout}.
89 *
90 * @param driver the {@link WebDriver} instance.
91 * @param timeout LocateTimeout instance specifying the time to wait until the parent is located, must be >= 0.
92 * @return {@literal true} if the {@link SearchContext} is located before the timeout expires, {@literal false}
93 * otherwise
94 * @see LocateTimeout
95 * @since 2.2
96 */
97 boolean isPresent(@Nonnull WebDriver driver, @Nonnull LocateTimeout timeout);
98
99
100 /**
101 * Provides information about timeout and poll interval to use while performing locatable operations.
102 *
103 * @since 2.2
104 */
105 public static final class LocateTimeout
106 {
107 public static Builder builder() {
108 return new Builder();
109 }
110
111 public static LocateTimeout zero() {
112 return new LocateTimeout(0, 1); // if timeout is 0, no poll should happen anyway
113 }
114
115 private final long timeout;
116 private final long pollInterval;
117
118 private LocateTimeout(long timeout, long pollInterval)
119 {
120 Preconditions.checkArgument(timeout >= 0, "timeout >= 0");
121 Preconditions.checkArgument(pollInterval > 0, "pollInterval > 0");
122 this.timeout = timeout;
123 this.pollInterval = pollInterval;
124 }
125
126 public long timeout()
127 {
128 return timeout;
129 }
130
131 public long pollInterval()
132 {
133 return pollInterval;
134 }
135
136 public static final class Builder
137 {
138 private long timeout;
139 private long pollInterval = DefaultTimeouts.DEFAULT_INTERVAL;
140
141
142 public Builder timeout(long millis)
143 {
144 this.timeout = millis;
145 return this;
146 }
147
148 public Builder timeout(long amount, TimeUnit unit)
149 {
150 return timeout(unit.toMillis(amount));
151 }
152
153 public Builder pollInterval(long millis)
154 {
155 this.pollInterval = millis;
156 return this;
157 }
158
159 public Builder pollInterval(long amount, TimeUnit unit)
160 {
161 return pollInterval(unit.toMillis(amount));
162 }
163
164 public LocateTimeout build()
165 {
166 return new LocateTimeout(timeout, pollInterval);
167 }
168 }
169 }
170 }