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 */
82 @Nonnull
83 SearchContext waitUntilLocated(@Nonnull WebDriver driver, @Nonnull LocateTimeout timeout)
84 throws NoSuchElementException;
85
86 /**
87 * Whether this {@link SearchContext} is present, given its parent is located by {@code timeout}.
88 *
89 * @param driver the {@link WebDriver} instance.
90 * @param timeout LocateTimeout instance specifying the time to wait until the parent is located, must be >= 0.
91 * @return {@literal true} if the {@link SearchContext} is located before the timeout expires, {@literal false}
92 * otherwise
93 * @see LocateTimeout
94 */
95 boolean isPresent(@Nonnull WebDriver driver, @Nonnull LocateTimeout timeout);
96
97
98 /**
99 * Provides information about timeout and poll interval to use while performing locatable operations.
100 *
101 * @since 2.2
102 */
103 public static final class LocateTimeout
104 {
105 public static Builder builder() {
106 return new Builder();
107 }
108
109 public static LocateTimeout zero() {
110 return new LocateTimeout(0, 1); // if timeout is 0, no poll should happen anyway
111 }
112
113 private final long timeout;
114 private final long pollInterval;
115
116 private LocateTimeout(long timeout, long pollInterval)
117 {
118 Preconditions.checkArgument(timeout >= 0, "timeout >= 0");
119 Preconditions.checkArgument(pollInterval > 0, "pollInterval > 0");
120 this.timeout = timeout;
121 this.pollInterval = pollInterval;
122 }
123
124 public long timeout()
125 {
126 return timeout;
127 }
128
129 public long pollInterval()
130 {
131 return pollInterval;
132 }
133
134 public static final class Builder
135 {
136 private long timeout;
137 private long pollInterval = DefaultTimeouts.DEFAULT_INTERVAL;
138
139
140 public Builder timeout(long millis)
141 {
142 this.timeout = millis;
143 return this;
144 }
145
146 public Builder timeout(long amount, TimeUnit unit)
147 {
148 return timeout(unit.toMillis(amount));
149 }
150
151 public Builder pollInterval(long millis)
152 {
153 this.pollInterval = millis;
154 return this;
155 }
156
157 public Builder pollInterval(long amount, TimeUnit unit)
158 {
159 return pollInterval(unit.toMillis(amount));
160 }
161
162 public LocateTimeout build()
163 {
164 return new LocateTimeout(timeout, pollInterval);
165 }
166 }
167 }
168 }