diff --git a/README.md b/README.md
index 2258737..c87ff80 100644
--- a/README.md
+++ b/README.md
@@ -28,10 +28,16 @@ It will register with Testerra Hooking system and uses the event bus to react on
### Requirements
-| Appium connector | Testerra |
-|------------------|-------------|
-| `>=1.1` | `>=1.3` |
-| `2.0 - 2.2` | `2.0 - 2.3` |
+| Appium connector | Testerra | Notes |
+|------------------|-------------|--------------------------------------|
+| `>=1.1` | `>=1.3` |
+| `2.0 - 2.2` | `2.0 - 2.3` | |
+| `2.3` | `2.4` | Support of Appium Client 8.5.1/8.6.0 |
+| `2.4` | `>=2.6` | (not released) |
+
+Important notes:
+* Please check the matrix at https://github.com/appium/java-client?tab=readme-ov-file#compatibility-matrix if Appium Java Client matches to Selenium version
+* Please check the Testerra releaes at https://github.com/telekom/testerra/releases which Selenium vesion is used
### Usage
@@ -41,10 +47,10 @@ Gradle:
```groovy
// Version from this module
-implementation 'io.testerra:appium:2.2'
+implementation 'io.testerra:appium:2.3'
// Used Testerra version
-implementation 'io.testerra:driver-ui:2.2'
-implementation 'io.appium:java-client:7.3.0'
+implementation 'io.testerra:driver-ui:2.4'
+implementation 'io.appium:java-client:8.6.0'
```
Maven:
@@ -54,18 +60,18 @@ Maven:
io.testerra
appium
- 2.2
+ 2.3
io.testerra
driver-ui
- 2.2
+ 2.4
io.appium
java-client
- 7.3.0
+ 8.6.0
@@ -86,15 +92,15 @@ This module is deployed and published to Maven Central. All JAR files are signed
The following properties have to be set via command line or ``~/.gradle/gradle.properties``
-| Property | Description |
-| ----------------------------- | --------------------------------------------------- |
-| `moduleVersion` | Version of deployed module, default is `1-SNAPSHOT` |
-| `deployUrl` | Maven repository URL |
-| `deployUsername` | Maven repository username |
-| `deployPassword` | Maven repository password |
-| `signing.keyId` | GPG private key ID (short form) |
-| `signing.password` | GPG private key password |
-| `signing.secretKeyRingFile` | Path to GPG private key |
+| Property | Description |
+|-----------------------------|-----------------------------------------------------|
+| `moduleVersion` | Version of deployed module, default is `1-SNAPSHOT` |
+| `deployUrl` | Maven repository URL |
+| `deployUsername` | Maven repository username |
+| `deployPassword` | Maven repository password |
+| `signing.keyId` | GPG private key ID (short form) |
+| `signing.password` | GPG private key password |
+| `signing.secretKeyRingFile` | Path to GPG private key |
If all properties are set, call the following to build, deploy and release this module:
```shell
diff --git a/appium-seetest/build.gradle b/appium-seetest/build.gradle
index 3273036..cb76555 100644
--- a/appium-seetest/build.gradle
+++ b/appium-seetest/build.gradle
@@ -1,6 +1,6 @@
dependencies {
compileOnly 'io.testerra:driver-ui:' + testerraCompileVersion
- compileOnly 'io.appium:java-client:7.3.0'
+ compileOnly 'io.appium:java-client:' + appiumJavaClientVersion
compileOnly project(':appium')
// Rest client
@@ -11,7 +11,7 @@ dependencies {
testImplementation 'io.testerra:driver-ui-desktop:' + testerraTestVersion
testImplementation 'io.testerra:report-ng:' + testerraTestVersion
testImplementation project(':appium')
- testImplementation 'io.appium:java-client:7.3.0'
+ testImplementation 'io.appium:java-client:' + appiumJavaClientVersion
}
test {
diff --git a/appium-seetest/src/main/java/eu/tsystems/mms/tic/testerra/plugins/appium/seetest/DriverUi_AppiumSeeTest.java b/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/ioc/DriverUi_AppiumSeeTest.java
similarity index 97%
rename from appium-seetest/src/main/java/eu/tsystems/mms/tic/testerra/plugins/appium/seetest/DriverUi_AppiumSeeTest.java
rename to appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/ioc/DriverUi_AppiumSeeTest.java
index cc843c9..0302514 100644
--- a/appium-seetest/src/main/java/eu/tsystems/mms/tic/testerra/plugins/appium/seetest/DriverUi_AppiumSeeTest.java
+++ b/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/ioc/DriverUi_AppiumSeeTest.java
@@ -19,7 +19,7 @@
* under the License.
*
*/
-package eu.tsystems.mms.tic.testerra.plugins.appium.seetest;
+package io.testerra.plugins.appium.seetest.ioc;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
diff --git a/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/utils/VideoLoader.java b/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/utils/VideoLoader.java
index 60ee8c6..6f1e383 100644
--- a/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/utils/VideoLoader.java
+++ b/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/utils/VideoLoader.java
@@ -28,7 +28,6 @@
import eu.tsystems.mms.tic.testframework.utils.AppiumProperties;
import eu.tsystems.mms.tic.testframework.utils.Sequence;
import io.testerra.plugins.appium.seetest.request.VideoRequest;
-import org.apache.http.HttpStatus;
import java.io.File;
import java.io.IOException;
@@ -81,7 +80,7 @@ private Optional downloadVideo(VideoRequest videoRequest) {
.header("Authorization", "Bearer " + AppiumProperties.MOBILE_GRID_ACCESS_KEY.asString())
.build();
HttpResponse httpResponse = client.send(request, HttpResponse.BodyHandlers.ofFile(videoFile.toPath()));
- if (httpResponse.statusCode() != HttpStatus.SC_OK) {
+ if (httpResponse.statusCode() != 200) {
log().info("Download status code: {}", httpResponse.statusCode());
log().info("Wait for video is ready for download...");
} else {
diff --git a/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/webdriver/SeeTestAppiumDriverFactory.java b/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/webdriver/SeeTestAppiumDriverFactory.java
index d90e4f0..2208706 100644
--- a/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/webdriver/SeeTestAppiumDriverFactory.java
+++ b/appium-seetest/src/main/java/io/testerra/plugins/appium/seetest/webdriver/SeeTestAppiumDriverFactory.java
@@ -5,6 +5,7 @@
import eu.tsystems.mms.tic.testframework.webdriver.WebDriverFactory;
import eu.tsystems.mms.tic.testframework.webdrivermanager.AppiumDriverRequest;
import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverRequest;
+import io.appium.java_client.remote.options.BaseOptions;
import io.testerra.plugins.appium.seetest.utils.SeeTestProperties;
import org.apache.commons.lang3.StringUtils;
@@ -19,11 +20,16 @@ public class SeeTestAppiumDriverFactory extends AppiumDriverFactory implements W
public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverRequest) {
AppiumDriverRequest request = (AppiumDriverRequest) super.prepareWebDriverRequest(webDriverRequest);
+ BaseOptions options = new BaseOptions();
+
final String appiumServer = SeeTestProperties.SEETEST_APPIUM_VERSION.asString();
if (StringUtils.isNotBlank(appiumServer)) {
- request.getDesiredCapabilities().setCapability("appiumVersion", appiumServer);
+ options.setCapability("appiumVersion", appiumServer);
+// request.getDesiredCapabilities().setCapability("appiumVersion", appiumServer);
}
+ request.setCapabilities(request.getCapabilities().merge(options));
+
return request;
}
diff --git a/appium/build.gradle b/appium/build.gradle
index 3569e6d..9b2b3d2 100644
--- a/appium/build.gradle
+++ b/appium/build.gradle
@@ -1,6 +1,6 @@
dependencies {
compileOnly 'io.testerra:driver-ui:' + testerraCompileVersion
- compileOnly 'io.appium:java-client:7.3.0'
+ compileOnly 'io.appium:java-client:' + appiumJavaClientVersion
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.apache.commons:commons-lang3:3.12.0'
@@ -11,7 +11,7 @@ dependencies {
testImplementation 'io.testerra:driver-ui:' + testerraTestVersion
// testImplementation 'io.testerra:driver-ui'
testImplementation 'io.testerra:report-ng:' + testerraTestVersion
- testImplementation 'io.appium:java-client:7.3.0'
+ testImplementation 'io.appium:java-client:' + appiumJavaClientVersion
}
test() {
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/appium/AppiumCapabilityHelper.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/appium/AppiumCapabilityHelper.java
new file mode 100644
index 0000000..ed3d995
--- /dev/null
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/appium/AppiumCapabilityHelper.java
@@ -0,0 +1,35 @@
+/*
+ * Testerra
+ *
+ * (C) 2024, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG
+ *
+ * Deutsche Telekom AG and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package eu.tsystems.mms.tic.testframework.appium;
+
+/**
+ * Created on 2024-06-11
+ *
+ * The Appium client convert all Appium specific capabilities and adds the prefix 'appium:'.
+ * This should help to read a capability.
+ */
+public interface AppiumCapabilityHelper {
+
+ default String getAppiumCap(final String capabilityName) {
+ return "appium:" + capabilityName;
+ }
+
+}
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/appium/WinAppDriverFactory.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/appium/WinAppDriverFactory.java
index 24e4442..6cfa741 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/appium/WinAppDriverFactory.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/appium/WinAppDriverFactory.java
@@ -21,8 +21,8 @@
package eu.tsystems.mms.tic.testframework.appium;
-import eu.tsystems.mms.tic.testframework.core.WinAppDriverCoreAdapter;
import eu.tsystems.mms.tic.testframework.common.IProperties;
+import eu.tsystems.mms.tic.testframework.core.WinAppDriverCoreAdapter;
import eu.tsystems.mms.tic.testframework.logging.Loggable;
import eu.tsystems.mms.tic.testframework.pageobjects.internal.core.GuiElementCore;
import eu.tsystems.mms.tic.testframework.pageobjects.internal.core.GuiElementData;
@@ -33,16 +33,15 @@
import eu.tsystems.mms.tic.testframework.webdrivermanager.WebDriverRequest;
import eu.tsystems.mms.tic.testframework.webdrivermanager.WinAppDriverRequest;
import io.appium.java_client.windows.WindowsDriver;
-import io.appium.java_client.windows.WindowsElement;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
+import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
public class WinAppDriverFactory implements WebDriverFactory, Loggable, TestControllerProvider, Sleepy {
public enum Properties implements IProperties {
@@ -68,7 +67,7 @@ public Object getDefault() {
}
}
- private WindowsDriver startNewWindowsDriver(WinAppDriverRequest appDriverRequest, SessionContext sessionContext) {
+ private WindowsDriver startNewWindowsDriver(WinAppDriverRequest appDriverRequest, SessionContext sessionContext) {
final URL finalWinAppServerUrl = appDriverRequest.getServerUrl().get();
sessionContext.setNodeUrl(finalWinAppServerUrl);
@@ -80,7 +79,7 @@ private WindowsDriver startNewWindowsDriver(WinAppDriverRequest
desiredCapabilities.setCapability(WinAppDriverRequest.APP_ID, appId);
});
- WindowsDriver windowsDriver = new WindowsDriver<>(finalWinAppServerUrl, desiredCapabilities);
+ WindowsDriver windowsDriver = new WindowsDriver(finalWinAppServerUrl, desiredCapabilities);
//CONTROL.retryFor(appDriverRequest.getStartupTimeoutSeconds(), windowsDriver::getTitle, this::sleep);
return windowsDriver;
}
@@ -94,8 +93,8 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques
}
@Override
- public WebDriver createWebDriver(WebDriverRequest webDriverRequest, SessionContext sessionContext) {
- WinAppDriverRequest appDriverRequest = (WinAppDriverRequest)webDriverRequest;
+ public WebDriver createWebDriver(WebDriverRequest webDriverRequest, SessionContext sessionContext) {
+ WinAppDriverRequest appDriverRequest = (WinAppDriverRequest) webDriverRequest;
/**
* Try to reuse an already opened application
@@ -113,11 +112,13 @@ public WebDriver createWebDriver(WebDriverRequest webDriverRequest, SessionConte
appDriverRequest.getServerUrl().ifPresent(desktopDriverRequest::setServerUrl);
}
- WindowsDriver desktopDriver = startNewWindowsDriver(desktopDriverRequest, sessionContext);
+ WindowsDriver desktopDriver = startNewWindowsDriver(desktopDriverRequest, sessionContext);
log().info(String.format("Try to create driver on running application by window title \"%s\"", reuseableWindowTitle));
CONTROL.waitFor(appDriverRequest.getReuseTimeoutSeconds(), () -> {
- WebElement elementByName = desktopDriver.findElementByName(reuseableWindowTitle);
+ // TODO: Verify migration
+ // WebElement elementByName = desktopDriver.findElementByName(reuseableWindowTitle); --> migrate to Appium 8.x
+ WebElement elementByName = desktopDriver.findElement(By.name(reuseableWindowTitle));
String nativeWindowHandle = elementByName.getAttribute("NativeWindowHandle");
int nativeWindowHandleId = Integer.parseInt(nativeWindowHandle);
if (nativeWindowHandleId > 0) {
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/ioc/DriverUi_Appium.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/ioc/DriverUi_Appium.java
index 4735a69..780fca9 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/ioc/DriverUi_Appium.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/ioc/DriverUi_Appium.java
@@ -26,6 +26,10 @@
import com.google.inject.multibindings.Multibinder;
import eu.tsystems.mms.tic.testframework.appium.WinAppDriverFactory;
import eu.tsystems.mms.tic.testframework.mobile.driver.AppiumDriverFactory;
+import eu.tsystems.mms.tic.testframework.mobile.guielement.AppiumUiElementHighlighter;
+import eu.tsystems.mms.tic.testframework.mobile.pageobject.AppiumPageFactory;
+import eu.tsystems.mms.tic.testframework.pageobjects.UiElementHighlighter;
+import eu.tsystems.mms.tic.testframework.pageobjects.internal.PageFactory;
import eu.tsystems.mms.tic.testframework.utils.AppiumExecutionUtils;
import eu.tsystems.mms.tic.testframework.utils.ExecutionUtils;
import eu.tsystems.mms.tic.testframework.webdriver.WebDriverFactory;
@@ -46,5 +50,9 @@ protected void configure() {
webDriverFactoryBinder.addBinding().to(AppiumDriverFactory.class).in(Scopes.SINGLETON);
webDriverFactoryBinder.addBinding().to(WinAppDriverFactory.class).in(Scopes.SINGLETON);
bind(ExecutionUtils.class).to(AppiumExecutionUtils.class).in(Scopes.SINGLETON);
+ // Support for device specific pages
+ bind(PageFactory.class).to(AppiumPageFactory.class).in(Scopes.SINGLETON);
+ // Prevent error while trying element highlighting in apps
+ bind(UiElementHighlighter.class).to(AppiumUiElementHighlighter.class).in(Scopes.SINGLETON);
}
}
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDeviceQuery.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDeviceQuery.java
index 3687d88..ca4ae64 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDeviceQuery.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDeviceQuery.java
@@ -45,7 +45,8 @@ public AppiumDeviceQuery() {
}
public AppiumDeviceQuery(Capabilities capabilities) {
- this.setOs((String) capabilities.getCapability("platformName"));
+ this.setOs(capabilities.getPlatformName().toString());
+// this.setOs((String) capabilities.getCapability("platformName"));
this.setVersion((String) capabilities.getCapability("platformVersion"));
this.setManufacture((String) capabilities.getCapability("deviceManufacture"));
this.setModel((String) capabilities.getCapability("deviceModel"));
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDriverFactory.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDriverFactory.java
index dfa46b8..1ade3db 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDriverFactory.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDriverFactory.java
@@ -31,7 +31,6 @@
import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext;
import eu.tsystems.mms.tic.testframework.report.utils.IExecutionContextController;
import eu.tsystems.mms.tic.testframework.utils.AppiumProperties;
-import eu.tsystems.mms.tic.testframework.utils.DefaultCapabilityUtils;
import eu.tsystems.mms.tic.testframework.utils.TimerUtils;
import eu.tsystems.mms.tic.testframework.webdriver.WebDriverFactory;
import eu.tsystems.mms.tic.testframework.webdrivermanager.AppiumDriverRequest;
@@ -41,10 +40,13 @@
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.remote.MobileBrowserType;
+import io.appium.java_client.remote.options.BaseOptions;
import org.apache.commons.lang3.StringUtils;
+import org.openqa.selenium.Capabilities;
+import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.remote.DesiredCapabilities;
+import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import java.net.URL;
@@ -71,24 +73,23 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques
finalRequest = new AppiumDriverRequest();
finalRequest.setSessionKey(webDriverRequest.getSessionKey());
finalRequest.setBrowser(webDriverRequest.getBrowser());
- finalRequest.setBrowserVersion(webDriverRequest.getBrowserVersion());
}
- DesiredCapabilities requestCapabilities = finalRequest.getDesiredCapabilities();
+ MutableCapabilities requestCapabilities = finalRequest.getMutableCapabilities();
+ BaseOptions baseOptions = new BaseOptions<>();
- // general caps
IExecutionContextController executionContext = Testerra.getInjector().getInstance(IExecutionContextController.class);
- requestCapabilities.setCapability(AppiumDriverRequest.CAPABILITY_NAME_TEST_NAME, executionContext.getExecutionContext().getRunConfig().getReportName());
+ baseOptions.setCapability(AppiumDriverRequest.CAPABILITY_NAME_TEST_NAME, executionContext.getExecutionContext().getRunConfig().getReportName());
if (requestCapabilities.getCapability(AppiumDriverRequest.DEVICE_QUERY) == null
|| StringUtils.isBlank(requestCapabilities.getCapability(AppiumDriverRequest.DEVICE_QUERY).toString())) {
switch (webDriverRequest.getBrowser()) {
case Browsers.mobile_safari: {
- finalRequest.setDeviceQuery(AppiumProperties.MOBILE_APPIUM_DEVICE_QUERY_IOS.asString());
+ baseOptions.setCapability(AppiumDriverRequest.DEVICE_QUERY, AppiumProperties.MOBILE_APPIUM_DEVICE_QUERY_IOS.asString());
break;
}
case Browsers.mobile_chrome: {
- finalRequest.setDeviceQuery(AppiumProperties.MOBILE_APPIUM_DEVICE_QUERY_ANDROID.asString());
+ baseOptions.setCapability(AppiumDriverRequest.DEVICE_QUERY, AppiumProperties.MOBILE_APPIUM_DEVICE_QUERY_ANDROID.asString());
break;
}
}
@@ -96,15 +97,20 @@ public WebDriverRequest prepareWebDriverRequest(WebDriverRequest webDriverReques
switch (webDriverRequest.getBrowser()) {
case Browsers.mobile_chrome:
- requestCapabilities.setBrowserName(MobileBrowserType.CHROME);
+ baseOptions.setCapability(CapabilityType.BROWSER_NAME, MobileBrowserType.CHROME);
break;
case Browsers.mobile_safari:
- requestCapabilities.setBrowserName(MobileBrowserType.SAFARI);
+ baseOptions.setCapability(CapabilityType.BROWSER_NAME, MobileBrowserType.SAFARI);
break;
default:
log().info("No mobile browser requested.");
}
+ // Any additional defined desired capabilities are merged into base options
+ baseOptions = baseOptions.merge(finalRequest.getDesiredCapabilities());
+ baseOptions = baseOptions.merge(finalRequest.getMutableCapabilities());
+ finalRequest.setCapabilities(baseOptions);
+
return finalRequest;
}
@@ -123,44 +129,26 @@ public WebDriver createWebDriver(WebDriverRequest webDriverRequest, SessionConte
private WebDriver startNewAppiumSession(WebDriverRequest webDriverRequest, SessionContext sessionContext) {
AppiumDriverRequest appiumDriverRequest = (AppiumDriverRequest) webDriverRequest;
- DesiredCapabilities requestCapabilities = appiumDriverRequest.getDesiredCapabilities();
+ Capabilities requestCapabilities = appiumDriverRequest.getCapabilities();
URL appiumUrl = appiumDriverRequest.getServerUrl().get();
- DesiredCapabilities finalCapabilities = new DesiredCapabilities(requestCapabilities);
-
- IExecutionContextController executionContextController = Testerra.getInjector().getInstance(IExecutionContextController.class);
- DefaultCapabilityUtils utils = new DefaultCapabilityUtils();
- // TODO: Move to prepareWebDriverRequest
- utils.putIfAbsent(finalCapabilities, AppiumDriverRequest.CAPABILITY_NAME_TEST_NAME, executionContextController.getExecutionContext().getRunConfig().getReportName());
AppiumDriver appiumDriver = null;
Platform mobilePlatform = new MobileOsChecker().getPlatform(webDriverRequest);
switch (mobilePlatform) {
case IOS:
- appiumDriver = new IOSDriver<>(appiumUrl, finalCapabilities);
+ appiumDriver = new IOSDriver(appiumUrl, requestCapabilities);
break;
case ANDROID:
- appiumDriver = new AndroidDriver<>(appiumUrl, finalCapabilities);
+ appiumDriver = new AndroidDriver(appiumUrl, requestCapabilities);
break;
}
-// switch (webDriverRequest.getBrowser()) {
-// case Browsers.mobile_safari: {
-// finalCapabilities.setBrowserName(MobileBrowserType.SAFARI);
-// appiumDriver = new IOSDriver<>(appiumUrl, finalCapabilities);
-// break;
-// }
-// case Browsers.mobile_chrome: {
-// finalCapabilities.setBrowserName(MobileBrowserType.CHROME);
-// appiumDriver = new AndroidDriver<>(appiumUrl, finalCapabilities);
-// break;
-// }
-// }
if (appiumDriver != null) {
AppiumDeviceQuery appiumDeviceQuery = new AppiumDeviceQuery(appiumDriver.getCapabilities());
- sessionContext.setActualBrowserName(appiumDeviceQuery.toString());
+ sessionContext.setUserAgent(appiumDeviceQuery.toString());
+ sessionContext.setActualBrowserName(appiumDeviceQuery.getBrowserName());
} else {
- throw new RuntimeException("Cannot create new Appium session - ambiguous capabilities found:\n " + finalCapabilities.toString());
-// throw new RuntimeException("Mobile Browser not supported: " + webDriverRequest.getBrowser());
+ throw new RuntimeException("Cannot create new Appium session - ambiguous capabilities found:\n " + requestCapabilities.toString());
}
return appiumDriver;
}
@@ -174,7 +162,7 @@ public void setupNewWebDriverSession(EventFiringWebDriver webDriver, SessionCont
.ifPresent(driver -> driverString.set(driver.getClass().toString()));
// In case of app automation it es not possible to call a URL
- if (StringUtils.isNotBlank(appiumDriverRequest.getDesiredCapabilities().getBrowserName())) {
+ if (StringUtils.isNotBlank(appiumDriverRequest.getBrowser())) {
appiumDriverRequest.getBaseUrl().ifPresent(url -> {
log().info("Open {} on {}", url, driverString.get());
webDriver.get(url.toString());
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/MobileOsChecker.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/MobileOsChecker.java
index 52e3746..d1a90d2 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/MobileOsChecker.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/MobileOsChecker.java
@@ -20,6 +20,7 @@
*/
package eu.tsystems.mms.tic.testframework.mobile.driver;
+import eu.tsystems.mms.tic.testframework.appium.AppiumCapabilityHelper;
import eu.tsystems.mms.tic.testframework.appium.Browsers;
import eu.tsystems.mms.tic.testframework.common.Testerra;
import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext;
@@ -28,10 +29,10 @@
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.IOSMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
+import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
-import java.util.Map;
import java.util.Optional;
/**
@@ -39,27 +40,15 @@
*
* @author mgn
*/
-public class MobileOsChecker {
+public class MobileOsChecker implements AppiumCapabilityHelper {
public Platform getPlatform(WebDriverRequest webDriverRequest) {
- Map capabilities = webDriverRequest.getCapabilities();
- if (webDriverRequest.getBrowser().equals(Browsers.mobile_chrome)
- || "Espresso".equals(capabilities.get(MobileCapabilityType.AUTOMATION_NAME))
- || "UiAutomator2".equals(capabilities.get(MobileCapabilityType.AUTOMATION_NAME))
- || "UiAutomator".equals(capabilities.get(MobileCapabilityType.AUTOMATION_NAME))
- || capabilities.containsKey(AndroidMobileCapabilityType.APP_PACKAGE)
- || capabilities.containsKey(AndroidMobileCapabilityType.APP_ACTIVITY)
- ) {
+ if (Browsers.mobile_chrome.equals(webDriverRequest.getBrowser()) || isAppTest(webDriverRequest, Platform.ANDROID)) {
return Platform.ANDROID;
}
- if (webDriverRequest.getBrowser().equals(Browsers.mobile_safari)
- || "XCUITest".equals(capabilities.get(MobileCapabilityType.AUTOMATION_NAME))
- || "UIAutomation".equals(capabilities.get(MobileCapabilityType.AUTOMATION_NAME))
- || capabilities.containsKey(IOSMobileCapabilityType.BUNDLE_ID)
- ) {
+ if (Browsers.mobile_safari.equals(webDriverRequest.getBrowser()) || isAppTest(webDriverRequest, Platform.IOS)) {
return Platform.IOS;
}
-
return Platform.ANY;
}
@@ -73,4 +62,23 @@ public Platform getPlatform(WebDriver driver) {
}
}
+ // Returns true if WebDriverRequest contains typical app capabilities
+ public boolean isAppTest(WebDriverRequest webDriverRequest, Platform platform) {
+ Capabilities capabilities = webDriverRequest.getCapabilities();
+ switch (platform) {
+ case ANDROID:
+ return "Espresso".equals(capabilities.getCapability(getAppiumCap(MobileCapabilityType.AUTOMATION_NAME)))
+ || "UiAutomator2".equals(capabilities.getCapability(getAppiumCap(MobileCapabilityType.AUTOMATION_NAME)))
+ || "UiAutomator".equals(capabilities.getCapability(getAppiumCap(MobileCapabilityType.AUTOMATION_NAME)))
+ || capabilities.getCapability(getAppiumCap(AndroidMobileCapabilityType.APP_PACKAGE)) != null
+ || capabilities.getCapability(getAppiumCap(AndroidMobileCapabilityType.APP_ACTIVITY)) != null;
+ case IOS:
+ return "XCUITest".equals(capabilities.getCapability(getAppiumCap(MobileCapabilityType.AUTOMATION_NAME)))
+ || "UIAutomation".equals(capabilities.getCapability(getAppiumCap(MobileCapabilityType.AUTOMATION_NAME)))
+ || capabilities.getCapability(getAppiumCap(IOSMobileCapabilityType.BUNDLE_ID)) != null;
+ default:
+ return false;
+ }
+ }
+
}
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/AppiumGuiElementCoreAdapter.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/AppiumGuiElementCoreAdapter.java
index f35b61e..87dc6cf 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/AppiumGuiElementCoreAdapter.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/AppiumGuiElementCoreAdapter.java
@@ -29,21 +29,21 @@
import eu.tsystems.mms.tic.testframework.pageobjects.internal.core.GuiElementCore;
import eu.tsystems.mms.tic.testframework.pageobjects.internal.core.GuiElementData;
import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider;
+import eu.tsystems.mms.tic.testframework.utils.AppiumUtils;
import eu.tsystems.mms.tic.testframework.utils.ExecutionUtils;
import io.appium.java_client.AppiumDriver;
-import io.appium.java_client.TouchAction;
-import io.appium.java_client.touch.LongPressOptions;
-import io.appium.java_client.touch.TapOptions;
-import io.appium.java_client.touch.WaitOptions;
-import io.appium.java_client.touch.offset.ElementOption;
-import io.appium.java_client.touch.offset.PointOption;
+import org.apache.commons.lang3.NotImplementedException;
+import org.openqa.selenium.Dimension;
+import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Pause;
+import org.openqa.selenium.interactions.PointerInput;
+import org.openqa.selenium.interactions.Sequence;
import java.time.Duration;
+import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Function;
-import java.util.function.Supplier;
/**
* Implements {@link GuiElementCore} to fullfill Testerra {@link GuiElement} functionality.
@@ -75,46 +75,48 @@ protected void switchToFrame(WebDriver webDriver, WebElement webElement) {
@Override
public void hover() {
-
// Caused by: org.openqa.selenium.WebDriverException: Not Implemented (Method 'mouseMoveTo' is not implemented)
- throw new MobileActionNotSupportedException("hover() is not supported on mobile element.s");
+ throw new MobileActionNotSupportedException("hover() is not supported on mobile elements.");
}
@Override
public void contextClick() {
this.findWebElement(webElement -> {
- final ElementOption elementOption = new ElementOption().withElement(webElement);
- final TouchAction action = new TouchAction<>(appiumDriver);
-
- action.longPress(new LongPressOptions().withElement(elementOption));
- action.perform();
+ Point sourceLocation = webElement.getLocation();
+ Dimension sourceSize = webElement.getSize();
+ int centerX = sourceLocation.getX() + sourceSize.getWidth() / 2;
+ int centerY = sourceLocation.getY() + sourceSize.getHeight() / 2;
+
+ PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
+ Sequence tap = new Sequence(finger, 1);
+ tap.addAction(finger.createPointerMove(Duration.ofMillis(0), PointerInput.Origin.viewport(), centerX, centerY));
+ tap.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
+
+ // Default in iOS: 500ms
+ // https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_uikit_gestures/handling_long-press_gestures
+ // Default in Android: 1_000ms
+ // https://developer.android.com/develop/ui/views/touch-and-input/input-events
+ tap.addAction(new Pause(finger, Duration.ofMillis(1_000)));
+ tap.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
+ this.appiumDriver.perform(List.of(tap));
});
}
- @Override
- public void doubleClick() {
- this.findWebElement(webElement -> {
- final ElementOption elementOption = new ElementOption().withElement(webElement);
- final TouchAction action = new TouchAction<>(appiumDriver);
-
- final TapOptions tapOptions = new TapOptions().withTapsCount(2).withElement(elementOption);
- action.tap(tapOptions).perform();
- });
- }
+ // TODO: Migrate to W3C actions
+// @Override
+// public void doubleClick() {
+// this.findWebElement(webElement -> {
+// final ElementOption elementOption = new ElementOption().withElement(webElement);
+// final TouchAction action = new TouchAction<>(appiumDriver);
+//
+// final TapOptions tapOptions = new TapOptions().withTapsCount(2).withElement(elementOption);
+// action.tap(tapOptions).perform();
+// });
+// }
@Override
public void swipe(int offsetX, int offsetY) {
- this.findWebElement(webElement -> {
- TouchAction touchAction = new TouchAction(appiumDriver);
-
- final TapOptions tapOption = new TapOptions().withElement(new ElementOption().withElement(webElement));
- touchAction.tap(tapOption);
- touchAction.waitAction(new WaitOptions().withDuration(Duration.ofMillis(1500)));
- touchAction.moveTo(new PointOption().withCoordinates(offsetX, offsetY));
- touchAction.waitAction(new WaitOptions().withDuration(Duration.ofMillis(1500)));
- touchAction.release();
- touchAction.perform();
- });
+ new AppiumUtils().swipe(this.guiElementData.getGuiElement(), new Point(offsetX, offsetY));
}
@Override
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/AppiumUiElementHighlighter.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/AppiumUiElementHighlighter.java
new file mode 100644
index 0000000..eb2481b
--- /dev/null
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/AppiumUiElementHighlighter.java
@@ -0,0 +1,53 @@
+/*
+ * Testerra
+ *
+ * (C) 2024, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG
+ *
+ * Deutsche Telekom AG and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package eu.tsystems.mms.tic.testframework.mobile.guielement;
+
+import eu.tsystems.mms.tic.testframework.common.Testerra;
+import eu.tsystems.mms.tic.testframework.mobile.driver.MobileOsChecker;
+import eu.tsystems.mms.tic.testframework.pageobjects.DefaultUiElementHighlighter;
+import eu.tsystems.mms.tic.testframework.report.utils.IExecutionContextController;
+import org.openqa.selenium.Platform;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+import java.awt.Color;
+
+/**
+ * Created on 2024-06-11
+ *
+ * @author mgn
+ */
+public class AppiumUiElementHighlighter extends DefaultUiElementHighlighter {
+
+ @Override
+ public void highlight(WebDriver driver, WebElement webElement, Color color) {
+ IExecutionContextController instance = Testerra.getInjector().getInstance(IExecutionContextController.class);
+ instance.getCurrentSessionContext().ifPresent(sessionContext -> {
+ // Highlighting is only working in browsers but not in apps
+ MobileOsChecker mobileOsChecker = new MobileOsChecker();
+ Platform platform = mobileOsChecker.getPlatform(driver);
+ if (!mobileOsChecker.isAppTest(sessionContext.getWebDriverRequest(), platform)) {
+ super.highlight(driver, webElement, color);
+ }
+ });
+ }
+
+}
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/CreateAppiumGuiElementAction.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/CreateAppiumGuiElementAction.java
index cb794f3..e179fd3 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/CreateAppiumGuiElementAction.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/guielement/CreateAppiumGuiElementAction.java
@@ -20,6 +20,7 @@
*/
package eu.tsystems.mms.tic.testframework.mobile.guielement;
+import eu.tsystems.mms.tic.testframework.appium.AppiumCapabilityHelper;
import eu.tsystems.mms.tic.testframework.common.Testerra;
import eu.tsystems.mms.tic.testframework.internal.NameableChild;
import eu.tsystems.mms.tic.testframework.logging.Loggable;
@@ -47,7 +48,10 @@
*
* @author mgn
*/
-public class CreateAppiumGuiElementAction extends AbstractFieldAction implements UiElementFinderFactoryProvider, Loggable {
+public class CreateAppiumGuiElementAction extends AbstractFieldAction implements
+ UiElementFinderFactoryProvider,
+ Loggable,
+ AppiumCapabilityHelper {
public CreateAppiumGuiElementAction(Field field, AbstractPage declaringPage) {
super(field, declaringPage);
@@ -100,9 +104,9 @@ private String getAutomationEngine(WebDriver driver, Platform platform) {
IWebDriverManager instance = Testerra.getInjector().getInstance(IWebDriverManager.class);
Optional optional = instance.getSessionContext(driver).map(SessionContext::getWebDriverRequest);
if (optional.isPresent()) {
- String automationEngine = optional.get().getCapabilities().get(MobileCapabilityType.AUTOMATION_NAME).toString();
- if (StringUtils.isNotBlank(automationEngine)) {
- return automationEngine;
+ Object automationEngine = optional.get().getCapabilities().getCapability(getAppiumCap(MobileCapabilityType.AUTOMATION_NAME));
+ if (automationEngine != null && StringUtils.isNotBlank(automationEngine.toString())) {
+ return automationEngine.toString();
} else {
// Use default values for automation engine
switch (platform) {
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumClassFinder.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumClassFinder.java
index 3814e37..5964a73 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumClassFinder.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumClassFinder.java
@@ -1,3 +1,23 @@
+/*
+ * Testerra
+ *
+ * (C) 2023, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG
+ *
+ * Deutsche Telekom AG and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
package eu.tsystems.mms.tic.testframework.mobile.pageobject;
import eu.tsystems.mms.tic.testframework.logging.Loggable;
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumPageFactory.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumPageFactory.java
index 706f8b0..1c6e0fa 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumPageFactory.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/pageobject/AppiumPageFactory.java
@@ -1,3 +1,23 @@
+/*
+ * Testerra
+ *
+ * (C) 2023, Martin Großmann, Deutsche Telekom MMS GmbH, Deutsche Telekom AG
+ *
+ * Deutsche Telekom AG and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
package eu.tsystems.mms.tic.testframework.mobile.pageobject;
import eu.tsystems.mms.tic.testframework.enums.CheckRule;
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/utils/AppiumUtils.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/utils/AppiumUtils.java
index 6673048..d6153db 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/utils/AppiumUtils.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/utils/AppiumUtils.java
@@ -25,13 +25,22 @@
import eu.tsystems.mms.tic.testframework.appium.AppiumContext;
import eu.tsystems.mms.tic.testframework.logging.Loggable;
import eu.tsystems.mms.tic.testframework.mobile.driver.MobileOsChecker;
+import eu.tsystems.mms.tic.testframework.pageobjects.UiElement;
import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider;
import io.appium.java_client.AppiumDriver;
+import io.appium.java_client.remote.SupportsContextSwitching;
+import io.appium.java_client.remote.SupportsRotation;
+import org.openqa.selenium.Dimension;
import org.openqa.selenium.Platform;
+import org.openqa.selenium.Point;
+import org.openqa.selenium.ScreenOrientation;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.interactions.PointerInput;
+import org.openqa.selenium.interactions.Sequence;
+import java.time.Duration;
import java.util.Arrays;
-import java.util.Optional;
+import java.util.List;
import java.util.Set;
/**
@@ -41,11 +50,45 @@
*/
public class AppiumUtils implements WebDriverManagerProvider, Loggable {
+ public enum Swipe {
+ LEFT,
+ RIGHT,
+ UP,
+ DOWN;
+ }
+
+ // Relative start and end positions to the screen dimension of standard swipe actions
+ // for example scroll down:
+ // - 0.2 * screenHeight -> start y (SCREEN_SWIPE_START)
+ // - 0.5 * screenHeight -> end y (SCREEN_MULTIPLIER)
+ // - x is center of screen
+ // for example scroll left:
+ // - 0.8 * screenWidth -> start x (SCREEN_SWIPE_END)
+ // - 0.5 * screenWidth -> end x (SCREEN_MULTIPLIER)
+ // - y is center of screen
+ private static final double SCREEN_SWIPE_START = 0.2;
+ private static final double SCREEN_SWIPE_END = 0.8;
+ private static final double SCREEN_MULTIPLIER = 0.5;
+
+ /**
+ * Run a shell command, especially at Android devices
+ *
+ * @param driver
+ * @param command
+ * @param args
+ * @return
+ */
public String runCommand(WebDriver driver, String command, String... args) {
log().info("Shell command (native): {}, {}", command, Arrays.toString(args)); // ImmutableList does NOT work here...
return String.valueOf(JSUtils.executeScript(driver, "mobile: shell", ImmutableMap.of("command", command, "args", Lists.newArrayList(args))));
}
+ /**
+ * Helper method to start a native app from iOS system. To start installed custom apps use the default way with AppiumDriverRequest
+ *
+ * @param driver Current webdriver instance
+ * @param bundleId Bundle ID of native app
+ */
public void launchIOSApp(WebDriver driver, String bundleId) {
log().info("Start application '{}'", bundleId);
MobileOsChecker checker = new MobileOsChecker();
@@ -58,15 +101,110 @@ public void launchIOSApp(WebDriver driver, String bundleId) {
}
}
+ public void rotate(WebDriver driver, ScreenOrientation screenOrientation) {
+ WEB_DRIVER_MANAGER.unwrapWebDriver(driver, AppiumDriver.class).ifPresent(appiumDriver -> {
+ ((SupportsRotation) appiumDriver).rotate(screenOrientation);
+ });
+ }
+
+ /**
+ * Perform a swipe action, start point is an element and end point is calculated based on the offset.
+ */
+ public void swipe(UiElement uiElement, Point offset) {
+ AppiumDriver appiumDriver = this.getAppiumDriver(uiElement.getWebDriver());
+
+ uiElement.findWebElement(webElement -> {
+ Point sourceLocation = webElement.getLocation();
+ Dimension sourceSize = webElement.getSize();
+ int centerX = sourceLocation.getX() + sourceSize.getWidth() / 2;
+ int centerY = sourceLocation.getY() + sourceSize.getHeight() / 2;
+ int endX = centerX + offset.getX();
+ int endY = centerY + offset.getY();
+
+ this.swipeAction(appiumDriver, Duration.ofMillis(200), centerX, centerY, endX, endY);
+ });
+ }
+
+ /**
+ * Perform a swipe action, start point is the center of an element. Possible directions are
+ * Swipe.LEFT, Swipe.RIGHT, Swipe.UP and Swipe.DOWN.
+ */
+ public void swipe(UiElement startElement, Swipe direction) {
+ startElement.findWebElement(webElement -> {
+ Point sourceLocation = webElement.getLocation();
+ Dimension sourceSize = webElement.getSize();
+ int startX = sourceLocation.getX() + sourceSize.getWidth() / 2;
+ int startY = sourceLocation.getY() + sourceSize.getHeight() / 2;
+ Point startPoint = new Point(startX, startY);
+
+ this.swipeAction(startElement.getWebDriver(), direction, startPoint);
+ });
+ }
+
+ /**
+ * Perform a swipe action. Start point is the center of the screen. Possible directions are
+ * Swipe.LEFT, Swipe.RIGHT, Swipe.UP and Swipe.DOWN.
+ */
+ public void swipe(WebDriver driver, Swipe direction) {
+ Dimension screenDim = driver.manage().window().getSize();
+ int startX = screenDim.getWidth() / 2;
+ int startY = screenDim.getHeight() / 2;
+ Point startPoint = new Point(startX, startY);
+ this.swipeAction(driver, direction, startPoint);
+ }
+
+ private void swipeAction(WebDriver driver, Swipe direction, Point startPoint) {
+ AppiumDriver appiumDriver = this.getAppiumDriver(driver);
+ final Duration intensity = Duration.ofMillis(500);
+ // Length of swipe action according screen resolution
+
+
+ Dimension screenDim = appiumDriver.manage().window().getSize();
+ final int diffX = (int) (screenDim.getWidth() * SCREEN_MULTIPLIER);
+ final int diffY = (int) (screenDim.getHeight() * SCREEN_MULTIPLIER);
+
+ int startX = startPoint.getX();
+ int startY = startPoint.getY();
+ int endX = startX;
+ int endY = startY;
+ switch (direction) {
+ case LEFT:
+ startX = (int) (screenDim.getWidth() * SCREEN_SWIPE_END);
+ endX = (int) (screenDim.getWidth() * SCREEN_SWIPE_START);
+// endX = Math.max(startX - diffX, 1);
+ break;
+ case RIGHT:
+ endX = Math.max(startX + diffX, screenDim.getWidth() - 1);
+ break;
+ case UP:
+ endY = Math.max(startY - diffY, 1);
+ break;
+ case DOWN:
+ endY = Math.max(startY + diffY, screenDim.getHeight() - 1);
+ }
+
+ this.swipeAction(appiumDriver, intensity, startX, startY, endX, endY);
+ }
+
+ private void swipeAction(AppiumDriver driver, Duration intensity, int startX, int startY, int endX, int endY) {
+ PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
+ Sequence swipe = new Sequence(finger, 1);
+ swipe.addAction(finger.createPointerMove(intensity, PointerInput.Origin.viewport(), startX, startY));
+ swipe.addAction(finger.createPointerDown(0));
+ swipe.addAction(finger.createPointerMove(intensity, PointerInput.Origin.viewport(), endX, endY));
+ swipe.addAction(finger.createPointerUp(0));
+ driver.perform(List.of(swipe));
+ }
+
/**
* Switch the Appium Context if available
*/
public void switchContext(WebDriver driver, AppiumContext desiredContext) {
- Optional appiumDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(driver, AppiumDriver.class);
- if (appiumDriver.isEmpty()) {
- throw new RuntimeException("Current Webdriver is not an Appium driver.");
- }
- String currentContext = appiumDriver.get().getContext();
+ AppiumDriver appiumDriver = this.getAppiumDriver(driver);
+
+ SupportsContextSwitching contextSwitchingDriver = (SupportsContextSwitching) appiumDriver;
+
+ String currentContext = contextSwitchingDriver.getContext();
AppiumContext parsedInitialContext = AppiumContext.parse(currentContext);
log().info("Current context: {} ({})", currentContext, parsedInitialContext);
@@ -75,14 +213,14 @@ public void switchContext(WebDriver driver, AppiumContext desiredContext) {
return;
}
- Set contextHandles = appiumDriver.get().getContextHandles();
+ Set contextHandles = contextSwitchingDriver.getContextHandles();
log().info("Available contexts: {}", contextHandles);
contextHandles.stream()
.filter(contextHandle -> AppiumContext.parse(contextHandle).equals(desiredContext))
.findFirst()
.ifPresentOrElse(handle -> {
log().info("Switch to context {} ({})", handle, desiredContext);
- appiumDriver.get().context(handle);
+ contextSwitchingDriver.context(handle);
}, () -> {
log().error("Couldn't find a {} context in {}", desiredContext, contextHandles);
throw new RuntimeException(String.format("Cannot switch in %s, because it does not exist. (%s)", desiredContext, contextHandles));
@@ -90,4 +228,12 @@ public void switchContext(WebDriver driver, AppiumContext desiredContext) {
}
+ /**
+ * Unwrap the current WebDriver instance and returns a native AppiumDriver instance.
+ */
+ public AppiumDriver getAppiumDriver(WebDriver webDriver) {
+ return WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, AppiumDriver.class)
+ .orElseThrow(() -> new RuntimeException("Current Webdriver is not an Appium driver."));
+ }
+
}
diff --git a/appium/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AppiumDriverRequest.java b/appium/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AppiumDriverRequest.java
index 4c5be9a..824f087 100644
--- a/appium/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AppiumDriverRequest.java
+++ b/appium/src/main/java/eu/tsystems/mms/tic/testframework/webdrivermanager/AppiumDriverRequest.java
@@ -21,6 +21,7 @@
package eu.tsystems.mms.tic.testframework.webdrivermanager;
+import eu.tsystems.mms.tic.testframework.appium.AppiumCapabilityHelper;
import eu.tsystems.mms.tic.testframework.appium.Browsers;
import eu.tsystems.mms.tic.testframework.utils.AppiumProperties;
import io.appium.java_client.remote.MobileCapabilityType;
@@ -30,15 +31,19 @@
import java.net.URL;
import java.util.Optional;
-public class AppiumDriverRequest extends SeleniumWebDriverRequest {
+public class AppiumDriverRequest extends SeleniumWebDriverRequest implements AppiumCapabilityHelper {
public static final String DEVICE_QUERY = "deviceQuery";
public static final String ACCESS_KEY = "accessKey";
public static final String CAPABILITY_NAME_TEST_NAME = "testName";
public AppiumDriverRequest() {
- setAccessKey(AppiumProperties.MOBILE_GRID_ACCESS_KEY.asString());
- this.setBrowser(Browsers.mobile);
+ this.setAccessKey(AppiumProperties.MOBILE_GRID_ACCESS_KEY.asString());
+
+ if (StringUtils.isBlank(this.getBrowser())) {
+ this.setBrowser(Browsers.mobile);
+ }
+
}
@Override
@@ -55,43 +60,43 @@ public Optional getServerUrl() {
public void setDeviceQuery(String deviceQuery) {
if (StringUtils.isNotBlank(deviceQuery)) {
- this.getDesiredCapabilities().setCapability(DEVICE_QUERY, deviceQuery);
+ this.getMutableCapabilities().setCapability(DEVICE_QUERY, deviceQuery);
}
}
public void setAccessKey(String accessKey) {
- this.getDesiredCapabilities().setCapability(ACCESS_KEY, accessKey);
+ this.getMutableCapabilities().setCapability(ACCESS_KEY, accessKey);
}
public void setAppiumEngine(String engine) {
- this.getDesiredCapabilities().setCapability(MobileCapabilityType.AUTOMATION_NAME, engine);
+ this.getMutableCapabilities().setCapability(MobileCapabilityType.AUTOMATION_NAME, engine);
}
public String getAppiumEngine() {
- return this.getDesiredCapabilities().getCapability(MobileCapabilityType.AUTOMATION_NAME).toString();
+ return this.getMutableCapabilities().getCapability(getAppiumCap(MobileCapabilityType.AUTOMATION_NAME)).toString();
}
public void setDeviceName(String deviceName) {
- this.getDesiredCapabilities().setCapability(MobileCapabilityType.DEVICE_NAME, deviceName);
+ this.getMutableCapabilities().setCapability(MobileCapabilityType.DEVICE_NAME, deviceName);
}
public String getDeviceName() {
- return this.getDesiredCapabilities().getCapability(MobileCapabilityType.DEVICE_NAME).toString();
+ return this.getMutableCapabilities().getCapability(getAppiumCap(MobileCapabilityType.DEVICE_NAME)).toString();
}
public void setPlatformVersion(String platformVersion) {
- this.getDesiredCapabilities().setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
+ this.getMutableCapabilities().setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
}
public String getPlatformVersion() {
- return this.getDesiredCapabilities().getCapability(MobileCapabilityType.PLATFORM_VERSION).toString();
+ return this.getMutableCapabilities().getCapability(getAppiumCap(MobileCapabilityType.PLATFORM_VERSION)).toString();
}
public void setDeviceId(String id) {
- this.getDesiredCapabilities().setCapability(MobileCapabilityType.UDID, id);
+ this.getMutableCapabilities().setCapability(MobileCapabilityType.UDID, id);
}
public String getDeviceId() {
- return this.getDesiredCapabilities().getCapability(MobileCapabilityType.UDID).toString();
+ return this.getMutableCapabilities().getCapability(getAppiumCap(MobileCapabilityType.UDID)).toString();
}
}
diff --git a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/TesterraMobileAppTest.java b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/TesterraMobileAppTest.java
index 82cdf42..2fb8e5d 100644
--- a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/TesterraMobileAppTest.java
+++ b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/TesterraMobileAppTest.java
@@ -47,12 +47,13 @@ public class TesterraMobileAppTest extends AbstractAppiumTest {
@Test
public void testT01AndroidApp() {
AppiumDriverRequest request = new AppiumDriverRequest();
+ request.setBrowser("mobile");
request.setDeviceQuery("contains(@name, 'Galaxy S20')");
- request.getDesiredCapabilities().setCapability("appiumVersion", "1.22.3");
+ request.getMutableCapabilities().setCapability("appiumVersion", "2.2.2");
- request.getDesiredCapabilities().setCapability(MobileCapabilityType.APP, "cloud:eu.tsystems.mms.tic.mdc.app.android/.HomeActivity");
- request.getDesiredCapabilities().setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "eu.tsystems.mms.tic.mdc.app.android");
- request.getDesiredCapabilities().setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, ".HomeActivity");
+ request.getMutableCapabilities().setCapability(MobileCapabilityType.APP, "cloud:eu.tsystems.mms.tic.mdc.app.android/.HomeActivity");
+ request.getMutableCapabilities().setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "eu.tsystems.mms.tic.mdc.app.android");
+ request.getMutableCapabilities().setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, ".HomeActivity");
request.setAppiumEngine("UiAutomator2");
WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver(request);
diff --git a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/VanillaAppiumAppTest.java b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/VanillaAppiumAppTest.java
index 39b5be0..3283f3d 100644
--- a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/VanillaAppiumAppTest.java
+++ b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/apps/VanillaAppiumAppTest.java
@@ -24,7 +24,6 @@
import eu.tsystems.mms.tic.testframework.utils.AppiumProperties;
import eu.tsystems.mms.tic.testframework.utils.TimerUtils;
import io.appium.java_client.android.AndroidDriver;
-import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
@@ -43,7 +42,7 @@
*/
public class VanillaAppiumAppTest extends AbstractAppiumTest {
- protected AndroidDriver driver = null;
+ protected AndroidDriver driver = null;
@BeforeMethod
public void setUp() throws MalformedURLException {
@@ -61,7 +60,7 @@ public void setUp() throws MalformedURLException {
dc.setCapability(MobileCapabilityType.AUTOMATION_NAME, "UIAutomator2");
URL url = new URL(AppiumProperties.MOBILE_GRID_URL.asString());
// driver = new IOSDriver<>(new URL(PropertyManager.getProperty("tt.mobile.grid.url")), dc);
- driver = new AndroidDriver<>(url, dc);
+ driver = new AndroidDriver(url, dc);
}
@Test
diff --git a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/TesterraAppiumDriverTest.java b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/TesterraAppiumDriverTest.java
index e738f55..5cf89d9 100644
--- a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/TesterraAppiumDriverTest.java
+++ b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/TesterraAppiumDriverTest.java
@@ -27,11 +27,11 @@
import eu.tsystems.mms.tic.testframework.report.model.context.Screenshot;
import eu.tsystems.mms.tic.testframework.report.model.context.SessionContext;
import eu.tsystems.mms.tic.testframework.testing.WebDriverManagerProvider;
+import eu.tsystems.mms.tic.testframework.utils.AppiumUtils;
import eu.tsystems.mms.tic.testframework.utils.JSUtils;
import eu.tsystems.mms.tic.testframework.utils.UITestUtils;
import eu.tsystems.mms.tic.testframework.utils.WebDriverUtils;
import eu.tsystems.mms.tic.testframework.webdrivermanager.AppiumDriverRequest;
-import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.ScreenOrientation;
import org.openqa.selenium.WebDriver;
@@ -48,28 +48,25 @@ public class TesterraAppiumDriverTest extends AbstractAppiumTest implements WebD
@Test
public void testT01_startDefaultSession() {
+ AppiumDriverRequest request = new AppiumDriverRequest();
+ request.getMutableCapabilities().setCapability("appiumVersion", "2.2.2");
+ final WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request);
+
+ new AppiumUtils().rotate(driver, ScreenOrientation.LANDSCAPE);
- final WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver();
- WEB_DRIVER_MANAGER.unwrapWebDriver(driver, AppiumDriver.class).ifPresent(appiumDriver -> {
- appiumDriver.rotate(ScreenOrientation.LANDSCAPE);
- });
driver.get("https://the-internet.herokuapp.com/dropdown");
+ UITestUtils.takeScreenshots();
}
@Test
public void testT02_startMultipleSessions() {
final WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver();
- AppiumDriver appiumDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(driver, AppiumDriver.class).get();
-
- appiumDriver.rotate(ScreenOrientation.LANDSCAPE);
+ new AppiumUtils().rotate(driver, ScreenOrientation.LANDSCAPE);
driver.get("https://the-internet.herokuapp.com/dropdown");
final WebDriver driver2 = WEB_DRIVER_MANAGER.getWebDriver("second");
- AppiumDriver appiumDriver2 = WEB_DRIVER_MANAGER.unwrapWebDriver(driver2, AppiumDriver.class).get();
-
- appiumDriver2.rotate(ScreenOrientation.PORTRAIT);
- driver2.get("https://the-internet.herokuapp.com/checkboxes");
+ new AppiumUtils().rotate(driver2, ScreenOrientation.PORTRAIT);
Assert.assertNotEquals(driver, driver2, "Driver equals");
}
@@ -80,6 +77,7 @@ public void testT03_startRequestSession() {
final String device = "Apple iPhone X";
request.setBrowser(Browsers.mobile_safari);
request.setDeviceQuery(String.format("contains(@name, '%s')", device));
+ request.getMutableCapabilities().setCapability("appiumVersion", "2.2.2");
final WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver(request);
@@ -103,15 +101,13 @@ public void testT04_startSessionTwice() {
public void testT05_takeScreenshot() {
final WebDriver driver = WEB_DRIVER_MANAGER.getWebDriver();
- AppiumDriver appiumDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(driver, AppiumDriver.class).get();
-
driver.get("https://the-internet.herokuapp.com/");
- appiumDriver.rotate(ScreenOrientation.LANDSCAPE);
+ new AppiumUtils().rotate(driver, ScreenOrientation.LANDSCAPE);
final Screenshot screenshotLandScape = UITestUtils.takeScreenshot(driver, true);
Assert.assertNotNull(screenshotLandScape, "Screenshot created.");
- appiumDriver.rotate(ScreenOrientation.PORTRAIT);
+ new AppiumUtils().rotate(driver, ScreenOrientation.PORTRAIT);
final Screenshot screenshotPortrait = UITestUtils.takeScreenshot(driver, true);
Assert.assertNotNull(screenshotPortrait, "Screenshot created.");
}
diff --git a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/VanillaAppiumDriverTest.java b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/VanillaAppiumDriverTest.java
index 27b54b1..8e7ec24 100644
--- a/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/VanillaAppiumDriverTest.java
+++ b/appium/src/test/java/eu/tsystems/mms/tic/testframework/mobile/test/driver/VanillaAppiumDriverTest.java
@@ -28,8 +28,8 @@
import eu.tsystems.mms.tic.testframework.report.Report;
import eu.tsystems.mms.tic.testframework.report.TesterraListener;
import eu.tsystems.mms.tic.testframework.utils.AppiumProperties;
+import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.ios.IOSDriver;
-import io.appium.java_client.ios.IOSElement;
import io.appium.java_client.remote.MobileBrowserType;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
@@ -47,6 +47,7 @@
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
+import java.time.Duration;
/**
* Date: 24.06.2020
@@ -56,30 +57,33 @@
*/
public class VanillaAppiumDriverTest extends AbstractAppiumTest implements Loggable, PropertyManagerProvider {
- protected IOSDriver driver = null;
-// protected AndroidDriver driver = null;
+// protected IOSDriver driver = null;
+ protected AndroidDriver driver = null;
@BeforeMethod
public void setUp() throws MalformedURLException {
final String accessKey = AppiumProperties.MOBILE_GRID_ACCESS_KEY.asString();
Assert.assertNotNull(accessKey, "No access key loaded");
+
+
DesiredCapabilities dc = new DesiredCapabilities();
- dc.setCapability("testName", "Demo Tests");
- dc.setCapability("accessKey", accessKey);
- dc.setCapability("appiumVersion", "1.22.3");
-// dc.setCapability("deviceQuery", "contains(@name, 'Samsung Galaxy S20')");
+ dc.setCapability("appium:testName", "Demo Tests");
+ dc.setCapability("appium:accessKey", accessKey);
+// dc.setCapability("appiumVersion", "1.22.3");
+ dc.setCapability("appium:appiumVersion", "2.2.2");
// dc.setCapability("deviceQuery", "contains(@name, 'Google Pixel 6')");
// dc.setCapability("deviceQuery", AppiumProperties.MOBILE_APPIUM_DEVICE_QUERY_ANDROID);
- dc.setCapability("deviceQuery", "contains(@name, 'Apple iPhone X (')");
+// dc.setCapability("appium:deviceQuery", "contains(@name, 'Apple iPhone X (')");
+ dc.setCapability("appium:deviceQuery", "contains(@name, 'Samsung Galaxy S20')");
// dc.setCapability(MobileCapabilityType.UDID, "...");
- dc.setBrowserName(MobileBrowserType.SAFARI);
-// dc.setBrowserName(MobileBrowserType.CHROME);
+// dc.setBrowserName(MobileBrowserType.SAFARI);
+ dc.setBrowserName(MobileBrowserType.CHROME);
URL url = new URL(AppiumProperties.MOBILE_GRID_URL.asString());
log().info(dc.toString());
- driver = new IOSDriver<>(url, dc);
-// driver = new AndroidDriver<>(url, dc);
+// driver = new IOSDriver(url, dc);
+ driver = new AndroidDriver(url, dc);
}
@@ -87,7 +91,7 @@ public void setUp() throws MalformedURLException {
public void testT01_DoGoogleSearch() {
driver.rotate(ScreenOrientation.PORTRAIT);
driver.get("https://www.google.com");
- new WebDriverWait(driver, 10).until(driver1 -> {
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(driver1 -> {
ExpectedCondition q = ExpectedConditions.presenceOfElementLocated(By.xpath("//input[@name='q']"));
return q;
});
diff --git a/appium/src/test/resources/test.properties b/appium/src/test/resources/test.properties
index c95bb1a..4a2af29 100644
--- a/appium/src/test/resources/test.properties
+++ b/appium/src/test/resources/test.properties
@@ -1,12 +1,13 @@
-#tt.browser=mobile_chrome
+tt.browser=mobile_chrome
#tt.browser=mobile_safari
-tt.watchdog.enable=false
-tt.baseurl=https://the-internet.herokuapp.com/
+
+#tt.baseurl=https://the-internet.herokuapp.com/
+
#tt.mobile.device.query.ios=@os='ios' and @category='PHONE'
tt.mobile.device.query.ios=contains(@name, 'iPhone X')
#tt.mobile.device.query.android=@os='android' and @category='PHONE' and @version='10'
-tt.mobile.device.query.android=contains(@name, 'Samsung Galaxy A5')
+tt.mobile.device.query.android=contains(@name, 'Samsung Galaxy S20')
tt.winapp.server.url=
diff --git a/build.gradle b/build.gradle
index 1976dcd..3f46097 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,10 +5,15 @@ plugins {
apply plugin: 'io.codearte.nexus-staging'
ext {
+ // Tested with
+// appiumJavaClientVersion = '9.0.0'
+ appiumJavaClientVersion = '8.6.0'
+
// Minimum required Testerra version
- testerraCompileVersion = '2.0'
+ testerraCompileVersion = '2.4'
// Unit tests use the latest Testerra version
- testerraTestVersion = '[2,3-SNAPSHOT)'
+// testerraTestVersion = '[2,3-SNAPSHOT)'
+ testerraTestVersion = '2.4'
moduleVersion = '2-SNAPSHOT'
if (System.properties.containsKey('moduleVersion')) {
moduleVersion = System.getProperty('moduleVersion')