1 package com.atlassian.pageobjects.elements.test.search;
2
3 import com.atlassian.pageobjects.elements.CheckboxElement;
4 import com.atlassian.pageobjects.elements.PageElement;
5 import com.atlassian.pageobjects.elements.PageElementFinder;
6 import com.atlassian.pageobjects.elements.PageElements;
7 import com.atlassian.pageobjects.elements.WebDriverElement;
8 import com.atlassian.pageobjects.elements.query.TimedQuery;
9 import com.atlassian.pageobjects.elements.search.AnyQuery;
10 import com.atlassian.pageobjects.elements.search.PageElementQuery;
11 import com.atlassian.pageobjects.elements.search.PageElementSearch;
12 import com.atlassian.pageobjects.elements.search.SearchQuery;
13 import com.atlassian.pageobjects.elements.test.AbstractPageElementBrowserTest;
14 import com.atlassian.pageobjects.elements.test.pageobjects.page.PageElementSearchPage;
15 import com.atlassian.pageobjects.elements.timeout.TimeoutType;
16 import org.hamcrest.FeatureMatcher;
17 import org.hamcrest.Matcher;
18 import org.hamcrest.Matchers;
19 import org.junit.Before;
20 import org.junit.Test;
21 import org.openqa.selenium.By;
22
23 import javax.inject.Inject;
24
25 import static com.atlassian.pageobjects.elements.PageElements.getDataAttribute;
26 import static com.atlassian.pageobjects.elements.PageElements.hasClass;
27 import static com.atlassian.pageobjects.elements.PageElements.hasDataAttribute;
28 import static com.atlassian.pageobjects.elements.query.Poller.waitUntil;
29 import static com.atlassian.pageobjects.elements.query.Poller.waitUntilTrue;
30 import static com.atlassian.pageobjects.elements.testing.PageElementMatchers.asMatcherOf;
31 import static com.atlassian.pageobjects.elements.testing.PageElementMatchers.isChecked;
32 import static com.atlassian.pageobjects.elements.testing.PageElementMatchers.withAttribute;
33 import static com.atlassian.pageobjects.elements.testing.PageElementMatchers.withClass;
34 import static com.atlassian.pageobjects.elements.testing.PageElementMatchers.withDataAttribute;
35 import static com.atlassian.pageobjects.elements.testing.PageElementMatchers.withId;
36 import static com.atlassian.pageobjects.elements.testing.PageElementMatchers.withText;
37 import static com.atlassian.webdriver.testing.matcher.MatcherPredicate.withMatcher;
38 import static org.hamcrest.Matchers.contains;
39 import static org.hamcrest.Matchers.emptyIterable;
40 import static org.hamcrest.Matchers.equalTo;
41 import static org.hamcrest.Matchers.everyItem;
42 import static org.hamcrest.Matchers.hasItems;
43 import static org.hamcrest.Matchers.is;
44 import static org.hamcrest.Matchers.not;
45 import static org.junit.Assert.assertEquals;
46 import static org.junit.Assert.assertNotNull;
47 import static org.junit.Assert.assertThat;
48 import static org.junit.Assert.assertTrue;
49 import static org.openqa.selenium.By.className;
50 import static org.openqa.selenium.By.id;
51 import static org.openqa.selenium.By.tagName;
52
53 @SuppressWarnings("unchecked")
54 public class TestPageElementSearch extends AbstractPageElementBrowserTest
55 {
56 @Inject
57 private PageElementSearch page;
58
59 @Inject
60 private PageElementFinder elementFinder;
61
62 private PageElementSearchPage searchPage;
63
64 @Before
65 public void goToElementSearchPage()
66 {
67 searchPage = product.visit(PageElementSearchPage.class);
68 }
69
70 @Test
71 public void shouldFindSinglePageElementById()
72 {
73 PageElement result = page.search()
74 .by(id("single-element"))
75 .first();
76
77 assertNotNull(result);
78 assertTrue(result.isPresent());
79 assertEquals("single-element", result.getAttribute("id"));
80 }
81
82 @Test
83 public void shouldFindSinglePageElementByIdAsIterable()
84 {
85 assertResult(page.search().by(id("single-element")), contains(withAttribute("id", "single-element")));
86 }
87
88 @Test
89 public void shouldReturnEmptyImmediatelyWhenSearchingFromNotExistingRoot()
90 {
91 Iterable<PageElement> result = elementFinder.find(By.id("no-such-id")).search()
92 .by(id("nested-id"))
93 .by(tagName("ul"))
94 .by(tagName("li")).filter(hasDataAttribute("pick-me"))
95 .now();
96
97 assertThat(result, emptyIterable());
98 }
99
100 @Test
101 public void shouldFindRowsWithFilter()
102 {
103 PageElementQuery<PageElement> result = page.search()
104 .by(id("table-list"))
105 .by(id("the-table"))
106 .by(tagName("tr"), hasClass("even-row"));
107
108 assertResult(result, contains(
109 withDataAttribute("name", "Even Row 1"),
110 withDataAttribute("name", "Even Row 2"),
111 withDataAttribute("name", "Even Row 3")
112 ));
113 }
114
115 @Test
116 public void shouldApplyFlatMap()
117 {
118 AnyQuery<String> result = page.search()
119 .by(id("table-list"))
120 .by(id("the-table"))
121 .by(tagName("tr"), hasClass("even-row"))
122 .flatMap(PageElements.getCssClasses());
123
124 assertResult(result, contains("even-row", "two", "even-row", "four", "even-row", "six"));
125 }
126
127 @Test
128 public void shouldFindRowsFromTableRoot()
129 {
130 Iterable<PageElement> result = searchPage.getTableRoot().search()
131 .by(id("the-table"))
132 .by(tagName("tr"))
133 .now();
134
135 assertThat(result, Matchers.<PageElement>iterableWithSize(7));
136 }
137
138 @Test
139 public void shouldFindRowsWithFilterAndTransformOnResult()
140 {
141 AnyQuery<String> result = page.search()
142 .by(id("table-list"))
143 .by(id("the-table"))
144 .by(tagName("tr"))
145 .filter(hasClass("uneven-row"))
146 .map(getDataAttribute("name"));
147
148 assertResult(result, contains("Uneven Row 1", "Uneven Row 2", "Uneven Row 3"));
149 }
150
151
152 @Test
153 public void shouldFindRowsWithFilterOnResultUsingMatcher()
154 {
155 AnyQuery<String> result = page.search()
156 .by(id("table-list"))
157 .by(id("the-table"))
158 .by(tagName("tr"))
159 .filter(withMatcher(withClass("uneven-row")))
160 .map(getDataAttribute("name"));
161
162 assertResult(result, contains("Uneven Row 1", "Uneven Row 2", "Uneven Row 3"));
163 }
164
165 @Test
166 public void shouldFindRowsWithFilterAndBindOnResult()
167 {
168 AnyQuery<RowWrapper> result = page.search()
169 .by(id("table-list"))
170 .by(id("the-table"))
171 .by(tagName("tr"))
172 .filter(hasClass("even-row"))
173 .bindTo(RowWrapper.class);
174
175 assertResult(result, contains(
176 rowWithName("Even Row 1"),
177 rowWithName("Even Row 2"),
178 rowWithName("Even Row 3")));
179 }
180
181 @Test
182 public void findFirstNestedElement()
183 {
184 PageElementQuery<PageElement> query = page.search()
185 .by(id("parent-1"))
186 .by(className("parent-2-class")).filter(hasDataAttribute("find-me"))
187 .by(tagName("ul"))
188 .by(tagName("li")).filter(withMatcher(withDataAttribute("pick-me", "yes")));
189
190 PageElement element = findFirst(query);
191 assertTrue(element.isPresent());
192 assertEquals("Yes-1", element.getText());
193 }
194
195 @Test
196 public void findMergeMultipleDomBranches()
197 {
198 PageElementQuery<PageElement> result = page.search()
199 .by(id("parent-1"))
200 .by(className("parent-2-class"))
201 .by(tagName("ul"))
202 .by(tagName("li"));
203
204 assertResultStrict(result, Matchers.<PageElement>iterableWithSize(5));
205 assertResultStrict(result, hasItems(
206 withText("WRONG!"),
207 withText("No"),
208 withText("Yes-1"),
209 withText("Yes-2"))
210 );
211 }
212
213 @Test
214 public void shouldWaitForSearchResultsToMatch() {
215 TimedQuery<Iterable<PageElement>> result = searchPage.getAsyncRoot().search()
216 .by(className("async-parent-level-2-class"))
217 .by(tagName("li"), hasDataAttribute("state", "2"))
218 .timed();
219 waitUntil(result, emptyIterable());
220
221
222 searchPage.clickAsyncButton(2);
223 waitUntil(result, Matchers.<PageElement>iterableWithSize(2));
224
225
226 searchPage.clickAsyncButton(1);
227 waitUntil(result, emptyIterable());
228 }
229
230 @Test
231 public void shouldAssignCustomTimeoutType()
232 {
233 PageElementQuery<PageElement> result = page.search()
234 .by(id("table-list"))
235 .by(id("the-table"))
236 .by(tagName("tr"), hasClass("even-row"))
237 .withTimeout(TimeoutType.PAGE_LOAD);
238
239 assertResultStrict(result, everyItem(hasTimeoutType(TimeoutType.PAGE_LOAD)));
240 }
241
242 @Test
243 public void shouldReturnResultAsCheckboxes()
244 {
245 PageElementQuery<CheckboxElement> result = page.search()
246 .by(id("checkbox-parent"))
247 .by(tagName("input"))
248 .as(CheckboxElement.class)
249 .filter(withMatcher(not(isChecked())));
250
251
252 assertResult(result, contains(
253 asMatcherOf(CheckboxElement.class, withId("checkbox-2")),
254 asMatcherOf(CheckboxElement.class, withId("checkbox-3"))
255 ));
256 }
257
258 private static <R> void assertResult(SearchQuery<R, ?> result, Matcher<Iterable<? extends R>> matcher)
259 {
260 waitUntil(result.timed(), matcher);
261 assertThat(result.get(), matcher);
262 assertThat(result.now(), matcher);
263 }
264
265 private static <R> void assertResultStrict(SearchQuery<R, ?> result, Matcher<Iterable<R>> matcher)
266 {
267 waitUntil(result.timed(), matcher);
268 assertThat(result.get(), matcher);
269 assertThat(result.now(), matcher);
270 }
271
272 private static PageElement findFirst(PageElementQuery<?> query)
273 {
274 waitUntilTrue(query.hasResult());
275
276 return query.first();
277 }
278
279 private static Matcher<PageElement> hasTimeoutType(TimeoutType expectedTimeout)
280 {
281 return new FeatureMatcher<PageElement, TimeoutType>(is(expectedTimeout), "timeout type", "timeoutType")
282 {
283 @Override
284 protected TimeoutType featureValueOf(PageElement pageElement)
285 {
286 return WebDriverElement.class.cast(pageElement).getDefaultTimeout();
287 }
288 };
289 }
290
291 private static Matcher<RowWrapper> rowWithName(final String name)
292 {
293 return new FeatureMatcher<RowWrapper, String>(equalTo(name), "row name", "name")
294 {
295 @Override
296 protected String featureValueOf(RowWrapper rowWrapper)
297 {
298 return rowWrapper.getName();
299 }
300 };
301 }
302
303 public static class RowWrapper
304 {
305 private final PageElement row;
306
307 public RowWrapper(PageElement element)
308 {
309 this.row = element;
310 }
311
312 String getName()
313 {
314 return getDataAttribute("name").apply(row);
315 }
316 }
317 }