Skip to content

Commit 36a63fd

Browse files
Final improvements before 2.0.
Change log: - MobileElement has become abstract. It implements FindsByAccessibilityId - AndroidElement and IOSElement have been created. - AndroidElement implements FindsByAndroidAutomator. - IOSElement implements FindsByIosAutomation. - Both AppiumDriver and MobileElement implement ScrollsTo. Yeah! MobileElement is scrollable too! - PageFactory facilities are synchronized with changes above.
1 parent c8e81b6 commit 36a63fd

16 files changed

+266
-103
lines changed

pom.xml

+15-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,21 @@
3737
<artifactId>cglib</artifactId>
3838
<version>3.1</version>
3939
</dependency>
40-
40+
<dependency>
41+
<groupId>org.reflections</groupId>
42+
<artifactId>reflections</artifactId>
43+
<version>0.9.8</version>
44+
<exclusions>
45+
<exclusion>
46+
<artifactId>guava</artifactId>
47+
<groupId>com.google.guava</groupId>
48+
</exclusion>
49+
<exclusion>
50+
<artifactId>xml-apis</artifactId>
51+
<groupId>xml-apis</groupId>
52+
</exclusion>
53+
</exclusions>
54+
</dependency>
4155
</dependencies>
4256
<packaging>jar</packaging>
4357
<name>java-client</name>

src/main/java/io/appium/java_client/AppiumDriver.java

+2-19
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import com.google.common.collect.ImmutableMap;
2222
import com.google.gson.JsonObject;
2323
import com.google.gson.JsonParser;
24-
import io.appium.java_client.internal.JsonToMobileElementConverter;
2524
import io.appium.java_client.remote.MobileCapabilityType;
2625
import org.openqa.selenium.*;
2726
import org.openqa.selenium.html5.Location;
@@ -42,7 +41,7 @@
4241
public abstract class AppiumDriver extends RemoteWebDriver implements MobileDriver,
4342
ContextAware, Rotatable, FindsByAccessibilityId, LocationContext,
4443
DeviceActionShortcuts, TouchShortcuts, InteractsWithFiles,
45-
InteractsWithApps {
44+
InteractsWithApps, ScrollsTo {
4645

4746
private final static ErrorHandler errorHandler = new ErrorHandler(
4847
new ErrorCodesMobile(), true);
@@ -106,7 +105,6 @@ protected static ImmutableMap<String, Object> getCommandImmutableMap(
106105
public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities) {
107106

108107
super(remoteAddress, desiredCapabilities);
109-
this.setElementConverter(new JsonToMobileElementConverter(this));
110108

111109
this.executeMethod = new AppiumExecutionMethod(this);
112110
this.remoteAddress = remoteAddress;
@@ -525,22 +523,7 @@ public void lockScreen(int seconds) {
525523
execute(LOCK, ImmutableMap.of("seconds", seconds));
526524
}
527525

528-
/**
529-
* Scroll to an element which contains the given text.
530-
* Implemented differently on iOS and Android, see docs for individual methods.
531-
* @param text
532-
*/
533-
public abstract void scrollTo(String text);
534-
535-
/**
536-
* Scroll to an element with the given text.
537-
* Implemented differently on iOS and Android, see docs for individual methods.
538-
* @param text
539-
*/
540-
public abstract void scrollToExact(String text);
541-
542-
543-
@Override
526+
@Override
544527
public WebDriver context(String name) {
545528
if (!_isNotNullOrEmpty(name)) {
546529
throw new IllegalArgumentException("Must supply a context name");

src/main/java/io/appium/java_client/MobileElement.java

+1-18
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727

2828
import java.util.List;
2929

30-
public class MobileElement extends RemoteWebElement implements FindsByAccessibilityId, FindsByAndroidUIAutomator,
31-
FindsByIosUIAutomation {
30+
public abstract class MobileElement extends RemoteWebElement implements FindsByAccessibilityId, ScrollsTo {
3231

3332
protected FileDetector fileDetector;
3433

@@ -40,22 +39,6 @@ public WebElement findElement(By by) {
4039
return by.findElement(this);
4140
}
4241

43-
public WebElement findElementByIosUIAutomation(String using) {
44-
return findElement("-ios uiautomation", using);
45-
}
46-
47-
public List<WebElement> findElementsByIosUIAutomation(String using) {
48-
return findElements("-ios uiautomation", using);
49-
}
50-
51-
public WebElement findElementByAndroidUIAutomator(String using) {
52-
return findElement("-android uiautomator", using);
53-
}
54-
55-
public List<WebElement> findElementsByAndroidUIAutomator(String using) {
56-
return findElements("-android uiautomator", using);
57-
}
58-
5942
public WebElement findElementByAccessibilityId(String using) {
6043
return findElement("accessibility id", using);
6144
}

src/main/java/io/appium/java_client/ScrollsTo.java

+8
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22

33
public interface ScrollsTo {
44

5+
/**
6+
* Scroll to an element which contains the given text.
7+
* @param text
8+
*/
59
public MobileElement scrollTo(String text);
610

11+
/**
12+
* Scroll to an element with the given text.
13+
* @param text
14+
*/
715
public MobileElement scrollToExact(String text);
816

917
}

src/main/java/io/appium/java_client/android/AndroidDriver.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import io.appium.java_client.AppiumDriver;
66
import io.appium.java_client.AppiumSetting;
77
import io.appium.java_client.FindsByAndroidUIAutomator;
8+
import io.appium.java_client.MobileElement;
89
import io.appium.java_client.NetworkConnectionSetting;
10+
import io.appium.java_client.android.internal.JsonToAndroidElementConverter;
911
import io.appium.java_client.remote.MobilePlatform;
1012

1113
import org.openqa.selenium.Capabilities;
@@ -37,6 +39,7 @@ public class AndroidDriver extends AppiumDriver implements
3739
public AndroidDriver(URL remoteAddress, Capabilities desiredCapabilities) {
3840
super(remoteAddress, substituteMobilePlatform(desiredCapabilities,
3941
ANDROID_PLATFORM));
42+
this.setElementConverter(new JsonToAndroidElementConverter(this));
4043
}
4144

4245
/**
@@ -45,10 +48,10 @@ public AndroidDriver(URL remoteAddress, Capabilities desiredCapabilities) {
4548
* @param text
4649
*/
4750
@Override
48-
public void scrollTo(String text) {
51+
public MobileElement scrollTo(String text) {
4952
String uiScrollables = UiScrollable("new UiSelector().descriptionContains(\"" + text + "\")") +
5053
UiScrollable("new UiSelector().textContains(\"" + text + "\")");
51-
findElementByAndroidUIAutomator(uiScrollables);
54+
return (MobileElement) findElementByAndroidUIAutomator(uiScrollables);
5255
}
5356

5457
/**
@@ -57,13 +60,13 @@ public void scrollTo(String text) {
5760
* @param text
5861
*/
5962
@Override
60-
public void scrollToExact(String text) {
63+
public MobileElement scrollToExact(String text) {
6164
String uiScrollables = UiScrollable("new UiSelector().description(\"" + text + "\")") +
6265
UiScrollable("new UiSelector().text(\"" + text + "\")");
63-
findElementByAndroidUIAutomator(uiScrollables);
66+
return (MobileElement) findElementByAndroidUIAutomator(uiScrollables);
6467
}
6568

66-
private String UiScrollable(String uiSelector) {
69+
static String UiScrollable(String uiSelector) {
6770
return "new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(" + uiSelector + ".instance(0));";
6871
}
6972

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package io.appium.java_client.android;
2+
3+
import java.util.List;
4+
5+
import org.openqa.selenium.WebElement;
6+
7+
import io.appium.java_client.FindsByAndroidUIAutomator;
8+
import io.appium.java_client.MobileElement;
9+
10+
public class AndroidElement extends MobileElement implements
11+
FindsByAndroidUIAutomator {
12+
13+
@Override
14+
public WebElement findElementByAndroidUIAutomator(String using) {
15+
return findElement("-android uiautomator", using);
16+
}
17+
18+
@Override
19+
public List<WebElement> findElementsByAndroidUIAutomator(String using) {
20+
return findElements("-android uiautomator", using);
21+
}
22+
23+
/**
24+
* Scroll forward to the element which has a description or name which contains the input text.
25+
* The scrolling is performed on the first scrollView present on the UI
26+
* @param text
27+
*/
28+
@Override
29+
public MobileElement scrollTo(String text) {
30+
String uiScrollables = AndroidDriver.UiScrollable("new UiSelector().descriptionContains(\"" + text + "\")") +
31+
AndroidDriver.UiScrollable("new UiSelector().textContains(\"" + text + "\")");
32+
return (MobileElement) findElementByAndroidUIAutomator(uiScrollables);
33+
}
34+
35+
/**
36+
* Scroll forward to the element which has a description or name which exactly matches the input text.
37+
* The scrolling is performed on the first scrollView present on the UI
38+
* @param text
39+
*/
40+
@Override
41+
public MobileElement scrollToExact(String text) {
42+
String uiScrollables = AndroidDriver.UiScrollable("new UiSelector().description(\"" + text + "\")") +
43+
AndroidDriver.UiScrollable("new UiSelector().text(\"" + text + "\")");
44+
return (MobileElement) findElementByAndroidUIAutomator(uiScrollables);
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.appium.java_client.android.internal;
2+
3+
import io.appium.java_client.AppiumDriver;
4+
import io.appium.java_client.MobileElement;
5+
import io.appium.java_client.android.AndroidElement;
6+
import io.appium.java_client.internal.JsonToMobileElementConverter;
7+
8+
public class JsonToAndroidElementConverter extends JsonToMobileElementConverter {
9+
10+
public JsonToAndroidElementConverter(AppiumDriver driver) {
11+
super(driver);
12+
}
13+
14+
@Override
15+
protected MobileElement newMobileElement() {
16+
AndroidElement toReturn = new AndroidElement();
17+
toReturn.setParent(driver);
18+
return toReturn;
19+
}
20+
21+
}

src/main/java/io/appium/java_client/internal/JsonToMobileElementConverter.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
* Reconstitutes {@link WebElement}s from their JSON representation. Will recursively convert Lists
1818
* and Maps to catch nested references. All other values pass through the converter unchanged.
1919
*/
20-
public class JsonToMobileElementConverter extends JsonToWebElementConverter {
21-
private AppiumDriver driver;
20+
public abstract class JsonToMobileElementConverter extends JsonToWebElementConverter {
21+
protected AppiumDriver driver;
2222

2323
public JsonToMobileElementConverter(AppiumDriver driver) {
2424
super(driver);
@@ -53,9 +53,9 @@ public Object apply(Object result) {
5353
return result;
5454
}
5555

56-
protected MobileElement newMobileElement() {
57-
MobileElement toReturn = new MobileElement();
58-
toReturn.setParent(driver);
59-
return toReturn;
60-
}
56+
protected abstract MobileElement newMobileElement(); //{
57+
//MobileElement toReturn = new MobileElement();
58+
//toReturn.setParent(driver);
59+
//return toReturn;
60+
//}
6161
}

src/main/java/io/appium/java_client/ios/IOSDriver.java

+12-36
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.appium.java_client.AppiumDriver;
66
import io.appium.java_client.FindsByIosUIAutomation;
77
import io.appium.java_client.MobileElement;
8+
import io.appium.java_client.ios.internal.JsonToIOSElementConverter;
89
import io.appium.java_client.remote.MobilePlatform;
910

1011
import org.openqa.selenium.Capabilities;
@@ -21,55 +22,30 @@ public class IOSDriver extends AppiumDriver implements IOSDeviceActionShortcuts,
2122
public IOSDriver(URL remoteAddress, Capabilities desiredCapabilities) {
2223
super(remoteAddress, substituteMobilePlatform(desiredCapabilities,
2324
IOS_PLATFORM));
25+
this.setElementConverter(new JsonToIOSElementConverter(this));
2426
}
2527

2628
/**
2729
* Scroll to the element whose 'text' attribute contains the input text.
2830
* This scrolling happens within the first UIATableView on the UI. Use the additional 'context' param to specify a different scrollView.
2931
* @param text input text contained in text attribute
3032
*/
31-
@Override
32-
public void scrollTo(String text) {
33-
scrollTo(text, (MobileElement) findElementByClassName("UIATableView"));
34-
}
33+
@Override
34+
public MobileElement scrollTo(String text) {
35+
return ((MobileElement) findElementByClassName("UIATableView")).scrollTo(text);
36+
}
3537

36-
/**
38+
/**
3739
* Scroll to the element whose 'text' attribute is equal to the input text.
3840
* This scrolling happens within the first UIATableView on the UI. Use the additional 'context' param to specify a different scrollView.
3941
* @param text input text to match
4042
*/
41-
@Override
42-
public void scrollToExact(String text) {
43-
scrollToExact(text, (MobileElement) findElementByClassName("UIATableView"));
44-
}
45-
46-
/**
47-
* Scroll to the element whose 'text' attribute contains the input text.
48-
* @param text input text contained in text attribute
49-
* @param context container element to scroll within
50-
*/
51-
public void scrollTo(String text, MobileElement context) {
52-
context.findElementByIosUIAutomation(".scrollToElementWithPredicate(\"name CONTAINS '" + text + "'\")");
53-
}
54-
55-
/**
56-
* Scroll to the element whose 'text' attribute is equal to the input text.
57-
* @param text input text to match
58-
* @param context container element to scroll within
59-
*/
60-
public void scrollToExact(String text, MobileElement context) {
61-
context.findElementByIosUIAutomation(".scrollToElementWithName(\"" + text + "\")");
62-
}
63-
64-
/**
65-
* Scroll to the given element.
66-
* This scrolling happens within the first UIATableView on the UI. Use the ScrollToExactWithinContext() method to specify a different scrollView.
67-
*/
68-
public void scrollTo(WebElement el) {
69-
scrollToExact(el.getText());
70-
}
43+
@Override
44+
public MobileElement scrollToExact(String text) {
45+
return ((MobileElement) findElementByClassName("UIATableView")).scrollToExact(text);
46+
}
7147

72-
/**
48+
/**
7349
* @see IOSDeviceActionShortcuts#hideKeyboard(String, String)
7450
*/
7551
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.appium.java_client.ios;
2+
3+
import java.util.List;
4+
5+
import org.openqa.selenium.WebElement;
6+
7+
import io.appium.java_client.FindsByIosUIAutomation;
8+
import io.appium.java_client.MobileElement;
9+
10+
public class IOSElement extends MobileElement implements FindsByIosUIAutomation{
11+
12+
@Override
13+
public WebElement findElementByIosUIAutomation(String using) {
14+
return findElement("-ios uiautomation", using);
15+
}
16+
17+
@Override
18+
public List<WebElement> findElementsByIosUIAutomation(String using) {
19+
return findElements("-ios uiautomation", using);
20+
}
21+
22+
@Override
23+
public MobileElement scrollTo(String text) {
24+
return (MobileElement) findElementByIosUIAutomation(".scrollToElementWithPredicate(\"name CONTAINS '" + text + "'\")");
25+
}
26+
27+
@Override
28+
public MobileElement scrollToExact(String text) {
29+
return (MobileElement) findElementByIosUIAutomation(".scrollToElementWithName(\"" + text + "\")");
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.appium.java_client.ios.internal;
2+
3+
import io.appium.java_client.AppiumDriver;
4+
import io.appium.java_client.MobileElement;
5+
import io.appium.java_client.internal.JsonToMobileElementConverter;
6+
import io.appium.java_client.ios.IOSElement;
7+
8+
public class JsonToIOSElementConverter extends JsonToMobileElementConverter {
9+
10+
public JsonToIOSElementConverter(AppiumDriver driver) {
11+
super(driver);
12+
}
13+
14+
@Override
15+
protected MobileElement newMobileElement() {
16+
IOSElement toReturn = new IOSElement();
17+
toReturn.setParent(driver);
18+
return toReturn;
19+
}
20+
21+
}

0 commit comments

Comments
 (0)