Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cfad198

Browse files
committedJan 4, 2022
Uploading project
1 parent 2c4da17 commit cfad198

38 files changed

+2048
-25
lines changed
 

‎.gitignore

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
1-
# Compiled class file
2-
*.class
3-
4-
# Log file
5-
*.log
6-
7-
# BlueJ files
8-
*.ctxt
9-
10-
# Mobile Tools for Java (J2ME)
11-
.mtj.tmp/
12-
13-
# Package Files #
14-
*.jar
15-
*.war
16-
*.nar
17-
*.ear
18-
*.zip
19-
*.tar.gz
20-
*.rar
21-
22-
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23-
hs_err_pid*
1+
target/
2+
build/
3+
.project
4+
.settings/
5+
.classpath
6+
.idea/
7+
.gradle/
8+
*.iml
9+
.DS_Store
10+
!gradle/wrapper/*

‎README.md

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,76 @@
1-
# browserstack-demo-testng
2-
BrowserStack demo across products using Java TestNG
1+
# BrowserStack Demo TestNG <a href="https://www.browserstack.com/"><img src="https://www.vectorlogo.zone/logos/browserstack/browserstack-icon.svg" alt="BrowserStack" height="30"/></a> <a href="https://java.com"><img src="https://www.vectorlogo.zone/logos/java/java-icon.svg" alt="Java" height="30" /></a> <a href="https://www.selenium.dev/"><img src="https://seeklogo.com/images/S/selenium-logo-DB9103D7CF-seeklogo.com.png" alt="Selenium" height="30" /></a>
2+
3+
| Product | Status |
4+
| --- | --- |
5+
| Automate | [![BrowserStack Status](https://automate.browserstack.com/badge.svg?badge_key=VVJsYk9IdWRoSG5TQldSbTE4elZZenlTS0V3S3hpWVRxTG9qWGdQVW5BVT0tLUFyV29QSTMwa1NiUkVmVWFIeUFoM2c9PQ==--36aaf62782c041f259b2e865d0364319ebc0947a)](https://automate.browserstack.com/public-build/VVJsYk9IdWRoSG5TQldSbTE4elZZenlTS0V3S3hpWVRxTG9qWGdQVW5BVT0tLUFyV29QSTMwa1NiUkVmVWFIeUFoM2c9PQ==--36aaf62782c041f259b2e865d0364319ebc0947a) |
6+
| App-Automate | [![BrowserStack Status](https://app-automate.browserstack.com/badge.svg?badge_key=czEwd3UxdlA0UkFuY0NpZ2h0eVI4V25qbTBwL1drbGg4My9rdUxneUdOYz0tLTJZT0NwVTlhVXVHbEROenhIamVFQlE9PQ==--e893df98cc09afe78a93a9b2ae4fb36a6495ac52)](https://app-automate.browserstack.com/public-build/czEwd3UxdlA0UkFuY0NpZ2h0eVI4V25qbTBwL1drbGg4My9rdUxneUdOYz0tLTJZT0NwVTlhVXVHbEROenhIamVFQlE9PQ==--e893df98cc09afe78a93a9b2ae4fb36a6495ac52) |
7+
8+
Test execution using [TestNG](http://testng.org) on BrowserStack.
9+
10+
## Using Maven
11+
12+
### Setup
13+
14+
- Clone the repo
15+
- Install dependencies `mvn compile`
16+
- Update the environment variables with your [BrowserStack Username and Access Key](https://www.browserstack.com/accounts/settings)
17+
18+
### Running your tests
19+
20+
#### Automate
21+
22+
- To run a single test, run `mvn -P single test`
23+
- To run a local test, run `mvn -P local test`
24+
- To run parallel tests, run `mvn -P parallel test`
25+
- To run parallel tests on mobile browsers, run `mvn -P mobile test`
26+
- To run parallel local tests, run `mvn -P local-parallel test`
27+
- To run a failed test, run `mvn -P fail test`
28+
29+
#### App-Automate
30+
31+
- To run a single test, run `mvn -P appium-single test`
32+
- To run a local test, run `mvn -P appium-local test`
33+
- To run parallel tests, run `mvn -P appium-parallel test`
34+
- To run a failed test, run `mvn -P appium-fail test`
35+
- To run an Espresso test, run `mvn -P espresso test`
36+
- To run a XCUI test, run `mvn -P xcuitest test`
37+
38+
## Using Gradle
39+
40+
### Setup
41+
42+
* Clone the repo
43+
* Install dependencies `./gradlew build`
44+
* Update the environment variables with your [BrowserStack Username and Access Key](https://www.browserstack.com/accounts/settings)
45+
46+
### Running your tests
47+
48+
#### Automate
49+
50+
- To run a single test, run `./gradlew single`
51+
- To run a local test, run `./gradlew local`
52+
- To run parallel tests, run `./gradlew parallel`
53+
- To run parallel tests on mobile browsers, run `./gradlew mobile`
54+
- To run parallel local tests, run `./gradlew local-parallel`
55+
- To run a failed test, run `./gradlew fail`
56+
57+
#### App-Automate
58+
59+
- To run a single test, run `./gradlew appium-single`
60+
- To run a local test, run `./gradlew appium-local`
61+
- To run parallel tests, run `./gradlew appium-parallel`
62+
- To run a failed test, run `./gradlew appium-fail`
63+
- To run an Espresso test, run `./gradlew espresso`
64+
- To run a XCUI test, run `./gradlew xcuitest`
65+
66+
## Notes
67+
- You can view your Automate test results on the [BrowserStack Automate dashboard](https://automate.browserstack.com/).
68+
- You can view your App-Automate test results on the [BrowserStack App-Automate dashboard](https://app-automate.browserstack.com/).
69+
- To start a locally hosted website, run `mvn -P start-server compile exec:java`. Website will open on `localhost:8000`.
70+
- To use specific number of threads:
71+
- For Maven use `-Dthreads=<thread-count>`. Example `-Dthreads=3`
72+
- For Gradle use `-Pthreads=<thread-count>`. Example `-Pthreads=3`
73+
- Export the environment variables for the Username and Access Key of your BrowserStack account.
74+
```sh
75+
export BROWSERSTACK_USERNAME=<browserstack-username> && export BROWSERSTACK_ACCESS_KEY=<browserstack-access-key>
76+
```

‎build.gradle

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
group = 'com.browserstack'
2+
version = '1.0'
3+
description = 'browserstack-java-testng'
4+
5+
apply plugin: 'java'
6+
7+
repositories {
8+
mavenCentral()
9+
}
10+
11+
sourceSets {
12+
test.java.srcDirs = ['src/test/java']
13+
test.resources.srcDirs = ['src/test/resources']
14+
}
15+
16+
dependencies {
17+
implementation 'io.appium:java-client:7.5.1'
18+
implementation 'org.testng:testng:7.4.0'
19+
implementation 'com.browserstack:browserstack-local-java:1.0.3'
20+
implementation 'io.rest-assured:rest-assured:4.3.3'
21+
}
22+
23+
tasks.register('single', Test) {
24+
useTestNG()
25+
include '**/SingleTest.class'
26+
testLogging {
27+
events "PASSED", "FAILED", "SKIPPED"
28+
}
29+
}
30+
31+
tasks.register('parallel', Test) {
32+
useTestNG() {
33+
suites 'src/test/resources/web/suites/parallel.testng.xml'
34+
parallel project.property('parallel')
35+
threadCount Integer.parseInt(project.property('threads'))
36+
}
37+
testLogging {
38+
events "PASSED", "FAILED", "SKIPPED"
39+
}
40+
}
41+
42+
tasks.register('fail', Test) {
43+
useTestNG()
44+
include '**/FailTest.class'
45+
testLogging {
46+
events "PASSED", "FAILED", "SKIPPED"
47+
}
48+
}
49+
50+
tasks.register('mobile', Test) {
51+
useTestNG() {
52+
suites 'src/test/resources/web/suites/mobile.testng.xml'
53+
parallel project.property('parallel')
54+
threadCount Integer.parseInt(project.property('threads'))
55+
}
56+
testLogging {
57+
events "PASSED", "FAILED", "SKIPPED"
58+
}
59+
}
60+
61+
tasks.register('local', Test) {
62+
useTestNG()
63+
include '**/LocalTest.class'
64+
testLogging {
65+
events "PASSED", "FAILED", "SKIPPED"
66+
}
67+
}
68+
69+
tasks.register('local-parallel', Test) {
70+
useTestNG() {
71+
suites 'src/test/resources/web/suites/local.testng.xml'
72+
parallel project.property('parallel')
73+
threadCount Integer.parseInt(project.property('threads'))
74+
}
75+
testLogging {
76+
events "PASSED", "FAILED", "SKIPPED"
77+
}
78+
}
79+
80+
tasks.register('appium-single', Test) {
81+
useTestNG()
82+
include '**/AppiumSingleTest.class'
83+
testLogging {
84+
events "PASSED", "FAILED", "SKIPPED"
85+
}
86+
}
87+
88+
tasks.register('appium-parallel', Test) {
89+
useTestNG() {
90+
suites 'src/test/resources/app/suites/parallel.testng.xml'
91+
parallel project.property('parallel')
92+
threadCount Integer.parseInt(project.property('threads'))
93+
}
94+
testLogging {
95+
events "PASSED", "FAILED", "SKIPPED"
96+
}
97+
}
98+
99+
tasks.register('appium-local', Test) {
100+
useTestNG()
101+
include '**/AppiumLocalTest.class'
102+
testLogging {
103+
events "PASSED", "FAILED", "SKIPPED"
104+
}
105+
}
106+
107+
tasks.register('appium-fail', Test) {
108+
useTestNG()
109+
include '**/AppiumFailTest.class'
110+
testLogging {
111+
events "PASSED", "FAILED", "SKIPPED"
112+
}
113+
}
114+
115+
tasks.register('espresso', Test) {
116+
useTestNG()
117+
include '**/EspressoTest.class'
118+
testLogging {
119+
events "PASSED", "FAILED", "SKIPPED"
120+
}
121+
}
122+
123+
tasks.register('xcuitest', Test) {
124+
useTestNG()
125+
include '**/XCUITest.class'
126+
testLogging {
127+
events "PASSED", "FAILED", "SKIPPED"
128+
}
129+
}

‎gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
parallel=tests
2+
threads=5

‎gradle/wrapper/gradle-wrapper.jar

57.8 KB
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
4+
zipStoreBase=GRADLE_USER_HOME
5+
zipStorePath=wrapper/dists

‎gradlew

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#!/usr/bin/env sh
2+
3+
#
4+
# Copyright 2015 the original author or authors.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# https://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
##############################################################################
20+
##
21+
## Gradle start up script for UN*X
22+
##
23+
##############################################################################
24+
25+
# Attempt to set APP_HOME
26+
# Resolve links: $0 may be a link
27+
PRG="$0"
28+
# Need this for relative symlinks.
29+
while [ -h "$PRG" ] ; do
30+
ls=`ls -ld "$PRG"`
31+
link=`expr "$ls" : '.*-> \(.*\)$'`
32+
if expr "$link" : '/.*' > /dev/null; then
33+
PRG="$link"
34+
else
35+
PRG=`dirname "$PRG"`"/$link"
36+
fi
37+
done
38+
SAVED="`pwd`"
39+
cd "`dirname \"$PRG\"`/" >/dev/null
40+
APP_HOME="`pwd -P`"
41+
cd "$SAVED" >/dev/null
42+
43+
APP_NAME="Gradle"
44+
APP_BASE_NAME=`basename "$0"`
45+
46+
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47+
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48+
49+
# Use the maximum available, or set MAX_FD != -1 to use that value.
50+
MAX_FD="maximum"
51+
52+
warn () {
53+
echo "$*"
54+
}
55+
56+
die () {
57+
echo
58+
echo "$*"
59+
echo
60+
exit 1
61+
}
62+
63+
# OS specific support (must be 'true' or 'false').
64+
cygwin=false
65+
msys=false
66+
darwin=false
67+
nonstop=false
68+
case "`uname`" in
69+
CYGWIN* )
70+
cygwin=true
71+
;;
72+
Darwin* )
73+
darwin=true
74+
;;
75+
MSYS* | MINGW* )
76+
msys=true
77+
;;
78+
NONSTOP* )
79+
nonstop=true
80+
;;
81+
esac
82+
83+
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84+
85+
86+
# Determine the Java command to use to start the JVM.
87+
if [ -n "$JAVA_HOME" ] ; then
88+
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89+
# IBM's JDK on AIX uses strange locations for the executables
90+
JAVACMD="$JAVA_HOME/jre/sh/java"
91+
else
92+
JAVACMD="$JAVA_HOME/bin/java"
93+
fi
94+
if [ ! -x "$JAVACMD" ] ; then
95+
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96+
97+
Please set the JAVA_HOME variable in your environment to match the
98+
location of your Java installation."
99+
fi
100+
else
101+
JAVACMD="java"
102+
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103+
104+
Please set the JAVA_HOME variable in your environment to match the
105+
location of your Java installation."
106+
fi
107+
108+
# Increase the maximum file descriptors if we can.
109+
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110+
MAX_FD_LIMIT=`ulimit -H -n`
111+
if [ $? -eq 0 ] ; then
112+
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113+
MAX_FD="$MAX_FD_LIMIT"
114+
fi
115+
ulimit -n $MAX_FD
116+
if [ $? -ne 0 ] ; then
117+
warn "Could not set maximum file descriptor limit: $MAX_FD"
118+
fi
119+
else
120+
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121+
fi
122+
fi
123+
124+
# For Darwin, add options to specify how the application appears in the dock
125+
if $darwin; then
126+
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127+
fi
128+
129+
# For Cygwin or MSYS, switch paths to Windows format before running java
130+
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131+
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132+
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133+
134+
JAVACMD=`cygpath --unix "$JAVACMD"`
135+
136+
# We build the pattern for arguments to be converted via cygpath
137+
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138+
SEP=""
139+
for dir in $ROOTDIRSRAW ; do
140+
ROOTDIRS="$ROOTDIRS$SEP$dir"
141+
SEP="|"
142+
done
143+
OURCYGPATTERN="(^($ROOTDIRS))"
144+
# Add a user-defined pattern to the cygpath arguments
145+
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146+
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147+
fi
148+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
149+
i=0
150+
for arg in "$@" ; do
151+
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152+
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153+
154+
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155+
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156+
else
157+
eval `echo args$i`="\"$arg\""
158+
fi
159+
i=`expr $i + 1`
160+
done
161+
case $i in
162+
0) set -- ;;
163+
1) set -- "$args0" ;;
164+
2) set -- "$args0" "$args1" ;;
165+
3) set -- "$args0" "$args1" "$args2" ;;
166+
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167+
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168+
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169+
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170+
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171+
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172+
esac
173+
fi
174+
175+
# Escape application args
176+
save () {
177+
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178+
echo " "
179+
}
180+
APP_ARGS=`save "$@"`
181+
182+
# Collect all arguments for the java command, following the shell quoting and substitution rules
183+
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184+
185+
exec "$JAVACMD" "$@"

‎gradlew.bat

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
@rem
2+
@rem Copyright 2015 the original author or authors.
3+
@rem
4+
@rem Licensed under the Apache License, Version 2.0 (the "License");
5+
@rem you may not use this file except in compliance with the License.
6+
@rem You may obtain a copy of the License at
7+
@rem
8+
@rem https://www.apache.org/licenses/LICENSE-2.0
9+
@rem
10+
@rem Unless required by applicable law or agreed to in writing, software
11+
@rem distributed under the License is distributed on an "AS IS" BASIS,
12+
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
@rem See the License for the specific language governing permissions and
14+
@rem limitations under the License.
15+
@rem
16+
17+
@if "%DEBUG%" == "" @echo off
18+
@rem ##########################################################################
19+
@rem
20+
@rem Gradle startup script for Windows
21+
@rem
22+
@rem ##########################################################################
23+
24+
@rem Set local scope for the variables with windows NT shell
25+
if "%OS%"=="Windows_NT" setlocal
26+
27+
set DIRNAME=%~dp0
28+
if "%DIRNAME%" == "" set DIRNAME=.
29+
set APP_BASE_NAME=%~n0
30+
set APP_HOME=%DIRNAME%
31+
32+
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
33+
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34+
35+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36+
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37+
38+
@rem Find java.exe
39+
if defined JAVA_HOME goto findJavaFromJavaHome
40+
41+
set JAVA_EXE=java.exe
42+
%JAVA_EXE% -version >NUL 2>&1
43+
if "%ERRORLEVEL%" == "0" goto execute
44+
45+
echo.
46+
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47+
echo.
48+
echo Please set the JAVA_HOME variable in your environment to match the
49+
echo location of your Java installation.
50+
51+
goto fail
52+
53+
:findJavaFromJavaHome
54+
set JAVA_HOME=%JAVA_HOME:"=%
55+
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56+
57+
if exist "%JAVA_EXE%" goto execute
58+
59+
echo.
60+
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61+
echo.
62+
echo Please set the JAVA_HOME variable in your environment to match the
63+
echo location of your Java installation.
64+
65+
goto fail
66+
67+
:execute
68+
@rem Setup the command line
69+
70+
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71+
72+
73+
@rem Execute Gradle
74+
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75+
76+
:end
77+
@rem End local scope for the variables with windows NT shell
78+
if "%ERRORLEVEL%"=="0" goto mainEnd
79+
80+
:fail
81+
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82+
rem the _cmd.exe /c_ return code!
83+
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84+
exit /b 1
85+
86+
:mainEnd
87+
if "%OS%"=="Windows_NT" endlocal
88+
89+
:omega

‎pom.xml

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.browserstack</groupId>
8+
<artifactId>browserstack-java-testng</artifactId>
9+
<version>1.0</version>
10+
11+
<properties>
12+
<maven.compiler.source>1.8</maven.compiler.source>
13+
<maven.compiler.target>1.8</maven.compiler.target>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
16+
<threads>5</threads>
17+
</properties>
18+
19+
<dependencies>
20+
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
21+
<dependency>
22+
<groupId>io.appium</groupId>
23+
<artifactId>java-client</artifactId>
24+
<version>7.5.1</version>
25+
</dependency>
26+
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
27+
<dependency>
28+
<groupId>org.testng</groupId>
29+
<artifactId>testng</artifactId>
30+
<version>7.4.0</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>com.browserstack</groupId>
34+
<artifactId>browserstack-local-java</artifactId>
35+
<version>1.0.3</version>
36+
</dependency>
37+
<!-- https://mvnrepository.com/artifact/io.rest-assured/rest-assured -->
38+
<dependency>
39+
<groupId>io.rest-assured</groupId>
40+
<artifactId>rest-assured</artifactId>
41+
<version>4.3.3</version>
42+
</dependency>
43+
</dependencies>
44+
45+
<profiles>
46+
<profile>
47+
<id>single</id>
48+
<activation>
49+
<activeByDefault>true</activeByDefault>
50+
</activation>
51+
<build>
52+
<plugins>
53+
<plugin>
54+
<groupId>org.apache.maven.plugins</groupId>
55+
<artifactId>maven-surefire-plugin</artifactId>
56+
<version>3.0.0-M5</version>
57+
<configuration>
58+
<includes>
59+
<include>SingleTest.java</include>
60+
</includes>
61+
</configuration>
62+
</plugin>
63+
</plugins>
64+
</build>
65+
</profile>
66+
<profile>
67+
<id>parallel</id>
68+
<build>
69+
<plugins>
70+
<plugin>
71+
<groupId>org.apache.maven.plugins</groupId>
72+
<artifactId>maven-surefire-plugin</artifactId>
73+
<version>3.0.0-M5</version>
74+
<configuration>
75+
<parallel>tests</parallel>
76+
<threadCount>${threads}</threadCount>
77+
<suiteXmlFiles>
78+
<suiteXmlFile>src/test/resources/web/suites/parallel.testng.xml</suiteXmlFile>
79+
</suiteXmlFiles>
80+
</configuration>
81+
</plugin>
82+
</plugins>
83+
</build>
84+
</profile>
85+
<profile>
86+
<id>fail</id>
87+
<build>
88+
<plugins>
89+
<plugin>
90+
<groupId>org.apache.maven.plugins</groupId>
91+
<artifactId>maven-surefire-plugin</artifactId>
92+
<version>3.0.0-M5</version>
93+
<configuration>
94+
<includes>
95+
<include>FailTest.java</include>
96+
</includes>
97+
</configuration>
98+
</plugin>
99+
</plugins>
100+
</build>
101+
</profile>
102+
<profile>
103+
<id>mobile</id>
104+
<build>
105+
<plugins>
106+
<plugin>
107+
<groupId>org.apache.maven.plugins</groupId>
108+
<artifactId>maven-surefire-plugin</artifactId>
109+
<version>3.0.0-M5</version>
110+
<configuration>
111+
<parallel>tests</parallel>
112+
<threadCount>${threads}</threadCount>
113+
<suiteXmlFiles>
114+
<suiteXmlFile>src/test/resources/web/suites/mobile.testng.xml</suiteXmlFile>
115+
</suiteXmlFiles>
116+
</configuration>
117+
</plugin>
118+
</plugins>
119+
</build>
120+
</profile>
121+
<profile>
122+
<id>local</id>
123+
<build>
124+
<plugins>
125+
<plugin>
126+
<groupId>org.apache.maven.plugins</groupId>
127+
<artifactId>maven-surefire-plugin</artifactId>
128+
<version>3.0.0-M5</version>
129+
<configuration>
130+
<includes>
131+
<include>LocalTest.java</include>
132+
</includes>
133+
</configuration>
134+
</plugin>
135+
</plugins>
136+
</build>
137+
</profile>
138+
<profile>
139+
<id>local-parallel</id>
140+
<build>
141+
<plugins>
142+
<plugin>
143+
<groupId>org.apache.maven.plugins</groupId>
144+
<artifactId>maven-surefire-plugin</artifactId>
145+
<version>3.0.0-M5</version>
146+
<configuration>
147+
<parallel>tests</parallel>
148+
<threadCount>${threads}</threadCount>
149+
<suiteXmlFiles>
150+
<suiteXmlFile>src/test/resources/web/suites/local.testng.xml</suiteXmlFile>
151+
</suiteXmlFiles>
152+
</configuration>
153+
</plugin>
154+
</plugins>
155+
</build>
156+
</profile>
157+
<profile>
158+
<id>start-server</id>
159+
<build>
160+
<plugins>
161+
<plugin>
162+
<groupId>org.codehaus.mojo</groupId>
163+
<artifactId>exec-maven-plugin</artifactId>
164+
<version>3.0.0</version>
165+
<configuration>
166+
<mainClass>com.local.server.MyHttpServer</mainClass>
167+
</configuration>
168+
</plugin>
169+
</plugins>
170+
</build>
171+
</profile>
172+
<profile>
173+
<id>appium-single</id>
174+
<build>
175+
<plugins>
176+
<plugin>
177+
<groupId>org.apache.maven.plugins</groupId>
178+
<artifactId>maven-surefire-plugin</artifactId>
179+
<version>3.0.0-M5</version>
180+
<configuration>
181+
<includes>
182+
<include>AppiumSingleTest.java</include>
183+
</includes>
184+
</configuration>
185+
</plugin>
186+
</plugins>
187+
</build>
188+
</profile>
189+
<profile>
190+
<id>appium-parallel</id>
191+
<build>
192+
<plugins>
193+
<plugin>
194+
<groupId>org.apache.maven.plugins</groupId>
195+
<artifactId>maven-surefire-plugin</artifactId>
196+
<version>3.0.0-M5</version>
197+
<configuration>
198+
<parallel>tests</parallel>
199+
<threadCount>${threads}</threadCount>
200+
<suiteXmlFiles>
201+
<suiteXmlFile>src/test/resources/app/suites/parallel.testng.xml</suiteXmlFile>
202+
</suiteXmlFiles>
203+
</configuration>
204+
</plugin>
205+
</plugins>
206+
</build>
207+
</profile>
208+
<profile>
209+
<id>appium-local</id>
210+
<build>
211+
<plugins>
212+
<plugin>
213+
<groupId>org.apache.maven.plugins</groupId>
214+
<artifactId>maven-surefire-plugin</artifactId>
215+
<version>3.0.0-M5</version>
216+
<configuration>
217+
<includes>
218+
<include>AppiumLocalTest.java</include>
219+
</includes>
220+
</configuration>
221+
</plugin>
222+
</plugins>
223+
</build>
224+
</profile>
225+
<profile>
226+
<id>appium-fail</id>
227+
<build>
228+
<plugins>
229+
<plugin>
230+
<groupId>org.apache.maven.plugins</groupId>
231+
<artifactId>maven-surefire-plugin</artifactId>
232+
<version>3.0.0-M5</version>
233+
<configuration>
234+
<includes>
235+
<include>AppiumFailTest.java</include>
236+
</includes>
237+
</configuration>
238+
</plugin>
239+
</plugins>
240+
</build>
241+
</profile>
242+
<profile>
243+
<id>espresso</id>
244+
<build>
245+
<plugins>
246+
<plugin>
247+
<groupId>org.apache.maven.plugins</groupId>
248+
<artifactId>maven-surefire-plugin</artifactId>
249+
<version>3.0.0-M5</version>
250+
<configuration>
251+
<includes>
252+
<include>EspressoTest.java</include>
253+
</includes>
254+
</configuration>
255+
</plugin>
256+
</plugins>
257+
</build>
258+
</profile>
259+
<profile>
260+
<id>xcuitest</id>
261+
<build>
262+
<plugins>
263+
<plugin>
264+
<groupId>org.apache.maven.plugins</groupId>
265+
<artifactId>maven-surefire-plugin</artifactId>
266+
<version>3.0.0-M5</version>
267+
<configuration>
268+
<includes>
269+
<include>XCUITest.java</include>
270+
</includes>
271+
</configuration>
272+
</plugin>
273+
</plugins>
274+
</build>
275+
</profile>
276+
</profiles>
277+
</project>

‎settings.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/*
2+
* This file was generated by the Gradle 'init' task.
3+
*/
4+
5+
rootProject.name = 'browserstack-java-testng'
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.local.server;
2+
3+
import com.sun.net.httpserver.HttpExchange;
4+
import com.sun.net.httpserver.HttpHandler;
5+
import com.sun.net.httpserver.HttpServer;
6+
7+
import java.io.File;
8+
import java.io.IOException;
9+
import java.io.OutputStream;
10+
import java.net.InetSocketAddress;
11+
import java.nio.file.Files;
12+
13+
public class MyHttpServer {
14+
15+
public static void main(String[] args) throws IOException {
16+
int port = 8000;
17+
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
18+
System.out.println("server started at " + port);
19+
server.createContext("/", new RootHandler());
20+
server.setExecutor(null);
21+
server.start();
22+
}
23+
24+
private static class RootHandler implements HttpHandler {
25+
26+
@Override
27+
public void handle(HttpExchange he) throws IOException {
28+
File file = new File("src/main/resources/index.html");
29+
he.sendResponseHeaders(200, file.length());
30+
try (OutputStream os = he.getResponseBody()) {
31+
Files.copy(file.toPath(), os);
32+
}
33+
}
34+
}
35+
36+
}

‎src/main/resources/index.html

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Local Server</title>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
8+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
9+
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
10+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
11+
</head>
12+
<body>
13+
14+
<div class="jumbotron text-center">
15+
<h1>Locally Hosted Webpage</h1>
16+
<p>This is a locally hosted webpage!</p>
17+
<img src="https://www.insightpartners.com//assets/media/2021/06/browserstack.png"
18+
class="mx-auto d-block" alt="BrowserStack">
19+
</div>
20+
21+
<div class="container">
22+
<div class="row">
23+
<div class="col-sm-4">
24+
<h3>Column 1</h3>
25+
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
26+
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p>
27+
</div>
28+
<div class="col-sm-4">
29+
<h3>Column 2</h3>
30+
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
31+
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p>
32+
</div>
33+
<div class="col-sm-4">
34+
<h3>Column 3</h3>
35+
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
36+
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p>
37+
</div>
38+
</div>
39+
</div>
40+
41+
</body>
42+
</html>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.app.test;
2+
3+
import io.appium.java_client.MobileDriver;
4+
import io.appium.java_client.MobileElement;
5+
import io.appium.java_client.android.AndroidDriver;
6+
import io.restassured.authentication.PreemptiveBasicAuthScheme;
7+
import io.restassured.builder.RequestSpecBuilder;
8+
import io.restassured.builder.ResponseSpecBuilder;
9+
import org.openqa.selenium.JavascriptExecutor;
10+
import org.openqa.selenium.NotFoundException;
11+
import org.openqa.selenium.remote.DesiredCapabilities;
12+
import org.openqa.selenium.support.ui.FluentWait;
13+
import org.openqa.selenium.support.ui.Wait;
14+
import org.testng.Assert;
15+
import org.testng.annotations.AfterMethod;
16+
import org.testng.annotations.BeforeMethod;
17+
import org.testng.annotations.BeforeSuite;
18+
import org.testng.annotations.Test;
19+
20+
import java.io.File;
21+
import java.lang.reflect.Method;
22+
import java.net.MalformedURLException;
23+
import java.net.URL;
24+
import java.time.Duration;
25+
import java.util.List;
26+
27+
import static io.restassured.RestAssured.*;
28+
29+
public class AppiumFailTest {
30+
31+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
32+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
33+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
34+
private MobileDriver<MobileElement> driver;
35+
36+
@BeforeSuite(alwaysRun = true)
37+
public void setupApp() {
38+
PreemptiveBasicAuthScheme authenticationScheme = new PreemptiveBasicAuthScheme();
39+
authenticationScheme.setUserName(USERNAME);
40+
authenticationScheme.setPassword(ACCESS_KEY);
41+
requestSpecification = new RequestSpecBuilder()
42+
.setBaseUri("https://api-cloud.browserstack.com")
43+
.setBasePath("app-automate")
44+
.setAuth(authenticationScheme)
45+
.build();
46+
responseSpecification = new ResponseSpecBuilder()
47+
.expectStatusCode(200)
48+
.build();
49+
List<String> apps = get("recent_apps").jsonPath().getList("custom_id");
50+
if (apps == null || !apps.contains("DemoApp")) {
51+
System.out.println("Uploading app...");
52+
given()
53+
.header("Content-Type", "multipart/form-data")
54+
.multiPart("file", new File("src/test/resources/app/appData/WikipediaSample.apk"), "text/apk")
55+
.param("custom_id", "DemoApp")
56+
.post("upload");
57+
} else {
58+
System.out.println("Using previously uploaded app...");
59+
}
60+
}
61+
62+
@BeforeMethod(alwaysRun = true)
63+
public void setup(Method m) throws MalformedURLException {
64+
DesiredCapabilities caps = new DesiredCapabilities();
65+
caps.setCapability("project", "BrowserStack Java TestNG");
66+
caps.setCapability("build", "Demo");
67+
caps.setCapability("name", m.getName() + " - Google Pixel 3");
68+
69+
caps.setCapability("device", "Google Pixel 3");
70+
caps.setCapability("os_version", "10.0");
71+
caps.setCapability("real_mobile", "true");
72+
caps.setCapability("app", "DemoApp");
73+
74+
caps.setCapability("browserstack.user", USERNAME);
75+
caps.setCapability("browserstack.key", ACCESS_KEY);
76+
caps.setCapability("browserstack.debug", "true");
77+
78+
driver = new AndroidDriver<>(new URL(URL), caps);
79+
}
80+
81+
@Test
82+
public void searchWikipedia() {
83+
Wait<MobileDriver<MobileElement>> wait = new FluentWait<>(driver)
84+
.withTimeout(Duration.ofSeconds(10))
85+
.pollingEvery(Duration.ofMillis(500))
86+
.ignoring(NotFoundException.class);
87+
MobileElement searchElement = wait.until(d -> d.findElementByAccessibilityId("Search Wikipedia"));
88+
searchElement.click();
89+
MobileElement insertTextElement = wait.until(d -> d.findElementById("org.wikipedia.alpha:id/search_src_text"));
90+
insertTextElement.sendKeys("BrowserStack");
91+
List<MobileElement> allProductName = wait.until(d -> d.findElementsByClassName("android.widget.TextView"));
92+
Assert.assertTrue(allProductName.isEmpty(), "Products are present");
93+
}
94+
95+
@AfterMethod(alwaysRun = true)
96+
public void tearDown(Method m) {
97+
JavascriptExecutor js = (JavascriptExecutor) driver;
98+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"failed\", \"reason\": \"" + m.getName() + " failed\"}}");
99+
driver.quit();
100+
}
101+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package com.app.test;
2+
3+
import com.browserstack.local.Local;
4+
import io.appium.java_client.MobileDriver;
5+
import io.appium.java_client.MobileElement;
6+
import io.appium.java_client.android.AndroidDriver;
7+
import io.restassured.authentication.PreemptiveBasicAuthScheme;
8+
import io.restassured.builder.RequestSpecBuilder;
9+
import io.restassured.builder.ResponseSpecBuilder;
10+
import org.openqa.selenium.JavascriptExecutor;
11+
import org.openqa.selenium.NotFoundException;
12+
import org.openqa.selenium.remote.DesiredCapabilities;
13+
import org.openqa.selenium.support.ui.FluentWait;
14+
import org.openqa.selenium.support.ui.Wait;
15+
import org.testng.Assert;
16+
import org.testng.annotations.*;
17+
18+
import java.io.File;
19+
import java.lang.reflect.Method;
20+
import java.net.MalformedURLException;
21+
import java.net.URL;
22+
import java.time.Duration;
23+
import java.util.HashMap;
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
import static io.restassured.RestAssured.*;
28+
29+
public class AppiumLocalTest {
30+
31+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
32+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
33+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
34+
private MobileDriver<MobileElement> driver;
35+
private Local local;
36+
37+
@BeforeSuite(alwaysRun = true)
38+
public void setupAppAndLocal() throws Exception {
39+
PreemptiveBasicAuthScheme authenticationScheme = new PreemptiveBasicAuthScheme();
40+
authenticationScheme.setUserName(USERNAME);
41+
authenticationScheme.setPassword(ACCESS_KEY);
42+
requestSpecification = new RequestSpecBuilder()
43+
.setBaseUri("https://api-cloud.browserstack.com")
44+
.setBasePath("app-automate")
45+
.setAuth(authenticationScheme)
46+
.build();
47+
responseSpecification = new ResponseSpecBuilder()
48+
.expectStatusCode(200)
49+
.build();
50+
List<String> customIds = get("recent_apps").jsonPath().getList("custom_id");
51+
if (customIds == null || !customIds.contains("LocalApp")) {
52+
System.out.println("Uploading app...");
53+
given()
54+
.header("Content-Type", "multipart/form-data")
55+
.multiPart("file", new File("src/test/resources/app/appdata/LocalSample.apk"), "text/apk")
56+
.param("custom_id", "LocalApp")
57+
.post("upload");
58+
} else {
59+
System.out.println("Using previously uploaded app...");
60+
}
61+
System.out.println("Connecting local");
62+
local = new Local();
63+
Map<String, String> options = new HashMap<>();
64+
options.put("key", ACCESS_KEY);
65+
local.start(options);
66+
System.out.println("Connected. Now testing...");
67+
}
68+
69+
@BeforeMethod(alwaysRun = true)
70+
public void setupDriver(Method m) throws MalformedURLException {
71+
DesiredCapabilities caps = new DesiredCapabilities();
72+
caps.setCapability("project", "BrowserStack Java TestNG");
73+
caps.setCapability("build", "Demo");
74+
caps.setCapability("name", m.getName() + " - Google Pixel 3");
75+
76+
caps.setCapability("device", "Google Pixel 3");
77+
caps.setCapability("os_version", "9.0");
78+
caps.setCapability("real_mobile", "true");
79+
caps.setCapability("app", "LocalApp");
80+
81+
caps.setCapability("browserstack.user", USERNAME);
82+
caps.setCapability("browserstack.key", ACCESS_KEY);
83+
caps.setCapability("browserstack.debug", "true");
84+
caps.setCapability("browserstack.local", "true");
85+
86+
driver = new AndroidDriver<>(new URL(URL), caps);
87+
}
88+
89+
@Test
90+
public void localAppCheckAssets() {
91+
Wait<MobileDriver<MobileElement>> wait = new FluentWait<>(driver)
92+
.withTimeout(Duration.ofSeconds(10))
93+
.pollingEvery(Duration.ofMillis(500))
94+
.ignoring(NotFoundException.class);
95+
MobileElement searchElement = wait.until(d -> d.findElementById("com.example.android.basicnetworking:id/test_action"));
96+
searchElement.click();
97+
List<MobileElement> allTextViewElements = wait.until(d -> d.findElementsByClassName("android.widget.TextView"));
98+
boolean textPresent = allTextViewElements.stream().anyMatch(e -> e.getText().contains("The active connection is wifi."));
99+
Assert.assertTrue(textPresent, "Text is not present");
100+
}
101+
102+
@AfterMethod(alwaysRun = true)
103+
public void closeDriver(Method m) {
104+
JavascriptExecutor js = (JavascriptExecutor) driver;
105+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"passed\"}}");
106+
driver.quit();
107+
}
108+
109+
@AfterSuite(alwaysRun = true)
110+
public void closeLocal() throws Exception {
111+
local.stop();
112+
System.out.println("Binary stopped");
113+
}
114+
115+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.app.test;
2+
3+
import io.appium.java_client.MobileDriver;
4+
import io.appium.java_client.MobileElement;
5+
import io.appium.java_client.android.AndroidDriver;
6+
import io.restassured.authentication.PreemptiveBasicAuthScheme;
7+
import io.restassured.builder.RequestSpecBuilder;
8+
import io.restassured.builder.ResponseSpecBuilder;
9+
import io.restassured.path.json.JsonPath;
10+
import org.openqa.selenium.JavascriptExecutor;
11+
import org.openqa.selenium.NotFoundException;
12+
import org.openqa.selenium.remote.DesiredCapabilities;
13+
import org.openqa.selenium.support.ui.FluentWait;
14+
import org.openqa.selenium.support.ui.Wait;
15+
import org.testng.Assert;
16+
import org.testng.annotations.*;
17+
18+
import java.io.File;
19+
import java.lang.reflect.Method;
20+
import java.net.MalformedURLException;
21+
import java.net.URL;
22+
import java.time.Duration;
23+
import java.util.HashMap;
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
import static io.restassured.RestAssured.*;
28+
29+
public class AppiumParallelTest {
30+
31+
private static final ThreadLocal<MobileDriver<MobileElement>> driverThread = new ThreadLocal<>();
32+
33+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
34+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
35+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
36+
37+
@BeforeSuite(alwaysRun = true)
38+
public void setupApp() {
39+
PreemptiveBasicAuthScheme authenticationScheme = new PreemptiveBasicAuthScheme();
40+
authenticationScheme.setUserName(USERNAME);
41+
authenticationScheme.setPassword(ACCESS_KEY);
42+
requestSpecification = new RequestSpecBuilder()
43+
.setBaseUri("https://api-cloud.browserstack.com")
44+
.setBasePath("app-automate")
45+
.setAuth(authenticationScheme)
46+
.build();
47+
responseSpecification = new ResponseSpecBuilder()
48+
.expectStatusCode(200)
49+
.build();
50+
List<String> customIds = get("recent_apps").jsonPath().getList("custom_id");
51+
if (customIds == null || !customIds.contains("DemoApp")) {
52+
System.out.println("Uploading app...");
53+
given()
54+
.header("Content-Type", "multipart/form-data")
55+
.multiPart("file", new File("src/test/resources/app/appdata/WikipediaSample.apk"), "text/apk")
56+
.param("custom_id", "DemoApp")
57+
.post("upload");
58+
} else {
59+
System.out.println("Using previously uploaded app...");
60+
}
61+
}
62+
63+
@BeforeMethod(alwaysRun = true)
64+
@Parameters({"config", "environment"})
65+
public void setupDriver(String configFile, String environment, Method m) throws MalformedURLException {
66+
JsonPath jsonPath = JsonPath.from(new File("src/test/resources/app/config/" + configFile + ".json"));
67+
Map<String, String> basicCapabilities = jsonPath.getMap("capabilities");
68+
Map<String, String> deviceCapabilities = jsonPath.getMap("environments." + environment);
69+
Map<String, String> capabilitiesMap = new HashMap<>();
70+
capabilitiesMap.putAll(basicCapabilities);
71+
capabilitiesMap.putAll(deviceCapabilities);
72+
capabilitiesMap.put("name", m.getName() + " - " + deviceCapabilities.get("device"));
73+
capabilitiesMap.put("browserstack.user", USERNAME);
74+
capabilitiesMap.put("browserstack.key", ACCESS_KEY);
75+
driverThread.set(new AndroidDriver<>(new URL(URL), new DesiredCapabilities(capabilitiesMap)));
76+
}
77+
78+
@Test
79+
public void searchWikipedia() {
80+
Wait<MobileDriver<MobileElement>> wait = new FluentWait<>(driverThread.get())
81+
.withTimeout(Duration.ofSeconds(10))
82+
.pollingEvery(Duration.ofMillis(500))
83+
.ignoring(NotFoundException.class);
84+
MobileElement searchElement = wait.until(d -> d.findElementByAccessibilityId("Search Wikipedia"));
85+
searchElement.click();
86+
MobileElement insertTextElement = wait.until(d -> d.findElementById("org.wikipedia.alpha:id/search_src_text"));
87+
insertTextElement.sendKeys("BrowserStack");
88+
List<MobileElement> allProductName = wait.until(d -> d.findElementsByClassName("android.widget.TextView"));
89+
Assert.assertTrue(allProductName.size() > 0, "Products are not present");
90+
}
91+
92+
@AfterMethod(alwaysRun = true)
93+
public void tearDown(Method m) {
94+
JavascriptExecutor js = (JavascriptExecutor) driverThread.get();
95+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"passed\"}}");
96+
driverThread.get().quit();
97+
driverThread.remove();
98+
}
99+
100+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.app.test;
2+
3+
import io.appium.java_client.MobileDriver;
4+
import io.appium.java_client.MobileElement;
5+
import io.appium.java_client.android.AndroidDriver;
6+
import io.restassured.authentication.PreemptiveBasicAuthScheme;
7+
import io.restassured.builder.RequestSpecBuilder;
8+
import io.restassured.builder.ResponseSpecBuilder;
9+
import org.openqa.selenium.JavascriptExecutor;
10+
import org.openqa.selenium.NotFoundException;
11+
import org.openqa.selenium.remote.DesiredCapabilities;
12+
import org.openqa.selenium.support.ui.FluentWait;
13+
import org.openqa.selenium.support.ui.Wait;
14+
import org.testng.Assert;
15+
import org.testng.annotations.AfterMethod;
16+
import org.testng.annotations.BeforeMethod;
17+
import org.testng.annotations.BeforeSuite;
18+
import org.testng.annotations.Test;
19+
20+
import java.io.File;
21+
import java.lang.reflect.Method;
22+
import java.net.MalformedURLException;
23+
import java.net.URL;
24+
import java.time.Duration;
25+
import java.util.List;
26+
27+
import static io.restassured.RestAssured.*;
28+
29+
public class AppiumSingleTest {
30+
31+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
32+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
33+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
34+
private MobileDriver<MobileElement> driver;
35+
36+
@BeforeSuite(alwaysRun = true)
37+
public void setupApp() {
38+
PreemptiveBasicAuthScheme authenticationScheme = new PreemptiveBasicAuthScheme();
39+
authenticationScheme.setUserName(USERNAME);
40+
authenticationScheme.setPassword(ACCESS_KEY);
41+
requestSpecification = new RequestSpecBuilder()
42+
.setBaseUri("https://api-cloud.browserstack.com")
43+
.setBasePath("app-automate")
44+
.setAuth(authenticationScheme)
45+
.build();
46+
responseSpecification = new ResponseSpecBuilder()
47+
.expectStatusCode(200)
48+
.build();
49+
List<String> customIds = get("recent_apps").jsonPath().getList("custom_id");
50+
if (customIds == null || !customIds.contains("DemoApp")) {
51+
System.out.println("Uploading app...");
52+
given()
53+
.header("Content-Type", "multipart/form-data")
54+
.multiPart("file", new File("src/test/resources/app/appdata/WikipediaSample.apk"), "text/apk")
55+
.param("custom_id", "DemoApp")
56+
.post("upload");
57+
} else {
58+
System.out.println("Using previously uploaded app...");
59+
}
60+
}
61+
62+
@BeforeMethod(alwaysRun = true)
63+
public void setup(Method m) throws MalformedURLException {
64+
DesiredCapabilities caps = new DesiredCapabilities();
65+
caps.setCapability("project", "BrowserStack Java TestNG");
66+
caps.setCapability("build", "Demo");
67+
caps.setCapability("name", m.getName() + " - Google Pixel 3");
68+
69+
caps.setCapability("device", "Google Pixel 3");
70+
caps.setCapability("os_version", "10.0");
71+
caps.setCapability("real_mobile", "true");
72+
caps.setCapability("app", "DemoApp");
73+
74+
caps.setCapability("browserstack.user", USERNAME);
75+
caps.setCapability("browserstack.key", ACCESS_KEY);
76+
caps.setCapability("browserstack.debug", "true");
77+
78+
driver = new AndroidDriver<>(new URL(URL), caps);
79+
}
80+
81+
@Test
82+
public void searchWikipedia() {
83+
Wait<MobileDriver<MobileElement>> wait = new FluentWait<>(driver)
84+
.withTimeout(Duration.ofSeconds(10))
85+
.pollingEvery(Duration.ofMillis(500))
86+
.ignoring(NotFoundException.class);
87+
MobileElement searchElement = wait.until(d -> d.findElementByAccessibilityId("Search Wikipedia"));
88+
searchElement.click();
89+
MobileElement insertTextElement = wait.until(d -> d.findElementById("org.wikipedia.alpha:id/search_src_text"));
90+
insertTextElement.sendKeys("BrowserStack");
91+
List<MobileElement> allProductName = wait.until(d -> d.findElementsByClassName("android.widget.TextView"));
92+
Assert.assertTrue(allProductName.size() > 0, "Products are not present");
93+
}
94+
95+
@AfterMethod(alwaysRun = true)
96+
public void tearDown(Method m) {
97+
JavascriptExecutor js = (JavascriptExecutor) driver;
98+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"passed\"}}");
99+
driver.quit();
100+
}
101+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.app.test;
2+
3+
import io.restassured.authentication.PreemptiveBasicAuthScheme;
4+
import io.restassured.builder.RequestSpecBuilder;
5+
import io.restassured.builder.ResponseSpecBuilder;
6+
import io.restassured.path.json.JsonPath;
7+
import org.testng.annotations.BeforeSuite;
8+
import org.testng.annotations.BeforeTest;
9+
import org.testng.annotations.Test;
10+
11+
import java.io.File;
12+
13+
import static io.restassured.RestAssured.*;
14+
15+
public class EspressoTest {
16+
17+
String appUrl, testSuiteUrl;
18+
19+
@BeforeSuite
20+
public void setup() {
21+
PreemptiveBasicAuthScheme authenticationScheme = new PreemptiveBasicAuthScheme();
22+
authenticationScheme.setUserName(System.getenv("BROWSERSTACK_USERNAME"));
23+
authenticationScheme.setPassword(System.getenv("BROWSERSTACK_ACCESS_KEY"));
24+
requestSpecification = new RequestSpecBuilder()
25+
.setBaseUri("https://api-cloud.browserstack.com")
26+
.setBasePath("app-automate/espresso/v2")
27+
.setAuth(authenticationScheme)
28+
.build();
29+
responseSpecification = new ResponseSpecBuilder()
30+
.expectStatusCode(200)
31+
.build();
32+
}
33+
34+
@BeforeTest
35+
public void uploadAppAndTestSuite() {
36+
System.out.println("Uploading app ...");
37+
appUrl = given()
38+
.header("Content-Type", "multipart/form-data")
39+
.multiPart("file", new File("src/test/resources/app/appdata/Espresso-App.apk"), "text/apk")
40+
.param("custom_id", "EspressoApp")
41+
.post("app")
42+
.jsonPath()
43+
.get("app_url");
44+
System.out.println("Uploading test suite ...");
45+
testSuiteUrl = given()
46+
.header("Content-Type", "multipart/form-data")
47+
.multiPart("file", new File("src/test/resources/app/appdata/Espresso-AppTest.apk"), "text/apk")
48+
.param("custom_id", "EspressoAppTest")
49+
.post("test-suite")
50+
.jsonPath()
51+
.get("test_suite_url");
52+
}
53+
54+
@Test
55+
public void espressoTest() {
56+
System.out.println("Executing test suite ...");
57+
String body = JsonPath.given(new File("src/test/resources/app/config/espresso.json"))
58+
.prettyPrint()
59+
.replaceFirst("appUrl", appUrl)
60+
.replaceFirst("testSuiteUrl", testSuiteUrl);
61+
given()
62+
.header("Content-Type", "application/json")
63+
.body(body)
64+
.post("build");
65+
}
66+
67+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.app.test;
2+
3+
import io.restassured.authentication.PreemptiveBasicAuthScheme;
4+
import io.restassured.builder.RequestSpecBuilder;
5+
import io.restassured.builder.ResponseSpecBuilder;
6+
import io.restassured.path.json.JsonPath;
7+
import org.testng.annotations.BeforeSuite;
8+
import org.testng.annotations.BeforeTest;
9+
import org.testng.annotations.Test;
10+
11+
import java.io.File;
12+
13+
import static io.restassured.RestAssured.*;
14+
15+
public class XCUITest {
16+
17+
String appUrl, testSuiteUrl;
18+
19+
@BeforeSuite
20+
public void setup() {
21+
PreemptiveBasicAuthScheme authenticationScheme = new PreemptiveBasicAuthScheme();
22+
authenticationScheme.setUserName(System.getenv("BROWSERSTACK_USERNAME"));
23+
authenticationScheme.setPassword(System.getenv("BROWSERSTACK_ACCESS_KEY"));
24+
requestSpecification = new RequestSpecBuilder()
25+
.setBaseUri("https://api-cloud.browserstack.com")
26+
.setBasePath("app-automate/xcuitest/v2")
27+
.setAuth(authenticationScheme)
28+
.build();
29+
responseSpecification = new ResponseSpecBuilder()
30+
.expectStatusCode(200)
31+
.build();
32+
}
33+
34+
@BeforeTest
35+
public void uploadAppAndTestSuite() {
36+
System.out.println("Uploading app ...");
37+
appUrl = given()
38+
.header("Content-Type", "multipart/form-data")
39+
.multiPart("file", new File("src/test/resources/app/appdata/XCUITest-App.ipa"), "text/ipa")
40+
.param("custom_id", "EspressoApp")
41+
.post("app")
42+
.jsonPath()
43+
.get("app_url");
44+
System.out.println("Uploading test suite ...");
45+
testSuiteUrl = given()
46+
.header("Content-Type", "multipart/form-data")
47+
.multiPart("file", new File("src/test/resources/app/appdata/XCUITest-AppTest.zip"), "text/zip")
48+
.param("custom_id", "EspressoAppTest")
49+
.post("test-suite")
50+
.jsonPath()
51+
.get("test_suite_url");
52+
}
53+
54+
@Test
55+
public void xcuiTest() {
56+
System.out.println("Executing test suite...");
57+
String body = JsonPath.given(new File("src/test/resources/app/config/xcuitest.json"))
58+
.prettyPrint()
59+
.replaceFirst("appUrl", appUrl)
60+
.replaceFirst("testSuiteUrl", testSuiteUrl);
61+
given()
62+
.header("Content-Type", "application/json")
63+
.body(body)
64+
.post("build");
65+
}
66+
67+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.web.test;
2+
3+
import org.openqa.selenium.By;
4+
import org.openqa.selenium.JavascriptExecutor;
5+
import org.openqa.selenium.WebDriver;
6+
import org.openqa.selenium.remote.DesiredCapabilities;
7+
import org.openqa.selenium.remote.RemoteWebDriver;
8+
import org.openqa.selenium.support.ui.WebDriverWait;
9+
import org.testng.Assert;
10+
import org.testng.annotations.AfterMethod;
11+
import org.testng.annotations.BeforeMethod;
12+
import org.testng.annotations.Test;
13+
14+
import java.lang.reflect.Method;
15+
import java.net.MalformedURLException;
16+
import java.net.URL;
17+
18+
import static org.openqa.selenium.Keys.TAB;
19+
import static org.openqa.selenium.support.ui.ExpectedConditions.elementToBeClickable;
20+
import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;
21+
22+
public class FailTest {
23+
24+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
25+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
26+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
27+
private WebDriver driver;
28+
29+
@BeforeMethod(alwaysRun = true)
30+
public void setup(Method m) throws MalformedURLException {
31+
DesiredCapabilities caps = new DesiredCapabilities();
32+
caps.setCapability("project", "BrowserStack Java TestNG");
33+
caps.setCapability("build", "Demo");
34+
caps.setCapability("name", m.getName() + " - Chrome latest");
35+
36+
caps.setCapability("os", "Windows");
37+
caps.setCapability("os_version", "10");
38+
caps.setCapability("browser", "Chrome");
39+
caps.setCapability("browser_version", "latest");
40+
41+
caps.setCapability("browserstack.user", USERNAME);
42+
caps.setCapability("browserstack.key", ACCESS_KEY);
43+
caps.setCapability("browserstack.debug", "true");
44+
caps.setCapability("browserstack.networkLogs", "true");
45+
46+
driver = new RemoteWebDriver(new URL(URL), caps);
47+
}
48+
49+
@Test
50+
public void loginBStackDemo() {
51+
WebDriverWait wait = new WebDriverWait(driver, 10);
52+
driver.get("https://bstackdemo.com");
53+
wait.until(elementToBeClickable(By.id("signin"))).click();
54+
wait.until(elementToBeClickable(By.cssSelector("#username input"))).sendKeys("fav_user" + TAB);
55+
driver.findElement(By.cssSelector("#password input")).sendKeys("testingisfun99" + TAB);
56+
driver.findElement(By.id("login-btn")).click();
57+
String username = wait.until(presenceOfElementLocated(By.className("username"))).getText();
58+
Assert.assertEquals(username, "incorrect_user", "Incorrect username");
59+
}
60+
61+
@AfterMethod(alwaysRun = true)
62+
public void teardown(Method m) {
63+
JavascriptExecutor js = (JavascriptExecutor) driver;
64+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"failed\", \"reason\": \"" + m.getName() + " failed\"}}");
65+
driver.quit();
66+
}
67+
68+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.web.test;
2+
3+
import com.browserstack.local.Local;
4+
import io.restassured.path.json.JsonPath;
5+
import org.openqa.selenium.JavascriptExecutor;
6+
import org.openqa.selenium.WebDriver;
7+
import org.openqa.selenium.remote.DesiredCapabilities;
8+
import org.openqa.selenium.remote.RemoteWebDriver;
9+
import org.testng.Assert;
10+
import org.testng.annotations.*;
11+
12+
import java.io.File;
13+
import java.lang.reflect.Method;
14+
import java.net.MalformedURLException;
15+
import java.net.URL;
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
19+
public class LocalParallelTest {
20+
21+
private static final ThreadLocal<WebDriver> driverThread = new ThreadLocal<>();
22+
private Local local;
23+
24+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
25+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
26+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
27+
28+
@BeforeSuite(alwaysRun = true)
29+
public void before() throws Exception {
30+
System.out.println("Connecting local");
31+
local = new Local();
32+
Map<String, String> bsLocalArgs = new HashMap<>();
33+
bsLocalArgs.put("key", ACCESS_KEY);
34+
local.start(bsLocalArgs);
35+
System.out.println("Connected. Now testing...");
36+
}
37+
38+
@BeforeMethod(alwaysRun = true)
39+
@Parameters({"config", "environment"})
40+
public void setup(String configFile, String environment, Method m) throws MalformedURLException {
41+
JsonPath jsonPath = JsonPath.from(new File("src/test/resources/web/config/" + configFile + ".json"));
42+
Map<String, String> basicCapabilities = jsonPath.getMap("capabilities");
43+
Map<String, String> browserCapabilities = jsonPath.getMap("environments." + environment);
44+
Map<String, String> capabilitiesMap = new HashMap<>();
45+
capabilitiesMap.putAll(basicCapabilities);
46+
capabilitiesMap.putAll(browserCapabilities);
47+
capabilitiesMap.put("name", m.getName() + " - " + browserCapabilities.get("browser") + " " + browserCapabilities.get("browser_version"));
48+
capabilitiesMap.put("browserstack.local", "true");
49+
capabilitiesMap.put("browserstack.user", USERNAME);
50+
capabilitiesMap.put("browserstack.key", ACCESS_KEY);
51+
driverThread.set(new RemoteWebDriver(new URL(URL), new DesiredCapabilities(capabilitiesMap)));
52+
53+
}
54+
55+
@Test
56+
public void openLocalWebPage() {
57+
WebDriver driver = driverThread.get();
58+
driver.get("http://localhost:8000");
59+
Assert.assertEquals(driver.getTitle(), "Local Server", "Incorrect title");
60+
}
61+
62+
@AfterMethod(alwaysRun = true)
63+
public void teardown(Method m) {
64+
JavascriptExecutor js = (JavascriptExecutor) driverThread.get();
65+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"passed\"}}");
66+
driverThread.get().quit();
67+
driverThread.remove();
68+
}
69+
70+
@AfterSuite(alwaysRun = true)
71+
public void after() throws Exception {
72+
local.stop();
73+
System.out.println("Binary stopped");
74+
}
75+
76+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.web.test;
2+
3+
import com.browserstack.local.Local;
4+
import org.openqa.selenium.JavascriptExecutor;
5+
import org.openqa.selenium.WebDriver;
6+
import org.openqa.selenium.remote.DesiredCapabilities;
7+
import org.openqa.selenium.remote.RemoteWebDriver;
8+
import org.testng.Assert;
9+
import org.testng.annotations.*;
10+
11+
import java.lang.reflect.Method;
12+
import java.net.MalformedURLException;
13+
import java.net.URL;
14+
import java.util.HashMap;
15+
import java.util.Map;
16+
17+
public class LocalTest {
18+
19+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
20+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
21+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
22+
private WebDriver driver;
23+
private Local local;
24+
25+
@BeforeSuite(alwaysRun = true)
26+
public void setupLocal() throws Exception {
27+
System.out.println("Connecting local");
28+
local = new Local();
29+
Map<String, String> bsLocalArgs = new HashMap<>();
30+
bsLocalArgs.put("key", ACCESS_KEY);
31+
local.start(bsLocalArgs);
32+
System.out.println("Connected. Now testing...");
33+
}
34+
35+
@BeforeMethod(alwaysRun = true)
36+
public void setupDriver(Method m) throws MalformedURLException {
37+
DesiredCapabilities caps = new DesiredCapabilities();
38+
caps.setCapability("project", "BrowserStack Java TestNG");
39+
caps.setCapability("build", "Demo");
40+
caps.setCapability("name", m.getName() + " - Chrome latest");
41+
42+
caps.setCapability("os", "Windows");
43+
caps.setCapability("os_version", "10");
44+
caps.setCapability("browser", "Chrome");
45+
caps.setCapability("browser_version", "latest");
46+
47+
caps.setCapability("browserstack.user", USERNAME);
48+
caps.setCapability("browserstack.key", ACCESS_KEY);
49+
caps.setCapability("browserstack.debug", "true");
50+
caps.setCapability("browserstack.networkLogs", "true");
51+
caps.setCapability("browserstack.local", "true");
52+
53+
driver = new RemoteWebDriver(new URL(URL), caps);
54+
}
55+
56+
@Test
57+
public void testLocalServer() {
58+
driver.get("http://localhost:8000");
59+
Assert.assertEquals(driver.getTitle(), "Local Server", "Incorrect title");
60+
}
61+
62+
@AfterMethod(alwaysRun = true)
63+
public void closeDriver(Method m) {
64+
JavascriptExecutor js = (JavascriptExecutor) driver;
65+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"passed\"}}");
66+
driver.quit();
67+
}
68+
69+
@AfterSuite(alwaysRun = true)
70+
public void closeLocal() throws Exception {
71+
local.stop();
72+
System.out.println("Binary stopped");
73+
}
74+
75+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.web.test;
2+
3+
import io.restassured.path.json.JsonPath;
4+
import org.openqa.selenium.By;
5+
import org.openqa.selenium.JavascriptExecutor;
6+
import org.openqa.selenium.WebDriver;
7+
import org.openqa.selenium.remote.DesiredCapabilities;
8+
import org.openqa.selenium.remote.RemoteWebDriver;
9+
import org.openqa.selenium.support.ui.WebDriverWait;
10+
import org.testng.Assert;
11+
import org.testng.annotations.AfterMethod;
12+
import org.testng.annotations.BeforeMethod;
13+
import org.testng.annotations.Parameters;
14+
import org.testng.annotations.Test;
15+
16+
import java.io.File;
17+
import java.lang.reflect.Method;
18+
import java.net.MalformedURLException;
19+
import java.net.URL;
20+
import java.util.HashMap;
21+
import java.util.Map;
22+
23+
import static org.openqa.selenium.Keys.TAB;
24+
import static org.openqa.selenium.support.ui.ExpectedConditions.elementToBeClickable;
25+
import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;
26+
27+
public class ParallelTest {
28+
29+
private static final ThreadLocal<WebDriver> driverThread = new ThreadLocal<>();
30+
31+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
32+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
33+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
34+
35+
@BeforeMethod(alwaysRun = true)
36+
@Parameters({"config", "environment"})
37+
public void setup(String configFile, String environment, Method m) throws MalformedURLException {
38+
JsonPath jsonPath = JsonPath.from(new File("src/test/resources/web/config/" + configFile + ".json"));
39+
Map<String, String> basicCapabilities = jsonPath.getMap("capabilities");
40+
Map<String, String> browserCapabilities = jsonPath.getMap("environments." + environment);
41+
Map<String, String> capabilitiesMap = new HashMap<>();
42+
capabilitiesMap.putAll(basicCapabilities);
43+
capabilitiesMap.putAll(browserCapabilities);
44+
if (browserCapabilities.get("device") == null) {
45+
capabilitiesMap.put("name", m.getName() + " - " + browserCapabilities.get("browser") + " " + browserCapabilities.get("browser_version"));
46+
} else {
47+
capabilitiesMap.put("name", m.getName() + " - " + browserCapabilities.get("device"));
48+
}
49+
capabilitiesMap.put("browserstack.user", USERNAME);
50+
capabilitiesMap.put("browserstack.key", ACCESS_KEY);
51+
driverThread.set(new RemoteWebDriver(new URL(URL), new DesiredCapabilities(capabilitiesMap)));
52+
}
53+
54+
@Test
55+
public void loginBStackDemo() {
56+
WebDriver driver = driverThread.get();
57+
WebDriverWait wait = new WebDriverWait(driver, 10);
58+
driver.get("https://bstackdemo.com");
59+
wait.until(elementToBeClickable(By.id("signin"))).click();
60+
wait.until(elementToBeClickable(By.cssSelector("#username input"))).sendKeys("fav_user" + TAB);
61+
driver.findElement(By.cssSelector("#password input")).sendKeys("testingisfun99" + TAB);
62+
driver.findElement(By.id("login-btn")).click();
63+
String username = wait.until(presenceOfElementLocated(By.className("username"))).getText();
64+
Assert.assertEquals(username, "fav_user", "Incorrect username");
65+
}
66+
67+
@AfterMethod(alwaysRun = true)
68+
public void teardown(Method m) {
69+
JavascriptExecutor js = (JavascriptExecutor) driverThread.get();
70+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"passed\"}}");
71+
driverThread.get().quit();
72+
driverThread.remove();
73+
}
74+
75+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.web.test;
2+
3+
import org.openqa.selenium.By;
4+
import org.openqa.selenium.JavascriptExecutor;
5+
import org.openqa.selenium.WebDriver;
6+
import org.openqa.selenium.remote.DesiredCapabilities;
7+
import org.openqa.selenium.remote.RemoteWebDriver;
8+
import org.openqa.selenium.support.ui.WebDriverWait;
9+
import org.testng.Assert;
10+
import org.testng.annotations.AfterMethod;
11+
import org.testng.annotations.BeforeMethod;
12+
import org.testng.annotations.Test;
13+
14+
import java.lang.reflect.Method;
15+
import java.net.MalformedURLException;
16+
import java.net.URL;
17+
18+
import static org.openqa.selenium.Keys.TAB;
19+
import static org.openqa.selenium.support.ui.ExpectedConditions.elementToBeClickable;
20+
import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;
21+
22+
public class SingleTest {
23+
24+
private static final String USERNAME = System.getenv("BROWSERSTACK_USERNAME");
25+
private static final String ACCESS_KEY = System.getenv("BROWSERSTACK_ACCESS_KEY");
26+
private static final String URL = "http://hub-cloud.browserstack.com/wd/hub";
27+
private WebDriver driver;
28+
29+
@BeforeMethod(alwaysRun = true)
30+
public void setup(Method m) throws MalformedURLException {
31+
DesiredCapabilities caps = new DesiredCapabilities();
32+
caps.setCapability("project", "BrowserStack Java TestNG");
33+
caps.setCapability("build", "Demo");
34+
caps.setCapability("name", m.getName() + " - Chrome latest");
35+
36+
// caps.setCapability("os", "Windows");
37+
// caps.setCapability("os_version", "10");
38+
// caps.setCapability("browser", "Chrome");
39+
// caps.setCapability("browser_version", "latest");
40+
41+
caps.setCapability("browserstack.user", USERNAME);
42+
caps.setCapability("browserstack.key", ACCESS_KEY);
43+
caps.setCapability("browserstack.debug", "true");
44+
caps.setCapability("browserstack.networkLogs", "true");
45+
46+
driver = new RemoteWebDriver(new URL(URL), caps);
47+
}
48+
49+
@Test
50+
public void loginBStackDemo() {
51+
WebDriverWait wait = new WebDriverWait(driver, 10);
52+
driver.get("https://bstackdemo.com");
53+
wait.until(elementToBeClickable(By.id("signin"))).click();
54+
wait.until(elementToBeClickable(By.cssSelector("#username input"))).sendKeys("fav_user" + TAB);
55+
driver.findElement(By.cssSelector("#password input")).sendKeys("testingisfun99" + TAB);
56+
driver.findElement(By.id("login-btn")).click();
57+
String username = wait.until(presenceOfElementLocated(By.className("username"))).getText();
58+
Assert.assertEquals(username, "fav_user", "Incorrect username");
59+
}
60+
61+
@AfterMethod(alwaysRun = true)
62+
public void teardown(Method m) {
63+
JavascriptExecutor js = (JavascriptExecutor) driver;
64+
js.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"passed\"}}");
65+
driver.quit();
66+
}
67+
68+
}
1.46 MB
Binary file not shown.
Binary file not shown.
493 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"capabilities": {
3+
"project": "BrowserStack Java TestNG",
4+
"build": "Demo",
5+
"browserstack.debug": "true",
6+
"app": "DemoApp"
7+
},
8+
"environments": {
9+
"pixel3": {
10+
"device": "Google Pixel 3",
11+
"os_version": "9.0"
12+
},
13+
"oneplus6t": {
14+
"device": "OnePlus 6T",
15+
"os_version": "9.0"
16+
},
17+
"pixel5": {
18+
"device": "Google Pixel 5",
19+
"os_version": "11.0"
20+
},
21+
"galaxys10e": {
22+
"device": "Samsung Galaxy S10e",
23+
"os_version": "9.0"
24+
},
25+
"redminote9": {
26+
"device": "Xiaomi Redmi Note 9",
27+
"os_version": "10.0"
28+
}
29+
}
30+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"app": "appUrl",
3+
"testSuite": "testSuiteUrl",
4+
"devices": [
5+
"Samsung Galaxy S20-10.0",
6+
"Google Pixel 3-9.0"
7+
],
8+
"project": "Espresso_Test"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"app": "appUrl",
3+
"testSuite": "testSuiteUrl",
4+
"devices": [
5+
"iPhone 8-11",
6+
"iPhone 8 Plus-11"
7+
],
8+
"deviceLogs": true
9+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
3+
<suite name="Parallel">
4+
<test name="ParallelTestPixel3">
5+
<parameter name="config" value="devices"/>
6+
<parameter name="environment" value="pixel3"/>
7+
<classes>
8+
<class name="com.app.test.AppiumParallelTest"/>
9+
</classes>
10+
</test>
11+
<test name="ParallelTestOnePlus6T">
12+
<parameter name="config" value="devices"/>
13+
<parameter name="environment" value="oneplus6t"/>
14+
<classes>
15+
<class name="com.app.test.AppiumParallelTest"/>
16+
</classes>
17+
</test>
18+
<test name="ParallelTestPixel5">
19+
<parameter name="config" value="devices"/>
20+
<parameter name="environment" value="pixel5"/>
21+
<classes>
22+
<class name="com.app.test.AppiumParallelTest"/>
23+
</classes>
24+
</test>
25+
<test name="ParallelTestGalaxy10e">
26+
<parameter name="config" value="devices"/>
27+
<parameter name="environment" value="galaxys10e"/>
28+
<classes>
29+
<class name="com.app.test.AppiumParallelTest"/>
30+
</classes>
31+
</test>
32+
<test name="ParallelTestRedmiNote9">
33+
<parameter name="config" value="devices"/>
34+
<parameter name="environment" value="redminote9"/>
35+
<classes>
36+
<class name="com.app.test.AppiumParallelTest"/>
37+
</classes>
38+
</test>
39+
</suite>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"capabilities": {
3+
"project": "BrowserStack Java TestNG",
4+
"build": "Demo",
5+
"browserstack.debug": "true",
6+
"browserstack.networkLogs": "true"
7+
},
8+
"environments": {
9+
"chrome": {
10+
"os": "OS X",
11+
"os_version": "Big Sur",
12+
"browser": "Chrome",
13+
"browser_version": "latest"
14+
},
15+
"firefox": {
16+
"os": "Windows",
17+
"os_version": "10",
18+
"browser": "Firefox",
19+
"browser_version": "latest"
20+
},
21+
"edge": {
22+
"os": "Windows",
23+
"os_version": "10",
24+
"browser": "Edge",
25+
"browser_version": "latest"
26+
},
27+
"safari": {
28+
"os": "OS X",
29+
"os_version": "Big Sur",
30+
"browser": "Safari",
31+
"browser_version": "latest"
32+
},
33+
"opera": {
34+
"os": "Windows",
35+
"os_version": "8.1",
36+
"browser": "Opera",
37+
"browser_version": "12.16"
38+
},
39+
"custom": {
40+
"browserstack.geoLocation": "FR",
41+
"browserstack.customNetwork": "1000,1000,100,1"
42+
}
43+
}
44+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"capabilities": {
3+
"project": "BrowserStack Java TestNG",
4+
"build": "Demo",
5+
"realMobile": "true",
6+
"browserstack.debug": "true",
7+
"browserstack.networkLogs": "true"
8+
},
9+
"environments": {
10+
"pixel5": {
11+
"device": "Google Pixel 5",
12+
"os_version": "11.0"
13+
},
14+
"galaxys10": {
15+
"device": "Samsung Galaxy S10",
16+
"os_version": "9.0"
17+
},
18+
"iphone11": {
19+
"device": "iPhone 11",
20+
"os_version": "13.0"
21+
},
22+
"iphoneXS": {
23+
"device": "iPhone XS",
24+
"os_version": "12.0"
25+
},
26+
"ipad11": {
27+
"device": "iPad Pro 11 2020",
28+
"os_version": "13.0"
29+
}
30+
}
31+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
3+
<suite name="BrowserStack Suite">
4+
<test name="BrowserStack Chrome Test">
5+
<parameter name="config" value="browsers"/>
6+
<parameter name="environment" value="chrome"/>
7+
<classes>
8+
<class name="com.web.test.LocalParallelTest"/>
9+
</classes>
10+
</test>
11+
<test name="BrowserStack Firefox Test">
12+
<parameter name="config" value="browsers"/>
13+
<parameter name="environment" value="firefox"/>
14+
<classes>
15+
<class name="com.web.test.LocalParallelTest"/>
16+
</classes>
17+
</test>
18+
<test name="BrowserStack Edge Test">
19+
<parameter name="config" value="browsers"/>
20+
<parameter name="environment" value="edge"/>
21+
<classes>
22+
<class name="com.web.test.LocalParallelTest"/>
23+
</classes>
24+
</test>
25+
<test name="BrowserStack Safari Test">
26+
<parameter name="config" value="browsers"/>
27+
<parameter name="environment" value="safari"/>
28+
<classes>
29+
<class name="com.web.test.LocalParallelTest"/>
30+
</classes>
31+
</test>
32+
<test name="BrowserStack Opera Test">
33+
<parameter name="config" value="browsers"/>
34+
<parameter name="environment" value="opera"/>
35+
<classes>
36+
<class name="com.web.test.LocalParallelTest"/>
37+
</classes>
38+
</test>
39+
</suite>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
3+
<suite name="Parallel">
4+
<test name="Parallel Test Pixel 5">
5+
<parameter name="config" value="devices"/>
6+
<parameter name="environment" value="pixel5"/>
7+
<classes>
8+
<class name="com.web.test.ParallelTest"/>
9+
</classes>
10+
</test>
11+
<test name="Parallel Test Galaxy S10">
12+
<parameter name="config" value="devices"/>
13+
<parameter name="environment" value="galaxys10"/>
14+
<classes>
15+
<class name="com.web.test.ParallelTest"/>
16+
</classes>
17+
</test>
18+
<test name="Parallel Test iPhone 11">
19+
<parameter name="config" value="devices"/>
20+
<parameter name="environment" value="iphone11"/>
21+
<classes>
22+
<class name="com.web.test.ParallelTest"/>
23+
</classes>
24+
</test>
25+
<test name="Parallel Test iPhone XS">
26+
<parameter name="config" value="devices"/>
27+
<parameter name="environment" value="iphoneXS"/>
28+
<classes>
29+
<class name="com.web.test.ParallelTest"/>
30+
</classes>
31+
</test>
32+
<test name="Parallel Test iPad 11">
33+
<parameter name="config" value="devices"/>
34+
<parameter name="environment" value="ipad11"/>
35+
<classes>
36+
<class name="com.web.test.ParallelTest"/>
37+
</classes>
38+
</test>
39+
</suite>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
3+
<suite name="BrowserStack Suite">
4+
<test name="BrowserStack Chrome Test">
5+
<parameter name="config" value="browsers"/>
6+
<parameter name="environment" value="chrome"/>
7+
<classes>
8+
<class name="com.web.test.ParallelTest"/>
9+
</classes>
10+
</test>
11+
<test name="BrowserStack Firefox Test">
12+
<parameter name="config" value="browsers"/>
13+
<parameter name="environment" value="firefox"/>
14+
<classes>
15+
<class name="com.web.test.ParallelTest"/>
16+
</classes>
17+
</test>
18+
<test name="BrowserStack Edge Test">
19+
<parameter name="config" value="browsers"/>
20+
<parameter name="environment" value="edge"/>
21+
<classes>
22+
<class name="com.web.test.ParallelTest"/>
23+
</classes>
24+
</test>
25+
<test name="BrowserStack Safari Test">
26+
<parameter name="config" value="browsers"/>
27+
<parameter name="environment" value="safari"/>
28+
<classes>
29+
<class name="com.web.test.ParallelTest"/>
30+
</classes>
31+
</test>
32+
<test name="BrowserStack Opera Test">
33+
<parameter name="config" value="browsers"/>
34+
<parameter name="environment" value="opera"/>
35+
<classes>
36+
<class name="com.web.test.ParallelTest"/>
37+
</classes>
38+
</test>
39+
</suite>

0 commit comments

Comments
 (0)
Please sign in to comment.