Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
# Conflicts:
#	README.md
#	appium/src/main/java/eu/tsystems/mms/tic/testframework/mobile/driver/AppiumDriverFactory.java
  • Loading branch information
martingrossmann committed Dec 15, 2022
1 parent e7932d3 commit 91e13f1
Show file tree
Hide file tree
Showing 21 changed files with 957 additions and 705 deletions.
206 changes: 183 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Testerra Appium Connector

<p align="center">
<a href="https://mvnrepository.com/artifact/io.testerra/appium" title="MavenCentral"><img src="https://img.shields.io/maven-central/v/io.testerra/appium/1?label=Maven%20Central"></a>
<a href="https://mvnrepository.com/artifact/io.testerra/appium" title="MavenCentral"><img src="https://img.shields.io/maven-central/v/io.testerra/appium/2?label=Maven%20Central"></a>
<a href="/../../commits/" title="Last Commit"><img src="https://img.shields.io/github/last-commit/telekom/testerra-appium-connector?style=flat"></a>
<a href="/../../issues" title="Open Issues"><img src="https://img.shields.io/github/issues/telekom/testerra-appium-connector?style=flat"></a>
<a href="./LICENSE" title="License"><img src="https://img.shields.io/badge/License-Apache%202.0-green.svg?style=flat"></a>
Expand Down Expand Up @@ -30,19 +30,21 @@ It will register with Testerra Hooking system and uses the event bus to react on

| Appium connector | Testerra |
|------------------|---------------|
| `>=1.1` | `>=1.3` |
| `>=1.1` | `>=1.3` |
| `>=2.0-RC-5` | `>=2.0-RC-18` |
| `>=2.0` | `>=2.0` |

### Usage

Include the following dependency in your project.
Include the following dependency in your project. Please replace `2-SNAPSHOT` with the latest version.

Gradle:

````groovy
// Version from this module
implementation 'io.testerra:appium:1.2'
// Replace with your Testerra version
implementation 'io.testerra:driver-ui:1.3'
implementation 'io.testerra:appium:2.0'
// Used Testerra version
implementation 'io.testerra:driver-ui:2.0'
implementation 'io.appium:java-client:7.3.0'
````

Expand All @@ -53,18 +55,25 @@ Maven:
<dependency>
<groupId>io.testerra</groupId>
<artifactId>appium</artifactId>
<version>1.2</version>
<version>2.0</version>
</dependency>
<!-- Replace with your Testerra version -->
<!-- Used Testerra version -->
<dependency>
<groupId>io.testerra</groupId>
<artifactId>driver-ui</artifactId>
<version>1.3</version>
<version>2.0</version>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.3.0</version>
<!-- Needed for correct Testerra logging -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
```

Expand All @@ -84,13 +93,10 @@ public class ExampleTest extends TesterraTest {
@Test
public void testT01_My_first_test() {

final AppiumDriverManager appiumDriverManager = new AppiumDriverManager();

final WebDriver driver = WebDriverManager.getWebDriver();
final AppiumDriver<MobileElement> appiumDriver = appiumDriverManager.fromWebDriver(driver);

appiumDriver.rotate(ScreenOrientation.LANDSCAPE);
driver.get(PropertyManager.get("tt.baseurl"));
WebDriver webDriver = WEB_DRIVER_MANAGER.getWebDriver();
WEB_DRIVER_MANAGER.unwrapWebDriver(webDriver, AppiumDriver.class).ifPresent(appiumDriver -> {
appiumDriver.rotate(ScreenOrientation.LANDSCAPE);
});
}
}
```
Expand All @@ -116,23 +122,177 @@ default values will provide you a device with given operating system and of `@ca

#### Screenshots

Screenshots on test case failure works out of the box, because Appium is implementing the necessary interfaces of Selenium to
achieve this.
Screenshots on test case failure works out of the box, because Appium is implementing the necessary interfaces of Selenium to achieve this.

#### Videos

Because videos are a platform dependent feature, Appium connector does not provide any platform-related video recording features.

### Properties

| Property | default | Description |
|--------------------------------|---------------------------------------|-------------------------------------------------------|
| tt.mobile.grid.url | NONE | Grid URL of Appium / Selenium Grid ending on "wd/hub" |
| tt.mobile.grid.access.key | NONE | Access key of your user and project |
| tt.mobile.device.query.ios | "@os='ios' and @category='PHONE'" | Access key of your user and project |
| tt.mobile.device.query.android | "@os='android' and @category='PHONE'" | Access key of your user and project |

---

### AppiumDriverRequest

You can also create new sessions by using the `WebDriverRequest` interface.

```java
AppiumDriverRequest appiumRequest = new AppiumDriverRequest();
appiumRequest.setAccessKey(String);
appiumRequest.setDeviceQuery(String);
appiumRequest.setServerUrl(URL);
appiumRequest.setStartupTimeoutSeconds(int);
appiumRequest.setReuseTimeoutSeconds(int);

WebDriver appiumDriver = WEB_DRIVER_MANAGER.getWebDriver(appiumRequest);
```

## WinAppDriver support

The Appium connector also supports automation of Windows application using the `WindowsDriver` in two setup scenarios.

* Using an Appium-Server
* Using a WinAppServer

### Using Appium-Server (*tbd*)
*(Documentation missing)*

### Using WinAppDriver

The [WinAppDriver](https://github.com/microsoft/WinAppDriver) is like a Selenium server for Windows applications. You can download it from the official project website or just install it via. [chocolatey](https://chocolatey.org/)

```shell
choco install winappdriver
```

Before you are able to use it, you should make sure:

* That the Windows Operating System runs in Development Mode.
* The WinAppDriver able to run.

```text
"C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe"
Windows Application Driver listening for requests at: http://127.0.0.1:4723/
Press ENTER to exit.
```
You can customize the connection using [Properties](#Properties)

## Starting an application

You can start applications in several ways:

* Start applications by the executable path.
* Start drivers for the Windows Desktop.
* Start drivers from known application window title.
* Start application from internal application id (*Documentation unknown*)

### Start applications from path

The application path gets translated to the application id and also sets the working directory based on its parent.

```java
WinAppDriverRequest appRequest = new WinAppDriverRequest();
appRequest.setApplicationPath("C:\\Program Files (x86)\\Application\\Application.exe");
```

**NOTE**: Some applications require their working directory set to the parent of the application binary to run properly.

For example: `C:\\Program Files (x86)\\Application\\Application.exe` needs to run in `C:\\Program Files (x86)\\Application`. When setting the application path, the `WinAppDriverRequests` tries to detect the parent directory by using Java `Path.getParent()`, but this seems to be buggy when using Windows paths in Posix environments. Therefore, we've implemented a workaround to detect the base directory by using basic regular expressions with `/` and `\\` delimiters.

### Start a Desktop driver
```java
WinAppDriverRequest appRequest = new WinAppDriverRequest();
appRequest.setDesktopApplication();
```

### Start driver from known window title

This will try to initialize the driver by an already opened application identified by its window title. Otherwise, it will try to start by given application id.

```java
WinAppDriverRequest appRequest = new WinAppDriverRequest();
appRequest.reuseApplicationByWindowTitle("My App");
appRequest.setApplicationPath("C:\\Program Files (x86)\\Application\\Application.exe");
```

### Start applications from application id

Starting the application from application id is currently unknown. However, this application id starts the default calculator app.

```java
WinAppDriverRequest appRequest = new WinAppDriverRequest();
appRequest.setApplication("Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");
```

### Retrieving element selectors

The WinAppDriver project provides a binary release of tool named [UIRecorder](https://github.com/microsoft/WinAppDriver/releases/tag/UIR-v1.1) for retrieving element selectors xPath by hovering and focusing elements.

### Find UiElements

Most of the applications support finding elements using `AutomationId` attribute selector.

```java
PreparedLocator automationLocator = LOCATE.prepare("//*[@AutomationId=\"%s\"]");
UiElement num1Btn = find(automationLocator.with("num1Button"));
```

### Accessing the native WindowsDriver API

All features of the `WindowsDriver` implementation are hidden by the `WebDriver` by default.
To retrieve the raw WindowsDriver, you can unwrap it via. `WebDriverManager`.

```java
Optional<WindowsDriver> optionalWindowsDriver = WEB_DRIVER_MANAGER.unwrapWebDriver(appDriver, WindowsDriver.class);

optionalWindowsDriver.ifPresent(windowsDriver -> {
// Native API access here
});
```

### Closing applications

The application will automatically be closed, when `WebDriver.quit()` gets called managed by Testerra on session end. But that closes the application's window which doesn't mean that the application is forced to quit. It could still be opened as a system service available by System tray icons.

There is an experimental feature to force quit an application: https://github.com/Microsoft/WinAppDriver/issues/159

Anyway, if you want to prevent Testerra from closing your `WinAppDriver`, just configure it on the `WinAppDriverRequest`.

```java
appRequest.setShutdownAfterTest(false);
appRequest.setShutdownAfterExecution(false);
```

### Properties

The WinAppDriver implementation provides the following properties.

|Property|default|Description|
|---|---|---|
|tt.mobile.grid.url|NONE|Grid URL of Appium / Selenium Grid ending on "wd/hub"|
|tt.mobile.grid.access.key|NONE|Access key of your user and project|
|tt.mobile.device.query.ios|"@os='ios' and @category='PHONE'"|Access key of your user and project|
|tt.mobile.device.query.android|"@os='android' and @category='PHONE'"|Access key of your user and project|
|`tt.winapp.server.url`|`http://localhost:4723/`|URL of the WinAppDriver or Appium / Selenium Grid ending on "wd/hub"|
|`tt.winapp.reuse.timeout.seconds`|`2`|Timeout for finding reusable applications. |
|`tt.winapp.startup.timeout.seconds`|`8`|Timeout for general driver startup. |

---
### Troubleshooting

**Symptom: Application forget settings after restart**
- Solution: Try to set the working directory manually.

**Symptom: Elements are not interactable on remote WinAppDriver**
- Reason: When closing RDP connections, the Desktop gets non-interactable as default behaviour.
- Solution: You can use VNC instead or configure your RDP to keep sessions active. More information can be found here: https://github.com/microsoft/WinAppDriver/issues/1510

**Symptom: Non-interactable elements on non-focused windows**
- Reason: Some applications get minimized when they loose focus.
- Solution: Try to bring the window to the front by calling `webDriver.manage().window().setPosition(new Point(0,0));`

## Publication

Expand Down
1 change: 1 addition & 0 deletions appium/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ dependencies {
implementation 'org.apache.commons:commons-lang3:3.9'

testImplementation 'io.testerra:driver-ui:' + testerraTestVersion
testImplementation 'io.testerra:report-ng:' + testerraTestVersion
testImplementation 'io.appium:java-client:7.3.0'
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Testerra
*
* (C) 2021, Mike Reiche, T-Systems 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;

/**
* A list ob supported browsers
*/
public class Browsers {
public static final String windows ="windows";
public static final String mobile_chrome = "mobile_chrome";
public static final String mobile_safari = "mobile_safari";
}
Loading

0 comments on commit 91e13f1

Please sign in to comment.