Skip to content

Commit

Permalink
Merge pull request #18 from telekom/feature/selenium-4-compatible
Browse files Browse the repository at this point in the history
Update connector to Appium Client 8.x/Selenium 4
  • Loading branch information
martingrossmann authored Jul 12, 2024
2 parents a508e2c + c457ded commit d525e69
Show file tree
Hide file tree
Showing 25 changed files with 503 additions and 195 deletions.
44 changes: 25 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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:
Expand All @@ -54,18 +60,18 @@ Maven:
<dependency>
<groupId>io.testerra</groupId>
<artifactId>appium</artifactId>
<version>2.2</version>
<version>2.3</version>
</dependency>
<!-- Used Testerra version -->
<dependency>
<groupId>io.testerra</groupId>
<artifactId>driver-ui</artifactId>
<version>2.2</version>
<version>2.4</version>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.3.0</version>
<version>8.6.0</version>
<!-- Needed for correct Testerra logging -->
<exclusions>
<exclusion>
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions appium-seetest/build.gradle
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -81,7 +80,7 @@ private Optional<File> downloadVideo(VideoRequest videoRequest) {
.header("Authorization", "Bearer " + AppiumProperties.MOBILE_GRID_ACCESS_KEY.asString())
.build();
HttpResponse<Path> 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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}

Expand Down
4 changes: 2 additions & 2 deletions appium/build.gradle
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -68,7 +67,7 @@ public Object getDefault() {
}
}

private WindowsDriver<WindowsElement> startNewWindowsDriver(WinAppDriverRequest appDriverRequest, SessionContext sessionContext) {
private WindowsDriver startNewWindowsDriver(WinAppDriverRequest appDriverRequest, SessionContext sessionContext) {
final URL finalWinAppServerUrl = appDriverRequest.getServerUrl().get();
sessionContext.setNodeUrl(finalWinAppServerUrl);

Expand All @@ -80,7 +79,7 @@ private WindowsDriver<WindowsElement> startNewWindowsDriver(WinAppDriverRequest
desiredCapabilities.setCapability(WinAppDriverRequest.APP_ID, appId);
});

WindowsDriver<WindowsElement> windowsDriver = new WindowsDriver<>(finalWinAppServerUrl, desiredCapabilities);
WindowsDriver windowsDriver = new WindowsDriver(finalWinAppServerUrl, desiredCapabilities);
//CONTROL.retryFor(appDriverRequest.getStartupTimeoutSeconds(), windowsDriver::getTitle, this::sleep);
return windowsDriver;
}
Expand All @@ -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
Expand All @@ -113,11 +112,13 @@ public WebDriver createWebDriver(WebDriverRequest webDriverRequest, SessionConte
appDriverRequest.getServerUrl().ifPresent(desktopDriverRequest::setServerUrl);
}

WindowsDriver<WindowsElement> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
Loading

0 comments on commit d525e69

Please sign in to comment.