Skip to content

Commit 63c2da2

Browse files
authored
Update capabilities to support mobile browsers (#287)
1 parent 50fa862 commit 63c2da2

File tree

19 files changed

+174
-52
lines changed

19 files changed

+174
-52
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ repositories {
238238
dependencies {
239239
constraints {
240240
api 'com.nordstrom.tools:java-utils:3.4.1'
241-
api 'com.nordstrom.tools:settings:3.0.7'
242-
api 'com.nordstrom.tools:junit-foundation:17.2.2'
241+
api 'com.nordstrom.tools:settings:3.0.8'
242+
api 'com.nordstrom.tools:junit-foundation:17.2.4'
243243
api 'com.github.sbabcoc:logback-testng:2.0.1'
244244
api 'org.hamcrest:hamcrest-core:3.0'
245245
api 'org.yaml:snakeyaml:2.4'

selenium3Deps.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ sourceSets {
2424

2525
dependencies {
2626
constraints {
27-
api 'com.nordstrom.tools:testng-foundation:5.1.3-j8'
27+
api 'com.nordstrom.tools:testng-foundation:5.2.1-j8'
2828
api 'org.seleniumhq.selenium:selenium-server:3.141.59'
2929
api 'org.seleniumhq.selenium:selenium-support:3.141.59'
3030
api 'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59'

selenium4Deps.gradle

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ sourceSets {
2424

2525
dependencies {
2626
constraints {
27-
api 'com.nordstrom.tools:testng-foundation:5.1.3-j11'
28-
api 'org.seleniumhq.selenium:selenium-grid:4.30.0'
29-
api 'org.seleniumhq.selenium:selenium-support:4.30.0'
30-
api 'org.seleniumhq.selenium:selenium-chrome-driver:4.30.0'
31-
api 'org.seleniumhq.selenium:selenium-edge-driver:4.30.0'
32-
api 'org.seleniumhq.selenium:selenium-firefox-driver:4.30.0'
27+
api 'com.nordstrom.tools:testng-foundation:5.2.1-j11'
28+
api 'org.seleniumhq.selenium:selenium-grid:4.32.0'
29+
api 'org.seleniumhq.selenium:selenium-support:4.32.0'
30+
api 'org.seleniumhq.selenium:selenium-chrome-driver:4.32.0'
31+
api 'org.seleniumhq.selenium:selenium-edge-driver:4.32.0'
32+
api 'org.seleniumhq.selenium:selenium-firefox-driver:4.32.0'
3333
api 'org.seleniumhq.selenium:selenium-opera-driver:4.4.0'
34-
api 'org.seleniumhq.selenium:selenium-safari-driver:4.30.0'
35-
api 'com.nordstrom.ui-tools:htmlunit-remote:4.30.0'
34+
api 'org.seleniumhq.selenium:selenium-safari-driver:4.32.0'
35+
api 'com.nordstrom.ui-tools:htmlunit-remote:4.30.1'
3636
api 'org.seleniumhq.selenium:htmlunit3-driver:4.30.0'
3737
api 'org.htmlunit:htmlunit:4.11.1'
3838
api 'com.codeborne:phantomjsdriver:1.5.0'

src/main/java/com/nordstrom/automation/selenium/core/GridUtility.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ public static HttpHost extractHost(URL url) {
310310
* @return IP address for the machine we're running on (a.k.a. - 'localhost')
311311
*/
312312
public static String getLocalHost() {
313-
return IDENTITY.getNonLoopbackAddressOfThisMachine();
313+
return IDENTITY.getIp4NonLoopbackAddressOfThisMachine().getHostAddress();
314314
}
315315

316316
/**

src/main/java/com/nordstrom/automation/selenium/core/JsUtility.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
* // Execute script as anonymous function, passing specified argument
5656
* WebElement response = JsUtility.runAndReturn(driver, script, name);
5757
* // If element reference was returned, extract 'content' attribute
58-
* return (response == null) ? null : response.getAttribute("content");
58+
* return (response == null) ? null : WebDriverUtils.getDomAttributeOf(response, "content");
5959
* }
6060
* }</code></pre>
6161
*
@@ -64,7 +64,7 @@
6464
*
6565
* <pre><code> var found = document.getElementsByTagName("meta");
6666
* for (var i = 0; i &lt; found.length; i++) {
67-
* if (found[i].getAttribute("name") == arguments[0]) return found[i];
67+
* if (WebDriverUtils.getDomAttributeOf(found[i], "name") == arguments[0]) return found[i];
6868
* }
6969
* return null;</code></pre>
7070
*/

src/main/java/com/nordstrom/automation/selenium/examples/ExamplePage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ public boolean setInputValue(boolean value) {
362362
* @return input field value
363363
*/
364364
public String getInputValue() {
365-
return findElement(Using.INPUT).getAttribute("value");
365+
return getDomPropertyOfElement(Using.INPUT, "value");
366366
}
367367

368368
/**

src/main/java/com/nordstrom/automation/selenium/examples/ShadowRootComponent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public boolean setInputValue(String value) {
110110
* @return input field value
111111
*/
112112
public String getInputValue() {
113-
return findElement(Using.INPUT).getAttribute("value");
113+
return getDomPropertyOfElement(Using.INPUT, "value");
114114
}
115115

116116
/**

src/main/java/com/nordstrom/automation/selenium/examples/TableComponent.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.openqa.selenium.SearchContext;
88
import org.openqa.selenium.WebElement;
99

10+
import com.nordstrom.automation.selenium.core.WebDriverUtils;
1011
import com.nordstrom.automation.selenium.model.ComponentContainer;
1112
import com.nordstrom.automation.selenium.model.PageComponent;
1213
import com.nordstrom.automation.selenium.model.RobustWebElement;
@@ -115,7 +116,7 @@ private List<TableRowComponent> getTableRows() {
115116
* @return table component key
116117
*/
117118
public static Object getKey(SearchContext context) {
118-
return ((WebElement) context).getAttribute("id");
119+
return WebDriverUtils.getDomAttributeOf((WebElement) context, "id");
119120
}
120121

121122
/**

src/main/java/com/nordstrom/automation/selenium/model/ComponentContainer.java

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,50 @@ public RobustWebElement findOptional(final By by) {
373373
return (RobustWebElement) RobustElementFactory.getElement(this, by, RobustElementWrapper.OPTIONAL);
374374
}
375375

376+
/**
377+
* Get the value of the named DOM property of the first WebElement matching the specified locator constant.
378+
*
379+
* @param constant the locator constant
380+
* @param name the name of the property
381+
* @return the property's current value or {@code null} if the value is not set
382+
*/
383+
public String getDomPropertyOfElement(final ByEnum constant, final String name) {
384+
return getDomPropertyOfElement(constant.locator(), name);
385+
}
386+
387+
/**
388+
* Get the value of the named DOM property of the first WebElement matching the specified locator.
389+
*
390+
* @param by the locating mechanism
391+
* @param name the name of the property
392+
* @return the property's current value or {@code null} if the value is not set
393+
*/
394+
public String getDomPropertyOfElement(final By by, final String name) {
395+
return WebDriverUtils.getDomPropertyOf(findElement(by), name);
396+
}
397+
398+
/**
399+
* Get the value of the named DOM attribute of the first WebElement matching the specified locator constant.
400+
*
401+
* @param constant the locator constant
402+
* @param name the name of the attribute
403+
* @return the attribute's value or {@code null} if the value is not set
404+
*/
405+
public String getDomAttributeOfElement(final ByEnum constant, final String name) {
406+
return getDomAttributeOfElement(constant.locator(), name);
407+
}
408+
409+
/**
410+
* Get the value of the named DOM attribute of the first WebElement matching the specified locator.
411+
*
412+
* @param by the locating mechanism
413+
* @param name the name of the attribute
414+
* @return the attribute's value or {@code null} if the value is not set
415+
*/
416+
public String getDomAttributeOfElement(final By by, final String name) {
417+
return WebDriverUtils.getDomAttributeOf(findElement(by), name);
418+
}
419+
376420
/**
377421
* Get the driver object associated with this container.
378422
*
@@ -394,7 +438,7 @@ public static boolean updateValue(final WebElement element, final boolean value)
394438
Objects.requireNonNull(element, ELEMENT_MESSAGE);
395439

396440
String tagName = element.getTagName().toLowerCase();
397-
if ("input".equals(tagName) && "checkbox".equals(element.getAttribute("type"))) {
441+
if ("input".equals(tagName) && "checkbox".equals(WebDriverUtils.getDomAttributeOf(element, "type"))) {
398442
if (element.isSelected() != value) {
399443
element.click();
400444
return true;
@@ -418,15 +462,15 @@ public static boolean updateValue(final WebElement element, final String value)
418462

419463
String tagName = element.getTagName().toLowerCase();
420464
if ("input".equals(tagName)) {
421-
if ("checkbox".equals(element.getAttribute("type"))) {
465+
if ("checkbox".equals(WebDriverUtils.getDomAttributeOf(element, "type"))) {
422466
return updateValue(element, Boolean.parseBoolean(value));
423467
} else if (!valueEquals(element, value)) {
424468
if (WebDriverUtils.isJavascriptEnabled(element)) {
425469
JsUtility.run(WebDriverUtils.getDriver(element), UPDATE_VALUE,
426470
element, (value != null) ? value : "");
427471
} else {
428472
StringBuilder keys = new StringBuilder();
429-
String exist = element.getAttribute("value");
473+
String exist = WebDriverUtils.getDomPropertyOf(element, "value");
430474
if (!(exist == null || exist.isEmpty())) {
431475
keys.append(Keys.END);
432476
for (int i = 0; i < exist.length(); i++) {
@@ -457,7 +501,7 @@ public static boolean updateValue(final WebElement element, final String value)
457501
private static boolean valueEquals(final WebElement element, final String value) {
458502
Objects.requireNonNull(element, ELEMENT_MESSAGE);
459503

460-
String exist = element.getAttribute("value");
504+
String exist = WebDriverUtils.getDomPropertyOf(element, "value");
461505
return (exist != null) ? exist.equals(value) : (value == null);
462506
}
463507

@@ -599,6 +643,7 @@ public <T extends Page> T openPageAtUrl(final Class<T> pageClass, final String u
599643
* @param url target URL or activity
600644
* @param driver driver object
601645
*/
646+
@SuppressWarnings("serial")
602647
public static void getUrl(final String url, final WebDriver driver) {
603648
Objects.requireNonNull(url, "[url] must be non-null");
604649
Objects.requireNonNull(driver, "[driver] must be non-null");

src/main/java/com/nordstrom/automation/selenium/platform/TargetType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ public enum TargetType implements TargetTypeName {
3030

3131
/**
3232
* target: web application<br>
33-
* driver: {@link RemoteWebDriverPlugin}
33+
* driver: {@link RemoteWebDriverPlugin}, {@link UiAutomator2Plugin}
3434
*/
35-
WEB_APP(WEB_APP_NAME, RemoteWebDriverPlugin.class),
35+
WEB_APP(WEB_APP_NAME, RemoteWebDriverPlugin.class, UiAutomator2Plugin.class),
3636

3737
/**
3838
* target: Android application<br>

src/main/java/com/nordstrom/automation/selenium/plugins/UiAutomator2Plugin.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,27 @@ public UiAutomator2Plugin() {
2222
}
2323

2424
private static final String CAPABILITIES =
25-
"{\"appium:automationName\":\"UiAutomator2\",\"platformName\":\"Android\"," +
26-
"\"browserName\":\"Chrome\",\"appium:deviceName\":\"Android Emulator\"}";
25+
"{\"appium:automationName\":\"UiAutomator2\",\"platformName\":\"Android\"}," +
26+
"{\"appium:automationName\":\"UiAutomator2\",\"platformName\":\"Android\",\"browserName\":\"chrome\"}";
2727

2828
private static final String BASELINE =
2929
"{\"appium:automationName\":\"UiAutomator2\",\"platformName\":\"Android\"," +
3030
"\"nord:options\":{\"personality\":\"UiAutomator2\"," +
3131
"\"pluginClass\":\"com.nordstrom.automation.selenium.plugins.UiAutomator2Plugin\"}}";
3232

33+
private static final String CHROME =
34+
"{\"appium:automationName\":\"UiAutomator2\",\"platformName\":\"Android\",\"browserName\":\"chrome\"," +
35+
"\"nord:options\":{\"personality\":\"UiAutomator2.chrome\"," +
36+
"\"pluginClass\":\"com.nordstrom.automation.selenium.plugins.UiAutomator2Plugin\"}}";
37+
3338
private static final Map<String, String> PERSONALITIES;
3439

3540
private static final String DRIVER_CLASS_NAME = "io.appium.java_client.android.AndroidDriver";
3641

3742
static {
3843
Map<String, String> personalities = new HashMap<>();
3944
personalities.put(DRIVER_NAME, BASELINE);
45+
personalities.put(DRIVER_NAME + ".chrome", CHROME);
4046
PERSONALITIES = Collections.unmodifiableMap(personalities);
4147
}
4248

src/main/java/com/nordstrom/automation/selenium/support/Coordinators.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ public static Coordinator<Boolean> textToBePresentInElementValue(final By locato
607607
@Override
608608
public Boolean apply(SearchContext context) {
609609
try {
610-
String elementText = context.findElement(locator).getAttribute("value");
610+
String elementText = WebDriverUtils.getDomPropertyOf(context.findElement(locator), "value");
611611
return elementText != null && elementText.contains(text);
612612
} catch (StaleElementReferenceException | NoSuchElementException e) {
613613
return null;
@@ -653,7 +653,7 @@ public static Coordinator<Boolean> elementToHaveAttributeValue(final By locator,
653653
@Override
654654
public Boolean apply(SearchContext context) {
655655
try {
656-
String attrib = context.findElement(locator).getAttribute(attribute);
656+
String attrib = WebDriverUtils.getDomPropertyOf(context.findElement(locator), attribute);
657657
if (attrib != null) {
658658
return attrib.equals(value);
659659
} else {

src/main/java/com/nordstrom/automation/selenium/support/RetryAnalyzer.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,21 @@
33
import org.openqa.selenium.WebDriverException;
44
import org.testng.ITestResult;
55

6-
import com.nordstrom.automation.testng.RetryManager;
6+
import com.nordstrom.automation.testng.TestNGRetryAnalyzer;
77

88
/**
99
* This class implements a Selenium-specific <b>TestNG</b> retry analyzer.
1010
*/
11-
public class RetryAnalyzer extends RetryManager {
11+
public class RetryAnalyzer implements TestNGRetryAnalyzer {
1212

1313
/**
1414
* {@inheritDoc}
1515
* <p>
1616
* This implementation deems that a test that fails with an instance of {@link WebDriverException} is re-triable.
1717
*/
1818
@Override
19-
protected boolean isRetriable(ITestResult result) {
20-
if (result.getThrowable() instanceof WebDriverException) {
21-
return true;
22-
}
23-
return super.isRetriable(result);
19+
public boolean retry(ITestResult result) {
20+
return (result.getThrowable() instanceof WebDriverException);
2421
}
2522

2623
}

src/selenium3/java/com/nordstrom/automation/selenium/core/WebDriverUtils.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ public final class WebDriverUtils {
3939
TimeoutException.class));
4040

4141
private static final Pattern FRAMEWORK_PACKAGE = Pattern.compile(
42-
"^(?:sun\\.reflect|java\\.lang"
43-
+ "|org\\.(?:openqa|testng|junit|hamcrest)"
44-
+ "|com\\.nordstrom\\.automation\\.selenium)\\.");
45-
42+
"^(?:sun\\.reflect|java\\.lang"
43+
+ "|org\\.(?:openqa|testng|junit|hamcrest)"
44+
+ "|com\\.nordstrom\\.automation\\.selenium)\\.");
45+
4646
/**
4747
* Private constructor to prevent instantiation.
4848
*/
@@ -122,6 +122,30 @@ public static Capabilities getCapabilities(final SearchContext context) {
122122
return (driver instanceof HasCapabilities) ? ((HasCapabilities) driver).getCapabilities() : null;
123123
}
124124

125+
/**
126+
* Get the value of the named DOM property of the specified WebElement.
127+
*
128+
* @param element the target element
129+
* @param name the name of the property
130+
* @return the property's current value or {@code null} if the value is not set
131+
*/
132+
public static String getDomPropertyOf(final WebElement element, final String name) {
133+
String script = String.format("return arguments[0].%s;", name);
134+
return JsUtility.runAndReturn(getDriver(element), script, element);
135+
}
136+
137+
/**
138+
* Get the value of the named DOM attribute of the specified WebElement.
139+
*
140+
* @param element the target element
141+
* @param name the name of the attribute
142+
* @return the attribute's value or {@code null} if the value is not set
143+
*/
144+
public static String getDomAttributeOf(final WebElement element, final String name) {
145+
String script = String.format("return arguments[0].getAttribute('%s');", name);
146+
return JsUtility.runAndReturn(getDriver(element), script, element);
147+
}
148+
125149
/**
126150
* Remove hidden elements from specified list.
127151
*

0 commit comments

Comments
 (0)