Skip to content

Commit 02b5b64

Browse files
Merge pull request #556 from TikhomirovSergey/master
#552 FIX
2 parents c607ff2 + d940158 commit 02b5b64

12 files changed

Lines changed: 347 additions & 93 deletions

File tree

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

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package io.appium.java_client;
1818

1919
import static com.google.common.base.Preconditions.checkNotNull;
20+
import static io.appium.java_client.remote.MobileCapabilityType.AUTOMATION_NAME;
21+
import static io.appium.java_client.remote.MobileCapabilityType.PLATFORM_NAME;
22+
import static java.util.Optional.ofNullable;
2023

2124
import com.google.common.collect.ImmutableMap;
2225

@@ -71,6 +74,10 @@ public class AppiumDriver<T extends WebElement>
7174
private URL remoteAddress;
7275
private RemoteLocationContext locationContext;
7376
private ExecuteMethod executeMethod;
77+
private final String platformName;
78+
private final String automationName;
79+
private String currentContext;
80+
7481

7582
/**
7683
* @param executor is an instance of {@link org.openqa.selenium.remote.HttpCommandExecutor}
@@ -85,7 +92,35 @@ public AppiumDriver(HttpCommandExecutor executor, Capabilities capabilities) {
8592
locationContext = new RemoteLocationContext(executeMethod);
8693
super.setErrorHandler(errorHandler);
8794
this.remoteAddress = executor.getAddressOfRemoteServer();
88-
this.setElementConverter(new JsonToMobileElementConverter(this, getSessionDetails()));
95+
final AppiumDriver<?> driver = this;
96+
97+
HasSessionDetails hasSessionDetails = new HasSessionDetails() {
98+
@Override
99+
public Response execute(String driverCommand, Map<String, ?> parameters) {
100+
return driver.execute(driverCommand, parameters);
101+
}
102+
103+
@Override
104+
public Response execute(String driverCommand) {
105+
return driver.execute(driverCommand);
106+
}
107+
};
108+
109+
Object capabilityPlatform1 = getCapabilities().getCapability(PLATFORM_NAME);
110+
Object capabilityAutomation1 = getCapabilities().getCapability(AUTOMATION_NAME);
111+
112+
Object capabilityPlatform2 = capabilities.getCapability(PLATFORM_NAME);
113+
Object capabilityAutomation2 = capabilities.getCapability(AUTOMATION_NAME);
114+
115+
platformName = ofNullable(ofNullable(hasSessionDetails.getPlatformName())
116+
.orElse(capabilityPlatform1 != null ? String.valueOf(capabilityPlatform1) : null))
117+
.orElse(capabilityPlatform2 != null ? String.valueOf(capabilityPlatform2) : null);
118+
automationName = ofNullable(ofNullable(hasSessionDetails.getAutomationName())
119+
.orElse(capabilityAutomation1 != null ? String.valueOf(capabilityAutomation1) : null))
120+
.orElse(capabilityAutomation2 != null ? String.valueOf(capabilityAutomation2) : null);
121+
122+
this.setElementConverter(new JsonToMobileElementConverter(this, this));
123+
currentContext = getContext();
89124
}
90125

91126
public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities) {
@@ -137,7 +172,7 @@ public AppiumDriver(Capabilities desiredCapabilities) {
137172
protected static Capabilities substituteMobilePlatform(Capabilities originalCapabilities,
138173
String newPlatform) {
139174
DesiredCapabilities dc = new DesiredCapabilities(originalCapabilities);
140-
dc.setCapability(MobileCapabilityType.PLATFORM_NAME, newPlatform);
175+
dc.setCapability(PLATFORM_NAME, newPlatform);
141176
return dc;
142177
}
143178

@@ -317,6 +352,7 @@ public void zoom(int x, int y) {
317352
@Override public WebDriver context(String name) {
318353
checkNotNull(name, "Must supply a context name");
319354
execute(DriverCommand.SWITCH_TO_CONTEXT, ImmutableMap.of("name", name));
355+
currentContext = name;
320356
return this;
321357
}
322358

@@ -384,4 +420,19 @@ public void zoom(int x, int y) {
384420
public URL getRemoteAddress() {
385421
return remoteAddress;
386422
}
423+
424+
@Override public String getPlatformName() {
425+
return platformName;
426+
}
427+
428+
@Override public String getAutomationName() {
429+
return automationName;
430+
}
431+
432+
@Override public boolean isBrowser() {
433+
if (super.isBrowser()) {
434+
return true;
435+
}
436+
return !currentContext.toLowerCase().contains("NATIVE_APP".toLowerCase());
437+
}
387438
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package io.appium.java_client;
1818

1919
import static io.appium.java_client.MobileCommand.GET_SESSION;
20+
import static java.util.Optional.ofNullable;
21+
import static org.apache.commons.lang3.StringUtils.isBlank;
2022

2123
import com.google.common.collect.ImmutableMap;
2224

@@ -39,4 +41,22 @@ default Map<String, Object> getSessionDetails() {
3941
default Object getSessionDetail(String detail) {
4042
return getSessionDetails().get(detail);
4143
}
44+
45+
default String getPlatformName() {
46+
Object platformName = getSessionDetail("platformName");
47+
return ofNullable(platformName != null ? String.valueOf(platformName) : null).orElse(null);
48+
}
49+
50+
default String getAutomationName() {
51+
Object automationName = getSessionDetail("automationName");
52+
return ofNullable(automationName != null ? String.valueOf(automationName) : null).orElse(null);
53+
}
54+
55+
/**
56+
* @return is focus on browser or on native content.
57+
*/
58+
default boolean isBrowser() {
59+
Object browserName = getSessionDetail("browserName");
60+
return browserName != null && !isBlank(String.valueOf(browserName));
61+
}
4262
}

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

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.common.collect.Lists;
2323
import com.google.common.collect.Maps;
2424

25+
import io.appium.java_client.HasSessionDetails;
2526
import org.openqa.selenium.WebDriverException;
2627
import org.openqa.selenium.remote.RemoteWebDriver;
2728
import org.openqa.selenium.remote.RemoteWebElement;
@@ -37,25 +38,17 @@
3738
*/
3839
public class JsonToMobileElementConverter extends JsonToWebElementConverter {
3940

40-
private static final String AUTOMATION_NAME_PARAMETER = "automationName";
41-
private static final String PLATFORM_NAME_PARAMETER = "platformName";
42-
43-
4441
protected final RemoteWebDriver driver;
45-
private final String automation;
46-
private final String platform;
42+
private final HasSessionDetails hasSessionDetails;
4743

4844
/**
4945
* @param driver an instance of {@link org.openqa.selenium.remote.RemoteWebDriver} subclass
50-
* @param sessionParameters the map of current session parameters
46+
* @param hasSessionDetails object that has session details
5147
*/
52-
public JsonToMobileElementConverter(RemoteWebDriver driver, Map<String, Object> sessionParameters) {
48+
public JsonToMobileElementConverter(RemoteWebDriver driver, HasSessionDetails hasSessionDetails) {
5349
super(driver);
5450
this.driver = driver;
55-
automation = String.valueOf(sessionParameters
56-
.get(AUTOMATION_NAME_PARAMETER)).toLowerCase();
57-
platform = String.valueOf(sessionParameters
58-
.get(PLATFORM_NAME_PARAMETER)).toLowerCase();
51+
this.hasSessionDetails = hasSessionDetails;
5952
}
6053

6154
/**
@@ -93,8 +86,14 @@ public Object apply(Object result) {
9386
}
9487

9588
protected RemoteWebElement newMobileElement() {
96-
Class<? extends RemoteWebElement> target =
97-
getElementClass(platform, automation);
89+
Class<? extends RemoteWebElement> target;
90+
if (hasSessionDetails.isBrowser()) {
91+
target = getElementClass(null, null);
92+
} else {
93+
target = getElementClass(hasSessionDetails.getPlatformName(),
94+
hasSessionDetails.getAutomationName());
95+
}
96+
9897
try {
9998
Constructor<? extends RemoteWebElement> constructor = target.getDeclaredConstructor();
10099
constructor.setAccessible(true);

src/main/java/io/appium/java_client/pagefactory/AppiumFieldDecorator.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import java.util.List;
4848
import java.util.Map;
4949
import java.util.concurrent.TimeUnit;
50+
import java.util.function.Supplier;
5051

5152
/**
5253
* Default decorator for use with PageFactory. Will decorate 1) all of the
@@ -72,7 +73,7 @@ public class AppiumFieldDecorator implements FieldDecorator {
7273
private final String automation;
7374
private final TimeOutDuration timeOutDuration;
7475

75-
private static String extractSessionData(WebDriver driver, String parameter) {
76+
private static String extractSessionData(WebDriver driver, Supplier<String> dataSupplier) {
7677
if (driver == null) {
7778
return null;
7879
}
@@ -81,7 +82,7 @@ private static String extractSessionData(WebDriver driver, String parameter) {
8182
return null;
8283
}
8384

84-
return String.valueOf(HasSessionDetails.class.cast(driver).getSessionDetail(parameter));
85+
return String.valueOf(dataSupplier.get());
8586
}
8687

8788
public AppiumFieldDecorator(SearchContext context, long implicitlyWaitTimeOut,
@@ -99,8 +100,10 @@ public AppiumFieldDecorator(SearchContext context, long implicitlyWaitTimeOut,
99100
*/
100101
public AppiumFieldDecorator(SearchContext context, TimeOutDuration timeOutDuration) {
101102
this.originalDriver = unpackWebDriverFromSearchContext(context);
102-
platform = extractSessionData(originalDriver, "platformName");
103-
automation = extractSessionData(originalDriver, "automationName");
103+
platform = extractSessionData(originalDriver, () ->
104+
HasSessionDetails.class.cast(originalDriver).getPlatformName());
105+
automation = extractSessionData(originalDriver, () ->
106+
HasSessionDetails.class.cast(originalDriver).getAutomationName());
104107
this.timeOutDuration = timeOutDuration;
105108

106109
defaultElementFieldDecoracor = new DefaultFieldDecorator(

src/test/java/io/appium/java_client/android/AndroidContextTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.appium.java_client.android;
1818

1919
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertTrue;
2021

2122
import io.appium.java_client.NoSuchContextException;
2223
import org.junit.BeforeClass;
@@ -46,6 +47,7 @@ public class AndroidContextTest extends BaseAndroidTest {
4647

4748
@Test(expected = NoSuchContextException.class) public void testContextError() {
4849
driver.context("Planet of the Ape-ium");
50+
assertTrue(driver.getContext().equals("Planet of the Ape-ium"));
4951
}
5052

5153
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package io.appium.java_client.appium.element.generation;
2+
3+
import static org.junit.Assert.assertTrue;
4+
5+
import io.appium.java_client.AppiumDriver;
6+
import io.appium.java_client.service.local.AppiumServiceBuilder;
7+
import org.junit.After;
8+
import org.openqa.selenium.By;
9+
import org.openqa.selenium.Capabilities;
10+
import org.openqa.selenium.WebElement;
11+
import org.openqa.selenium.remote.DesiredCapabilities;
12+
13+
import java.util.function.BiPredicate;
14+
import java.util.function.Supplier;
15+
16+
public class BaseElementGenerationTest {
17+
protected AppiumDriver<?> driver;
18+
protected final BiPredicate<By, Class<? extends WebElement>> commonPredicate = (by, aClass) -> {
19+
WebElement element = driver.findElement(by);
20+
assertTrue(element.getClass().equals(aClass));
21+
return true;
22+
};
23+
24+
@After
25+
public void tearDown() {
26+
if (driver != null) {
27+
driver.quit();
28+
}
29+
driver = null;
30+
}
31+
32+
protected boolean check(Supplier<DesiredCapabilities> serverCapabilitiesSupplier,
33+
Supplier<Capabilities> clientCapabilitiesSupplier,
34+
BiPredicate<By, Class<? extends WebElement>> filter,
35+
By by, Class<? extends WebElement> clazz) {
36+
AppiumServiceBuilder builder = new AppiumServiceBuilder()
37+
.withCapabilities(serverCapabilitiesSupplier.get());
38+
driver = new AppiumDriver<>(builder, clientCapabilitiesSupplier.get());
39+
return filter.test(by, clazz);
40+
}
41+
42+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package io.appium.java_client.appium.element.generation.android;
2+
3+
import static io.appium.java_client.MobileBy.AndroidUIAutomator;
4+
import static org.junit.Assert.assertTrue;
5+
import static org.openqa.selenium.By.className;
6+
import static org.openqa.selenium.By.tagName;
7+
8+
import io.appium.java_client.android.AndroidElement;
9+
import io.appium.java_client.appium.element.generation.BaseElementGenerationTest;
10+
import io.appium.java_client.remote.AndroidMobileCapabilityType;
11+
import io.appium.java_client.remote.MobileBrowserType;
12+
import io.appium.java_client.remote.MobileCapabilityType;
13+
import io.appium.java_client.remote.MobilePlatform;
14+
import org.junit.Test;
15+
import org.openqa.selenium.remote.DesiredCapabilities;
16+
import org.openqa.selenium.remote.RemoteWebElement;
17+
18+
import java.io.File;
19+
import java.util.function.Supplier;
20+
21+
public class AndroidElementGeneratingTest extends BaseElementGenerationTest {
22+
23+
private final File app = new File(new File("src/test/java/io/appium/java_client"),
24+
"ApiDemos-debug.apk");
25+
private final Supplier<DesiredCapabilities> serverCapabilitiesSupplier = () -> {
26+
DesiredCapabilities serverCapabilities = new DesiredCapabilities();
27+
serverCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.ANDROID);
28+
serverCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
29+
serverCapabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
30+
return serverCapabilities;
31+
};
32+
33+
@Test public void whenAndroidNativeAppIsLaunched() {
34+
assertTrue(check(serverCapabilitiesSupplier, () -> {
35+
DesiredCapabilities clientCapabilities = new DesiredCapabilities();
36+
clientCapabilities.setCapability(MobileCapabilityType.FULL_RESET, true);
37+
clientCapabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 60);
38+
return clientCapabilities;
39+
}, commonPredicate, AndroidUIAutomator("new UiSelector().clickable(true)"),
40+
AndroidElement.class));
41+
}
42+
43+
@Test public void whenAndroidHybridAppIsLaunched() {
44+
assertTrue(check(serverCapabilitiesSupplier, () -> {
45+
DesiredCapabilities clientCapabilities = new DesiredCapabilities();
46+
clientCapabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "io.appium.android.apis");
47+
clientCapabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, ".view.WebView1");
48+
return clientCapabilities;
49+
}, (by, aClass) -> {
50+
driver.context("WEBVIEW_io.appium.android.apis");
51+
return commonPredicate.test(by, aClass);
52+
}, tagName("a"), RemoteWebElement.class));
53+
}
54+
55+
@Test public void whenAndroidBrowserIsLaunched() {
56+
assertTrue(check(() -> {
57+
DesiredCapabilities serverCapabilities = new DesiredCapabilities();
58+
serverCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.ANDROID);
59+
serverCapabilities.setCapability(MobileCapabilityType.BROWSER_NAME, MobileBrowserType.BROWSER);
60+
return serverCapabilities;
61+
}, () -> {
62+
DesiredCapabilities clientCapabilities = new DesiredCapabilities();
63+
clientCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
64+
return clientCapabilities;
65+
}, (by, aClass) -> {
66+
driver.get("https://www.google.com");
67+
return commonPredicate.test(by, aClass);
68+
}, className("gsfi"), RemoteWebElement.class));
69+
}
70+
}

0 commit comments

Comments
 (0)