Skip to content

Commit 5330470

Browse files
fix: Avoid using getSession call for capability values retrieval
1 parent 7239a9d commit 5330470

File tree

14 files changed

+122
-47
lines changed

14 files changed

+122
-47
lines changed

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
import static com.google.common.base.Preconditions.checkNotNull;
2020
import static io.appium.java_client.remote.MobileCapabilityType.PLATFORM_NAME;
2121
import static org.apache.commons.lang3.StringUtils.containsIgnoreCase;
22+
import static org.apache.commons.lang3.StringUtils.isBlank;
2223

2324
import com.google.common.collect.ImmutableMap;
2425

26+
import io.appium.java_client.internal.CapabilityHelpers;
2527
import io.appium.java_client.internal.JsonToMobileElementConverter;
2628
import io.appium.java_client.remote.AppiumCommandExecutor;
2729
import io.appium.java_client.remote.MobileCapabilityType;
@@ -88,7 +90,7 @@ public AppiumDriver(HttpCommandExecutor executor, Capabilities capabilities) {
8890
locationContext = new RemoteLocationContext(executeMethod);
8991
super.setErrorHandler(errorHandler);
9092
this.remoteAddress = executor.getAddressOfRemoteServer();
91-
this.setElementConverter(new JsonToMobileElementConverter(this, this));
93+
this.setElementConverter(new JsonToMobileElementConverter(this));
9294
}
9395

9496
public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities) {
@@ -314,8 +316,19 @@ public URL getRemoteAddress() {
314316

315317
@Override
316318
public boolean isBrowser() {
317-
return super.isBrowser()
318-
&& !containsIgnoreCase(getContext(), "NATIVE_APP");
319+
String browserName = CapabilityHelpers.getCapability(getCapabilities(), "browserName", String.class);
320+
if (!isBlank(browserName)) {
321+
try {
322+
return (boolean) executeScript("return !!window.navigator;");
323+
} catch (WebDriverException ign) {
324+
// ignore
325+
}
326+
}
327+
try {
328+
return !containsIgnoreCase(getContext(), "NATIVE_APP");
329+
} catch (WebDriverException e) {
330+
return false;
331+
}
319332
}
320333

321334
@Override
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* See the NOTICE file distributed with this work for additional
5+
* information regarding copyright ownership.
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 io.appium.java_client.internal;
18+
19+
import org.openqa.selenium.Capabilities;
20+
21+
import javax.annotation.Nullable;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
public class CapabilityHelpers {
26+
public static final String APPIUM_PREFIX = "appium:";
27+
28+
/**
29+
* Helper that is used for capability values retrieval.
30+
* Supports both prefixed W3C and "classic" capability names.
31+
*
32+
* @param caps driver caps object
33+
* @param name capability name
34+
* @param expectedType the expected capability type
35+
* @return The retrieved capability value or null if the cap either not present has an unexpected type
36+
*/
37+
@Nullable
38+
public static <T> T getCapability(Capabilities caps, String name, Class<T> expectedType) {
39+
List<String> possibleNames = new ArrayList<>();
40+
possibleNames.add(name);
41+
if (!name.startsWith(APPIUM_PREFIX)) {
42+
possibleNames.add(APPIUM_PREFIX + name);
43+
}
44+
for (String capName : possibleNames) {
45+
if (caps.getCapability(capName) != null
46+
&& expectedType.isAssignableFrom(caps.getCapability(capName).getClass())) {
47+
return expectedType.cast(caps.getCapability(capName));
48+
}
49+
}
50+
return null;
51+
}
52+
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,10 @@ public enum ElementMap {
5050
mobileElementMap = builder.build();
5151
}
5252

53-
54-
5553
private final String platformOrAutomation;
5654
private final Class<? extends RemoteWebElement> elementClass;
5755

58-
private ElementMap(String platformOrAutomation, Class<? extends MobileElement> elementClass) {
56+
ElementMap(String platformOrAutomation, Class<? extends MobileElement> elementClass) {
5957
this.platformOrAutomation = platformOrAutomation;
6058
this.elementClass = elementClass;
6159
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import static io.appium.java_client.internal.ElementMap.getElementClass;
2020

21-
import io.appium.java_client.HasSessionDetails;
21+
import org.openqa.selenium.Capabilities;
2222
import org.openqa.selenium.WebDriverException;
2323
import org.openqa.selenium.remote.RemoteWebDriver;
2424
import org.openqa.selenium.remote.RemoteWebElement;
@@ -41,20 +41,20 @@ public class JsonToMobileElementConverter extends JsonToWebElementConverter {
4141
* Creates a new instance based on {@code driver} and object with session details.
4242
*
4343
* @param driver an instance of {@link RemoteWebDriver} subclass
44-
* @param hasSessionDetails object that has session details
4544
*/
46-
public JsonToMobileElementConverter(RemoteWebDriver driver, HasSessionDetails hasSessionDetails) {
45+
public JsonToMobileElementConverter(RemoteWebDriver driver) {
4746
super(driver);
4847
this.driver = driver;
49-
this.platform = hasSessionDetails.getPlatformName();
50-
this.automation = hasSessionDetails.getAutomationName();
48+
Capabilities caps = driver.getCapabilities();
49+
this.platform = CapabilityHelpers.getCapability(caps, "platformName", String.class);
50+
this.automation = CapabilityHelpers.getCapability(caps, "automationName", String.class);
5151
}
5252

5353
@Override
5454
public Object apply(Object result) {
5555
Object toBeReturned = result;
5656
if (toBeReturned instanceof RemoteWebElement) {
57-
toBeReturned = newRemoteWebElement();
57+
toBeReturned = newRemoteWebElement();
5858
((RemoteWebElement) toBeReturned).setId(((RemoteWebElement) result).getId());
5959
}
6060

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

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,22 @@
2020
import static io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy;
2121
import static io.appium.java_client.pagefactory.utils.WebDriverUnpackUtility.unpackWebDriverFromSearchContext;
2222
import static java.time.Duration.ofSeconds;
23-
import static java.util.Optional.ofNullable;
2423

2524
import com.google.common.collect.ImmutableList;
2625

27-
import io.appium.java_client.HasSessionDetails;
2826
import io.appium.java_client.MobileElement;
2927
import io.appium.java_client.android.AndroidElement;
28+
import io.appium.java_client.internal.CapabilityHelpers;
3029
import io.appium.java_client.ios.IOSElement;
3130
import io.appium.java_client.pagefactory.bys.ContentType;
3231
import io.appium.java_client.pagefactory.locator.CacheableLocator;
3332
import io.appium.java_client.windows.WindowsElement;
33+
import org.openqa.selenium.Capabilities;
34+
import org.openqa.selenium.HasCapabilities;
3435
import org.openqa.selenium.SearchContext;
3536
import org.openqa.selenium.WebDriver;
3637
import org.openqa.selenium.WebElement;
38+
import org.openqa.selenium.remote.RemoteWebDriver;
3739
import org.openqa.selenium.remote.RemoteWebElement;
3840
import org.openqa.selenium.support.pagefactory.DefaultFieldDecorator;
3941
import org.openqa.selenium.support.pagefactory.ElementLocator;
@@ -71,30 +73,24 @@ public class AppiumFieldDecorator implements FieldDecorator {
7173
private final String automation;
7274
private final Duration duration;
7375

74-
7576
/**
7677
* Creates field decorator based on {@link SearchContext} and timeout {@code duration}.
7778
*
78-
* @param context is an instance of {@link SearchContext}
79-
* It may be the instance of {@link WebDriver} or {@link WebElement} or
80-
* {@link Widget} or some other user's extension/implementation.
79+
* @param context is an instance of {@link SearchContext}
80+
* It may be the instance of {@link WebDriver} or {@link WebElement} or
81+
* {@link Widget} or some other user's extension/implementation.
8182
* @param duration is a desired duration of the waiting for an element presence.
8283
*/
8384
public AppiumFieldDecorator(SearchContext context, Duration duration) {
8485
this.webDriver = unpackWebDriverFromSearchContext(context);
85-
HasSessionDetails hasSessionDetails = ofNullable(this.webDriver).map(webDriver -> {
86-
if (!HasSessionDetails.class.isAssignableFrom(webDriver.getClass())) {
87-
return null;
88-
}
89-
return HasSessionDetails.class.cast(webDriver);
90-
}).orElse(null);
9186

92-
if (hasSessionDetails == null) {
93-
platform = null;
94-
automation = null;
87+
if (this.webDriver instanceof HasCapabilities) {
88+
Capabilities caps = ((HasCapabilities) this.webDriver).getCapabilities();
89+
this.platform = CapabilityHelpers.getCapability(caps, "platformName", String.class);
90+
this.automation = CapabilityHelpers.getCapability(caps, "automationName", String.class);
9591
} else {
96-
platform = hasSessionDetails.getPlatformName();
97-
automation = hasSessionDetails.getAutomationName();
92+
this.platform = null;
93+
this.automation = null;
9894
}
9995

10096
this.duration = duration;
@@ -115,7 +111,8 @@ protected List<WebElement> proxyForListLocator(ClassLoader ignored,
115111
return getEnhancedProxy(ArrayList.class, elementInterceptor);
116112
}
117113

118-
@Override protected boolean isDecoratableList(Field field) {
114+
@Override
115+
protected boolean isDecoratableList(Field field) {
119116
if (!List.class.isAssignableFrom(field.getType())) {
120117
return false;
121118
}
@@ -148,7 +145,7 @@ public AppiumFieldDecorator(SearchContext context) {
148145
* Decorated page object {@code field}.
149146
*
150147
* @param ignored class loader is ignored by current implementation
151-
* @param field is {@link Field} of page object which is supposed to be decorated.
148+
* @param field is {@link Field} of page object which is supposed to be decorated.
152149
* @return a field value or null.
153150
*/
154151
public Object decorate(ClassLoader ignored, Field field) {
@@ -197,19 +194,19 @@ private Object decorateWidget(Field field) {
197194

198195
CacheableLocator locator = widgetLocatorFactory.createLocator(field);
199196
Map<ContentType, Constructor<? extends Widget>> map =
200-
OverrideWidgetReader.read(widgetType, field, platform);
197+
OverrideWidgetReader.read(widgetType, field, platform);
201198

202199
if (isAlist) {
203200
return getEnhancedProxy(ArrayList.class,
204-
new WidgetListInterceptor(locator, webDriver, map, widgetType,
205-
duration));
201+
new WidgetListInterceptor(locator, webDriver, map, widgetType,
202+
duration));
206203
}
207204

208205
Constructor<? extends Widget> constructor =
209-
WidgetConstructorUtil.findConvenientConstructor(widgetType);
210-
return getEnhancedProxy(widgetType, new Class[] {constructor.getParameterTypes()[0]},
211-
new Object[] {proxyForAnElement(locator)},
212-
new WidgetInterceptor(locator, webDriver, null, map, duration));
206+
WidgetConstructorUtil.findConvenientConstructor(widgetType);
207+
return getEnhancedProxy(widgetType, new Class[]{constructor.getParameterTypes()[0]},
208+
new Object[]{proxyForAnElement(locator)},
209+
new WidgetInterceptor(locator, webDriver, null, map, duration));
213210
}
214211

215212
private WebElement proxyForAnElement(ElementLocator locator) {

src/main/java/io/appium/java_client/pagefactory/utils/WebDriverUnpackUtility.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@ public static WebDriver unpackWebDriverFromSearchContext(SearchContext searchCon
8282
public static ContentType getCurrentContentType(SearchContext context) {
8383
return ofNullable(unpackWebDriverFromSearchContext(context)).map(driver -> {
8484
if (HasSessionDetails.class.isAssignableFrom(driver.getClass())) {
85-
HasSessionDetails hasSessionDetails = HasSessionDetails.class.cast(driver);
85+
HasSessionDetails hasSessionDetails = (HasSessionDetails) driver;
8686

8787
if (!hasSessionDetails.isBrowser()) {
8888
return NATIVE_MOBILE_SPECIFIC;
8989
}
9090
}
9191

9292
if (ContextAware.class.isAssignableFrom(driver.getClass())) { //it is desktop browser
93-
ContextAware contextAware = ContextAware.class.cast(driver);
93+
ContextAware contextAware = (ContextAware) driver;
9494
String currentContext = contextAware.getContext();
9595
if (containsIgnoreCase(currentContext, NATIVE_APP_PATTERN)) {
9696
return NATIVE_MOBILE_SPECIFIC;

src/main/java/io/appium/java_client/remote/NewAppiumSessionPayload.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import static com.google.common.collect.ImmutableMap.of;
2121
import static com.google.common.collect.ImmutableMap.toImmutableMap;
22+
import static io.appium.java_client.internal.CapabilityHelpers.APPIUM_PREFIX;
2223
import static io.appium.java_client.remote.MobileCapabilityType.FORCE_MJSONWP;
2324
import static java.nio.charset.StandardCharsets.UTF_8;
2425
import static java.util.Optional.ofNullable;
@@ -88,7 +89,6 @@ public class NewAppiumSessionPayload implements Closeable {
8889
.addAll(getAppiumCapabilities(AndroidMobileCapabilityType.class))
8990
.addAll(getAppiumCapabilities(IOSMobileCapabilityType.class))
9091
.addAll(getAppiumCapabilities(YouiEngineCapabilityType.class)).build();
91-
private static final String APPIUM_PREFIX = "appium:";
9292
private static final String DESIRED_CAPABILITIES = "desiredCapabilities";
9393
private static final String CAPABILITIES = "capabilities";
9494
private static final String REQUIRED_CAPABILITIES = "requiredCapabilities";

src/test/java/io/appium/java_client/ios/IOSNativeWebTapSettingTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
public class IOSNativeWebTapSettingTest extends BaseSafariTest {
1212

1313
@Test public void nativeWebTapSettingTest() {
14+
assertTrue(driver.isBrowser());
1415
driver.get("https://saucelabs.com/test/guinea-pig");
1516

1617
// do a click with nativeWebTap turned on, and assert we get to the right page

src/test/java/io/appium/java_client/pagefactory_tests/widget/tests/AbstractStubWebDriver.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,30 @@
33
import static com.google.common.collect.ImmutableList.of;
44
import static io.appium.java_client.remote.AutomationName.APPIUM;
55
import static io.appium.java_client.remote.AutomationName.IOS_XCUI_TEST;
6-
import static io.appium.java_client.remote.AutomationName.SELENDROID;
76
import static io.appium.java_client.remote.MobilePlatform.ANDROID;
87
import static io.appium.java_client.remote.MobilePlatform.IOS;
98
import static io.appium.java_client.remote.MobilePlatform.WINDOWS;
109
import static org.apache.commons.lang3.StringUtils.EMPTY;
1110

1211
import io.appium.java_client.HasSessionDetails;
1312
import org.openqa.selenium.By;
13+
import org.openqa.selenium.Capabilities;
1414
import org.openqa.selenium.Cookie;
15+
import org.openqa.selenium.HasCapabilities;
1516
import org.openqa.selenium.WebDriver;
1617
import org.openqa.selenium.logging.Logs;
18+
import org.openqa.selenium.remote.DesiredCapabilities;
1719
import org.openqa.selenium.remote.Response;
1820

21+
import java.util.HashMap;
1922
import java.util.HashSet;
2023
import java.util.List;
2124
import java.util.Map;
2225
import java.util.Set;
2326
import java.util.concurrent.TimeUnit;
2427

25-
public abstract class AbstractStubWebDriver implements WebDriver, HasSessionDetails {
28+
public abstract class AbstractStubWebDriver implements WebDriver, HasSessionDetails,
29+
HasCapabilities {
2630
@Override
2731
public Response execute(String driverCommand, Map<String, ?> parameters) {
2832
return null;
@@ -104,6 +108,14 @@ public Navigation navigate() {
104108
return null;
105109
}
106110

111+
@Override
112+
public Capabilities getCapabilities() {
113+
Map<String, Object> caps = new HashMap<>();
114+
caps.put("platformName", getPlatformName());
115+
caps.put("automationName", getAutomationName());
116+
return new DesiredCapabilities(caps);
117+
}
118+
107119
@Override
108120
public Options manage() {
109121
return new Options() {

src/test/java/io/appium/java_client/pagefactory_tests/widget/tests/ExtendedWidgetTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ protected ExtendedWidgetTest(ExtendedApp app, WebDriver driver) {
2424
public abstract void checkCaseWhenWidgetClassHasNoDeclaredAnnotationButItHasSuperclass();
2525

2626
@Test
27-
public abstract void checkCaseWhenBothWidgetFieldAndClassHaveDelaredAnnotations();
27+
public abstract void checkCaseWhenBothWidgetFieldAndClassHaveDeclaredAnnotations();
2828

2929
protected static void checkThatLocatorsAreCreatedCorrectly(DefaultStubWidget single,
3030
List<DefaultStubWidget> multiple, By rootLocator,

0 commit comments

Comments
 (0)