Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 61 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,61 @@
# selfheal-demo-browserstack
Self Heal Demo Scripts
# Self Heal Demo (TestNG)

## Overview
This repository contains demo scripts and configuration for testing the self-healing feature on BrowserStack using Appium and TestNG. It includes two main flows:

### 1. Base App Flow
- Uses the **BaseApp.apk** for standard automation tests without self-healing.
- Located at: `android/testng-examples/BaseApp.apk`
- Demonstrates normal automation behavior and serves as a reference for comparison.

### 2. Self-Heal App Flow
- Uses the **SelfHealApp.apk** to showcase BrowserStack's self-heal capability.
- Located at: `android/testng-examples/SelfHealApp.apk`
- **Run sessions with and without self-heal enabled** to observe how the feature recovers from locator changes or UI modifications:
- **Without self-heal:** Tests may fail if locators change.
- **With self-heal:** Tests should pass even if some locators have changed, as self-heal attempts to find the correct elements automatically.

## How to Compare
- Run your test suite on the Self-Heal App twice: once with `selfHeal: false` and once with `selfHeal: true` in your `browserstack.yml`.
- Compare the results and logs to see the impact of self-healing.

## About the Self-Heal Feature
- The self-heal feature in BrowserStack automatically detects and recovers from locator changes in your app's UI during automated tests.
- If a locator fails (e.g., due to a UI update), self-heal attempts to find the correct element using alternative strategies, allowing your tests to continue without manual intervention.
- This reduces test flakiness and maintenance effort, especially in agile environments with frequent UI changes.
- **To enable self-healing, set `selfHeal: true` in your `browserstack.yml` configuration file.**

#### Example `browserstack.yml` snippet:
```yaml
selfHeal: true
```

## Usage
- Build and upload the APKs to BrowserStack as needed.
- Run your automation scripts using the provided configuration files.
- Make sure `selfHeal: true` is set in your `browserstack.yml` to enable the self-heal feature.
- Review the test results and logs to observe self-healing in action.

### Running Tests with Maven or Gradle
- **For Maven:**
- To run the Base App test suite:
```sh
mvn test -P sampleBaseAppTest
```
- To run the Self-Heal App test suite:
```sh
mvn test -P sampleSelfHealAppTest
```
- **For Gradle:**
- To run the Base App test suite:
```sh
gradle clean sampleBaseAppTest
```
- To run the Self-Heal App test suite:
```sh
gradle clean sampleSelfHealAppTest
```

## Getting Help

If you are running into any issues or have any queries, please check [Browserstack Support page](https://www.browserstack.com/support/app-automate) or [get in touch with us](https://www.browserstack.com/contact?ref=help).
Binary file added android/testng-examples/BaseApp.apk
Binary file not shown.
Binary file added android/testng-examples/SelfHealApp.apk
Binary file not shown.
81 changes: 81 additions & 0 deletions android/testng-examples/browserstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# =============================
# Set BrowserStack Credentials
# =============================
# Add your BrowserStack userName and acccessKey here or set BROWSERSTACK_USERNAME and
# BROWSERSTACK_ACCESS_KEY as env variables
userName: BROWSERSTACK_USERNAME
accessKey: BROWSERSTACK_ACCESS_KEY

# ======================
# BrowserStack Reporting
# ======================
# The following capabilities are used to set up reporting on BrowserStack:
# Set 'projectName' to the name of your project. Example, Marketing Website
projectName: BrowserStack Samples
# Set `buildName` as the name of the job / testsuite being run
buildName: browserstack build
# `buildIdentifier` is a unique id to differentiate every execution that gets appended to
# buildName. Choose your buildIdentifier format from the available expressions:
# ${BUILD_NUMBER} (Default): Generates an incremental counter with every execution
# ${DATE_TIME}: Generates a Timestamp with every execution. Eg. 05-Nov-19:30
# Read more about buildIdentifiers here -> https://www.browserstack.com/docs/automate/selenium/organize-tests
buildIdentifier: '#${BUILD_NUMBER}' # Supports strings along with either/both ${expression}
# Set `framework` of your test suite. Example, `testng`, `cucumber`, `cucumber-testng`
# This property is needed to send test context to BrowserStack (test name, status)
framework: testng

source: testng:appium-sample-sdk:v1.1

app: ./BaseApp.apk
# app: ./SelfHealApp.apk # For testing with the Self Heal App

# =======================================
# Platforms (Browsers / Devices to test)
# =======================================
# Platforms object contains all the browser / device combinations you want to test on.
# Entire list available here -> (https://www.browserstack.com/list-of-browsers-and-platforms/automate)

platforms:
- deviceName: Samsung Galaxy S22 Ultra
osVersion: 12.0
platformName: android
- deviceName: Samsung Galaxy S21
osVersion: 11.0
platformName: android
- deviceName: Google Pixel 6 Pro
osVersion: 12.0
platformName: android

# =======================
# Parallels per Platform
# =======================
# The number of parallel threads to be used for each platform set.
# BrowserStack's SDK runner will select the best strategy based on the configured value
#
# Example 1 - If you have configured 3 platforms and set `parallelsPerPlatform` as 2, a total of 6 (2 * 3) parallel threads will be used on BrowserStack
#
# Example 2 - If you have configured 1 platform and set `parallelsPerPlatform` as 5, a total of 5 (1 * 5) parallel threads will be used on BrowserStack
parallelsPerPlatform: 1

# ==========================================
# BrowserStack Local
# (For localhost, staging/private websites)
# ==========================================
# Set browserStackLocal to true if your website under test is not accessible publicly over the internet
# Learn more about how BrowserStack Local works here -> https://www.browserstack.com/docs/automate/selenium/local-testing-introduction
browserstackLocal: true # <boolean> (Default false)
#browserStackLocalOptions:
#Options to be passed to BrowserStack local in-case of advanced configurations
# localIdentifier: # <string> (Default: null) Needed if you need to run multiple instances of local.
# forceLocal: true # <boolean> (Default: false) Set to true if you need to resolve all your traffic via BrowserStack Local tunnel.
# Entire list of arguments available here -> https://www.browserstack.com/docs/automate/selenium/manage-incoming-connections

# ===================
# Debugging features
# ===================
debug: false # <boolean> # Set to true if you need screenshots for every selenium command ran
networkLogs: false # <boolean> Set to true to enable HAR logs capturing
consoleLogs: errors # <string> Remote browser's console debug levels to be printed (Default: errors)
# Available options are `disable`, `errors`, `warnings`, `info`, `verbose` (Default: errors)

selfHeal: false # Set to true if you want to enable self-healing capabilities in your tests
47 changes: 47 additions & 0 deletions android/testng-examples/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
plugins {
id 'java'
}

repositories { mavenCentral() }

dependencies {
testImplementation 'org.testng:testng:7.5'
implementation 'org.seleniumhq.selenium:selenium-java:4.13.0'
implementation 'io.appium:java-client:8.6.0'
implementation 'commons-io:commons-io:2.11.0'
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
implementation 'com.browserstack:browserstack-java-sdk:latest.release'
}

group = 'com.browserstack'
version = '1.0-SNAPSHOT'
description = 'testng-browserstack'
sourceCompatibility = '1.8'

def browserstackSDKArtifact = configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.find { it.name == 'browserstack-java-sdk' }

tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}

tasks.withType(Test) {
systemProperties = System.properties
}

task sampleBaseAppTest(type: Test) {
useTestNG() {
dependsOn cleanTest
useDefaultListeners = true
suites "src/test/resources/com/browserstack/sample-base-app-test.testng.xml"
jvmArgs "-javaagent:${browserstackSDKArtifact.file}"
}
}

task sampleSelfHealAppTest(type: Test) {
useTestNG() {
dependsOn cleanTest
useDefaultListeners = true
suites "src/test/resources/com/browserstack/sample-self-heal-app-test.testng.xml"
jvmArgs "-javaagent:${browserstackSDKArtifact.file}"
}
}
127 changes: 127 additions & 0 deletions android/testng-examples/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?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.browserstack</groupId>
<artifactId>testng-browserstack-android</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>testng-appium-app</name>
<url>https://github.com/browserstack/selfheal-demo-browserstack</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<surefire.version>2.19.1</surefire.version>
<surefire.plugin.version>3.0.0-M5</surefire.plugin.version>
<config.file>default</config.file>
</properties>

<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.5</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.13.0</version>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>8.6.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.browserstack</groupId>
<artifactId>browserstack-java-sdk</artifactId>
<version>LATEST</version>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>getClasspathFilenames</id>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/com/browserstack/sample-base-app-test.testng.xml</suiteXmlFile>
</suiteXmlFiles>
<argLine>-javaagent:${com.browserstack:browserstack-java-sdk:jar}</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>sampleBaseAppTest</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/com/browserstack/sample-base-app-test.testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>sampleSelfHealAppTest</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/com/browserstack/sample-self-heal-app-test.testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
16 changes: 16 additions & 0 deletions android/testng-examples/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pluginManagement {
repositories {
mavenCentral()
mavenLocal()
gradlePluginPortal()
}

resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.browserstack.gradle-sdk") {
useModule("com.browserstack:gradle-sdk:1.1.2")
}
}
}
}
rootProject.name = 'testng-browserstack-android'
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.browserstack;

import java.net.URL;

import org.openqa.selenium.MutableCapabilities;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;


public class AppiumTest {

public AndroidDriver driver;

@BeforeMethod(alwaysRun=true)
public void setUp() throws Exception {
MutableCapabilities capabilities = new UiAutomator2Options();
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),capabilities);
}

@AfterMethod(alwaysRun=true)
public void tearDown() throws Exception {
driver.quit();
}
}
Loading