Skip to content

Commit

Permalink
update android native app implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
titusfortner committed Feb 4, 2025
1 parent f176bb0 commit 32c23e0
Show file tree
Hide file tree
Showing 10 changed files with 646 additions and 0 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/appium-examples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Appium Examples

on:
schedule:
- cron: '35 20 * * *'
workflow_dispatch:
push:
branches: [ main ]
paths:
- '**/appium/**'
pull_request:
paths:
- '**/appium/**'

env:
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
cloud: [ RDC, VDC ]
steps:
- uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: 11
distribution: "temurin"
- name: Android Native App ${{ matrix.cloud }}
working-directory: ./appium/android-app
run: mvn test -Dsauce.cloud=${{ matrix.cloud }}
38 changes: 38 additions & 0 deletions appium/android-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
64 changes: 64 additions & 0 deletions appium/android-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Testing an Android App

If you have an Android native application, you can test it with Appium on a Simulator
in Sauce Labs Virtual Device Cloud, or on a Real Device in the Sauce Labs Real Device Cloud.

[Setup Instructions](https://github.com/saucelabs-training/demo-java/blob/main/README.md#%EF%B8%8Fsetupprerequisites)
and
[Contribution Information](https://github.com/saucelabs-training/demo-java/blob/main/README.md#contributing)
can be found on the [Main README](https://github.com/saucelabs-training/demo-java/blob/main/README.md).

## Executing Examples
The Android app being tested is found in the [My Demo App Android Repository](https://github.com/saucelabs/my-demo-app-android)

1. After cloning this repo from instructions, change to this subdirectory:
```
$ cd appium/android-app
```

2. Run the following command to update any package dependencies:
```
$ mvn dependency:resolve
```
3. Then run the following command to compile your test code:
```
$ mvn test-compile
```
4. Finally, run the following test to see if you've properly configured the test environment:
```
$ mvn clean test
```
See passing tests on [GitHub Actions](https://github.com/saucelabs-training/demo-java/actions/workflows/appium-examples.yml)
## Configurations
This code allows toggling what cloud the tests will target.
The capabilities for these configurations can be copied from the
[Platform Configurator](https://app.saucelabs.com/platform-configurator),
and can be viewed in the [Test Configurations](src/test/java/com/saucedemo/TestConfigurations.java) file.
### Virtual Device Cloud (default)
Tests will execute on an emulator:
```
$ mvn clean test -Dsauce.cloud=vdc
```
### Real Device Cloud
Tests will execute on a real device:
```
$ mvn clean test -Dsauce.cloud=rdc
```
## Disclaimer
> The code in these scripts is provided on an "AS-IS" basis without warranty of any kind, either
> express or implied, including without limitation any implied warranties of condition,
> uninterrupted
> use, merchantability, fitness for a particular purpose, or non-infringement. These scripts are
> provided for educational and demonstration purposes only and should not be used in production.
> Issues regarding these scripts should be submitted through GitHub. These scripts are maintained by
> the Technical Services team at Sauce Labs.
>
> Some examples in this repository, such as `appium-example`, `parallel-testing`, and `headless`,
> may require a different account tier beyond free trial. Please contact
> the [Sauce Labs Sales Team](https://saucelabs.com/contact) for support and information.
53 changes: 53 additions & 0 deletions appium/android-app/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.saucelabs</groupId>
<artifactId>android-app</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<surefire.parallel>10</surefire.parallel>
</properties>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>9.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<properties>
<configurationParameters>
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.config.strategy = fixed
junit.jupiter.execution.parallel.config.fixed.parallelism = ${surefire.parallel}
junit.jupiter.execution.parallel.config.fixed.max-pool-size = ${surefire.parallel}
</configurationParameters>
</properties>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.saucedemo;

import io.appium.java_client.AppiumBy;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebElement;

public class AuthenticationTest extends TestBase {

@Test
@DisplayName("Bad Login to Swag Labs")
public void signInUnsuccessful() {
driver.findElement(AppiumBy.accessibilityId("View menu")).click();
// driver.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/drawerMenu"));

scrollDown(AppiumBy.id("com.saucelabs.mydemoapp.android:id/menuRV"));
driver.findElement(AppiumBy.accessibilityId("Login Menu Item")).click();

driver
.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/nameET"))
.sendKeys("[email protected]");
driver
.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/passwordET"))
.sendKeys("secret_sauce");
driver.findElement(AppiumBy.accessibilityId("Tap to login with given credentials")).click();

WebElement errorElement =
driver.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/passwordErrorTV"));

Assertions.assertEquals("Sorry this user has been locked out.", errorElement.getText(),
"Expected error not displayed");
}

@Test
@DisplayName("Good Login to Swag Labs")
public void signInSuccessful() {
driver.findElement(AppiumBy.accessibilityId("View menu")).click();
// driver.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/drawerMenu"));

scrollDown(AppiumBy.id("com.saucelabs.mydemoapp.android:id/menuRV"));
driver.findElement(AppiumBy.accessibilityId("Login Menu Item")).click();

driver
.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/nameET"))
.sendKeys("standard_user");
driver
.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/passwordET"))
.sendKeys("secret_sauce");
driver.findElement(AppiumBy.accessibilityId("Tap to login with given credentials")).click();

driver.findElement(AppiumBy.accessibilityId("View menu")).click();
scrollDown(AppiumBy.id("com.saucelabs.mydemoapp.android:id/menuRV"));
Assertions.assertTrue(
driver.findElement(AppiumBy.accessibilityId("Logout Menu Item")).isDisplayed());
}

@Test
@DisplayName("Log Out of Swag Labs")
public void logout() throws InterruptedException {
driver.findElement(AppiumBy.accessibilityId("View menu")).click();
// driver.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/drawerMenu"));

scrollDown(AppiumBy.id("com.saucelabs.mydemoapp.android:id/menuRV"));
driver.findElement(AppiumBy.accessibilityId("Login Menu Item")).click();

driver
.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/nameET"))
.sendKeys("standard_user");
driver
.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/passwordET"))
.sendKeys("secret_sauce");

driver.findElement(AppiumBy.accessibilityId("Tap to login with given credentials")).click();

driver.findElement(AppiumBy.accessibilityId("View menu")).click();
scrollDown(AppiumBy.id("com.saucelabs.mydemoapp.android:id/menuRV"));

driver.findElement(AppiumBy.accessibilityId("Logout Menu Item")).click();
driver.findElement(AppiumBy.id("android:id/button1")).click();

WebElement loginButton =
driver.findElement(AppiumBy.accessibilityId("Tap to login with given credentials"));
Assertions.assertTrue(loginButton.isDisplayed(), "Login button is not displayed");
}
}
40 changes: 40 additions & 0 deletions appium/android-app/src/test/java/com/saucedemo/CartTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.saucedemo;

import io.appium.java_client.AppiumBy;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class CartTest extends TestBase {
@Test
@DisplayName("Add product to cart")
public void addToCart() {
driver.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/productIV")).click();

scrollDown(AppiumBy.accessibilityId("Container for fragments"));
driver.findElement(AppiumBy.accessibilityId("Tap to add product to cart")).click();

Assertions.assertEquals(
"1",
driver.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/cartTV")).getText(),
"Item not correctly added to cart");
}

@Test
@DisplayName("Remove product from cart")
public void removeFromCart() {
driver.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/productIV")).click();
scrollDown(AppiumBy.accessibilityId("Container for fragments"));
driver.findElement(AppiumBy.accessibilityId("Tap to add product to cart")).click();

driver.findElement(AppiumBy.accessibilityId("View cart")).click();

driver.findElement(AppiumBy.accessibilityId("Removes product from cart")).click();

Assertions.assertTrue(
driver
.findElement(AppiumBy.id("com.saucelabs.mydemoapp.android:id/noItemTitleTV"))
.isDisplayed(),
"Shopping Cart is not empty");
}
}
Loading

0 comments on commit 32c23e0

Please sign in to comment.