Skip to content

Commit 4a12de7

Browse files
Artem Koshelevsevaseva
Artem Koshelev
authored andcommitted
Provide ability to use custom annotations
This change simplify extending default Page Object implementation with custom annotations. AbstractAnnotations class provides basic methods for default annotations such as FindBy. It's extension can be passed now to existing element locators, so there is no need to implement them as well. Signed-off-by: Seva Lotoshnikov <[email protected]>
1 parent 3a2e29e commit 4a12de7

File tree

6 files changed

+284
-156
lines changed

6 files changed

+284
-156
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
Copyright 2007-2009 Selenium committers
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package org.openqa.selenium.support.pagefactory;
18+
19+
import java.util.HashSet;
20+
import java.util.Set;
21+
22+
import org.openqa.selenium.By;
23+
import org.openqa.selenium.support.ByIdOrName;
24+
import org.openqa.selenium.support.FindAll;
25+
import org.openqa.selenium.support.FindBy;
26+
import org.openqa.selenium.support.FindBys;
27+
import org.openqa.selenium.support.How;
28+
29+
/**
30+
* Abstract class to work with fields in Page Objects.
31+
* Provides methods to process {@link org.openqa.selenium.support.FindBy},
32+
* {@link org.openqa.selenium.support.FindBys} and
33+
* {@link org.openqa.selenium.support.FindAll} annotations.
34+
*/
35+
public abstract class AbstractAnnotations {
36+
37+
/**
38+
* Defines how to transform given object (field, class, etc)
39+
* into {@link org.openqa.selenium.By} class used by webdriver to locate elements.
40+
*/
41+
public abstract By buildBy();
42+
43+
/**
44+
* Defines whether or not given element
45+
* should be returned from cache on further calls.
46+
*/
47+
public abstract boolean isLookupCached();
48+
49+
protected By buildByFromFindBys(FindBys findBys) {
50+
assertValidFindBys(findBys);
51+
52+
FindBy[] findByArray = findBys.value();
53+
By[] byArray = new By[findByArray.length];
54+
for (int i = 0; i < findByArray.length; i++) {
55+
byArray[i] = buildByFromFindBy(findByArray[i]);
56+
}
57+
58+
return new ByChained(byArray);
59+
}
60+
61+
protected By buildBysFromFindByOneOf(FindAll findBys) {
62+
assertValidFindAll(findBys);
63+
64+
FindBy[] findByArray = findBys.value();
65+
By[] byArray = new By[findByArray.length];
66+
for (int i = 0; i < findByArray.length; i++) {
67+
byArray[i] = buildByFromFindBy(findByArray[i]);
68+
}
69+
70+
return new ByAll(byArray);
71+
}
72+
73+
protected By buildByFromFindBy(FindBy findBy) {
74+
assertValidFindBy(findBy);
75+
76+
By ans = buildByFromShortFindBy(findBy);
77+
if (ans == null) {
78+
ans = buildByFromLongFindBy(findBy);
79+
}
80+
81+
return ans;
82+
}
83+
84+
protected By buildByFromLongFindBy(FindBy findBy) {
85+
How how = findBy.how();
86+
String using = findBy.using();
87+
88+
switch (how) {
89+
case CLASS_NAME:
90+
return By.className(using);
91+
92+
case CSS:
93+
return By.cssSelector(using);
94+
95+
case ID:
96+
return By.id(using);
97+
98+
case ID_OR_NAME:
99+
return new ByIdOrName(using);
100+
101+
case LINK_TEXT:
102+
return By.linkText(using);
103+
104+
case NAME:
105+
return By.name(using);
106+
107+
case PARTIAL_LINK_TEXT:
108+
return By.partialLinkText(using);
109+
110+
case TAG_NAME:
111+
return By.tagName(using);
112+
113+
case XPATH:
114+
return By.xpath(using);
115+
116+
default:
117+
// Note that this shouldn't happen (eg, the above matches all
118+
// possible values for the How enum)
119+
throw new IllegalArgumentException("Cannot determine how to locate element ");
120+
}
121+
}
122+
123+
protected By buildByFromShortFindBy(FindBy findBy) {
124+
if (!"".equals(findBy.className()))
125+
return By.className(findBy.className());
126+
127+
if (!"".equals(findBy.css()))
128+
return By.cssSelector(findBy.css());
129+
130+
if (!"".equals(findBy.id()))
131+
return By.id(findBy.id());
132+
133+
if (!"".equals(findBy.linkText()))
134+
return By.linkText(findBy.linkText());
135+
136+
if (!"".equals(findBy.name()))
137+
return By.name(findBy.name());
138+
139+
if (!"".equals(findBy.partialLinkText()))
140+
return By.partialLinkText(findBy.partialLinkText());
141+
142+
if (!"".equals(findBy.tagName()))
143+
return By.tagName(findBy.tagName());
144+
145+
if (!"".equals(findBy.xpath()))
146+
return By.xpath(findBy.xpath());
147+
148+
// Fall through
149+
return null;
150+
}
151+
152+
private void assertValidFindBys(FindBys findBys) {
153+
for (FindBy findBy : findBys.value()) {
154+
assertValidFindBy(findBy);
155+
}
156+
}
157+
158+
private void assertValidFindAll(FindAll findBys) {
159+
for (FindBy findBy : findBys.value()) {
160+
assertValidFindBy(findBy);
161+
}
162+
}
163+
164+
private void assertValidFindBy(FindBy findBy) {
165+
if (findBy.how() != null) {
166+
if (findBy.using() == null) {
167+
throw new IllegalArgumentException(
168+
"If you set the 'how' property, you must also set 'using'");
169+
}
170+
}
171+
172+
Set<String> finders = new HashSet<String>();
173+
if (!"".equals(findBy.using())) finders.add("how: " + findBy.using());
174+
if (!"".equals(findBy.className())) finders.add("class name:" + findBy.className());
175+
if (!"".equals(findBy.css())) finders.add("css:" + findBy.css());
176+
if (!"".equals(findBy.id())) finders.add("id: " + findBy.id());
177+
if (!"".equals(findBy.linkText())) finders.add("link text: " + findBy.linkText());
178+
if (!"".equals(findBy.name())) finders.add("name: " + findBy.name());
179+
if (!"".equals(findBy.partialLinkText()))
180+
finders.add("partial link text: " + findBy.partialLinkText());
181+
if (!"".equals(findBy.tagName())) finders.add("tag name: " + findBy.tagName());
182+
if (!"".equals(findBy.xpath())) finders.add("xpath: " + findBy.xpath());
183+
184+
// A zero count is okay: it means to look by name or id.
185+
if (finders.size() > 1) {
186+
throw new IllegalArgumentException(
187+
String.format("You must specify at most one location strategy. Number found: %d (%s)",
188+
finders.size(), finders.toString()));
189+
}
190+
}
191+
}

Diff for: java/client/src/org/openqa/selenium/support/pagefactory/AjaxElementLocator.java

+19-3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ public class AjaxElementLocator extends DefaultElementLocator {
4141
protected final int timeOutInSeconds;
4242
private final Clock clock;
4343

44+
/**
45+
* Use this constructor in order to process custom annotaions.
46+
*
47+
* @param context The context to use when finding the element
48+
* @param timeOutInSeconds How long to wait for the element to appear. Measured in seconds.
49+
* @param annotations AbstractAnnotations class implementation
50+
*/
51+
public AjaxElementLocator(SearchContext context, int timeOutInSeconds, AbstractAnnotations annotations) {
52+
this(new SystemClock(), context, timeOutInSeconds, annotations);
53+
}
54+
55+
public AjaxElementLocator(Clock clock, SearchContext context, int timeOutInSeconds,
56+
AbstractAnnotations annotations) {
57+
super(context, annotations);
58+
this.timeOutInSeconds = timeOutInSeconds;
59+
this.clock = clock;
60+
}
61+
4462
/**
4563
* Main constructor.
4664
*
@@ -53,9 +71,7 @@ public AjaxElementLocator(SearchContext searchContext, Field field, int timeOutI
5371
}
5472

5573
public AjaxElementLocator(Clock clock, SearchContext searchContext, Field field, int timeOutInSeconds) {
56-
super(searchContext, field);
57-
this.timeOutInSeconds = timeOutInSeconds;
58-
this.clock = clock;
74+
this(clock, searchContext, timeOutInSeconds, new Annotations(field));
5975
}
6076

6177
/**

0 commit comments

Comments
 (0)