├── .gitignore ├── LICENSE ├── README.md ├── graphics ├── Aleksandra_Shineleva.png ├── EyalAvatar.png └── workshop_fork.mp4 ├── pom.xml └── src └── test ├── java └── com │ └── demo │ ├── Config.java │ ├── DemoTest.java │ ├── answers │ ├── ex1_CreateAndroidDriver.java │ ├── ex2_DevelopAndroidTest.java │ ├── ex3_CreateIOSDriver.java │ └── ex4_DevelopIOSTest.java │ └── exercises │ ├── ex1_CreateAndroidDriver.java │ ├── ex2_DevelopAndroidTest.java │ ├── ex3_CreateIOSDriver.java │ └── ex4_DevelopIOSTest.java └── resources └── config ├── myDemoParallelTests.xml └── myDemoTests.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | *.setting 4 | *.DS_store 5 | *.classpath 6 | .settings/ 7 | *.project 8 | *.png 9 | test-output/ 10 | build/ 11 | .DS_Store 12 | test-order-details/ 13 | test-results/ 14 | img/ 15 | perfectoReports/ 16 | .git/ 17 | *.log 18 | /logs/ 19 | /dashboard/ 20 | *.pdf 21 | /bin 22 | Drivers/ 23 | target/surefire-reports/index.html 24 | apps/ 25 | *.iml 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 eyaly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mobile testing w/ Appium + Java 2 | 3 | Mobile automated testing using Appium and Java 4 | 5 | > Before we start, open this in a new tab and let the container load. 6 | 7 | [![Try in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/eyaly/mobile-appium-java-workshop) 8 | 9 | ## 🧠You will learn to 10 | 11 | * What is Appium 12 | * Create an automated Android test 13 | * Create an automated iOS test 14 | * Find element locators using Appium Inspector 15 | * Run tests in Sauce Labs real devices 16 | * Run tests in parallel 17 | 18 | ## Testing for Good 19 | 20 | ### 🌎Testing for Good enables great test automation engineering while shaping a more equitable society.👩‍💻 21 | 22 | Today, we're asking for donations for [Environmental Working Group](https://buy.stripe.com/9AQdU42lj9i7bHGcMN) 23 | 24 | ### [About Environmental Working Group](https://www.ewg.org/) 25 | 26 | We're advocates who won't quit. We're scientists that find solutions. We're people trying to make the safest choices for our health. At the Environmental Working Group, we believe that you should have easy access to the information you need to make smart, healthy choices. It’s this belief that inspired our president and co-founder, Ken Cook, to create EWG. 27 | 28 | Since 1993, we've worked tirelessly to protect public health. Whether it's spotlighting harmful industry standards, speaking out against outdated government legislation or empowering consumers with breakthrough education and research, we're in this fight. 29 | 30 | And we're not going anywhere. 31 | 32 | 👉 While the event is free, Sauce Labs encourages all attendees to 33 | 34 | 👉 **[donate](https://buy.stripe.com/9AQdU42lj9i7bHGcMN)** 35 | 36 | Anything helps! 37 | 38 | 100% of donations go to support the cause. 39 | 40 | ## Key 41 | 42 | 💡 this is a tip 43 | 44 | 🏋️‍♀️ this is an exercise for you to do 45 | 46 | ❓ this is a question for us to think and talk about. Try not to scroll beyond this question before we discuss 47 | 48 | 49 | ## Your Instructor: Eyal Yovel 50 | 51 | me 52 | 53 | 54 | - 🏢 I’m a Sr Solutions Architect at Sauce Labs 55 | - 😄 Pronouns: he/him 56 | - 📫   Links: 57 |
[![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/eyal-yovel-9786933/) 58 | [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/eyalyovel) 59 | [![Github](https://img.shields.io/badge/Github-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/eyaly/) 60 | 61 | ## Your TA: 62 | 63 | --- 64 | ## Setup 65 | 66 | --- 67 | ### Sauce Labs setup 68 | 1. Free [Sauce account](https://saucelabs.com/sign-up) 69 | 2. Make sure you know how to find your Sauce Labs Username and Access Key by going to the [Sauce Labs user settings page](https://app.saucelabs.com/user-settings) 70 | 71 | --- 72 | ### Appium setup 73 | 1. We will run our automated tests on Sauce Labs devices; therefore, there is no need to install Appium Server. 74 | 2. Please install [appium inspector](https://github.com/appium/appium-inspector#installation). Appium Inspector is basically just an Appium client (like WebdriverIO, Appium's Java client, etc...) with a user interface. 75 | 76 | --- 77 | ### Demo App(s) 78 | 1. The demo app that has been used for all these tests can be found [here](https://github.com/saucelabs/sample-app-mobile/releases). 79 | 2. Be aware of the fact that and iOS simulator uses a different build then a iOS real device. So please check the file you 80 | download. 81 | --- 82 | ### Gitpod setup 83 | 84 | ℹ Gitpod lets you run an entire Dev environment from a browser! You can use this approach if you don't have time or you don't know how to setup a local Java environment. 85 | 86 | 1. Sign up for a free [GitHub account](https://github.com/) 87 | 2. [Fork this repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo) 88 | * Make sure you are logged into GitHub 89 | * Click the Fork in the upper right of the GitHub. 90 | * Give the repo a ⭐ while you're here 🤩 91 | 3. Click here 92 | 93 | [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/nadvolod/js-code/tree/master/web-testing-2022) 94 | 95 | OR 96 | In the browser address bar, add your GitHub url (`https://github.com/USERNAME/this-repo-name`) with `https://gitpod.io/#` 97 | * The resulting url should look as follows: 98 | 99 | > https://gitpod.io/#https://github.com/USERNAME/mobile-appium-java-workshop 100 | 101 | 4. Once the Gitpod.io URL is loaded, you will need to sign in with the GitHub account you created earlier 102 | 5. Once the development environment is loaded, you should see 'Ready to test!' in the Terminal window in the lower portion of the window, run the following commands in that Terminal to set your `SAUCE_USERNAME`, `SAUCE_ACCESS_KEY`: 103 | 104 | ```bash 105 | eval $(gp env -e SAUCE_USERNAME=) 106 | eval $(gp env -e SAUCE_ACCESS_KEY=) 107 | ``` 108 | 109 | > Replace , with your credentials 110 | 111 | Once you have run those 2 commands, you can run the following commands to test your environment variables: 112 | 113 | ```bash 114 | echo $SAUCE_USERNAME 115 | echo $SAUCE_ACCESS_KEY 116 | ``` 117 | 118 | Run sanity tests 119 | 120 | ```bash 121 | mvn clean test -DtestngXmlFile=myDemoTests.xml 122 | ``` 123 | 124 |
125 |
126 | 127 | Click here to see an example console output. 128 | 129 | 130 | [INFO] ------------------------------------------------------- 131 | [INFO] T E S T S 132 | [INFO] ------------------------------------------------------- 133 | [INFO] Running TestSuite 134 | *** BeforeMethod hook. Running method demoTest *** 135 | region is us 136 | *** Start demoTest test *** 137 | *** AfterMethod hook *** 138 | [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.488 s - in TestSuite 139 | [INFO] 140 | [INFO] Results: 141 | [INFO] 142 | [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 143 | [INFO] 144 | [INFO] ------------------------------------------------------------------------ 145 | [INFO] BUILD SUCCESS 146 | [INFO] ------------------------------------------------------------------------ 147 | [INFO] Total time: 3.579 s 148 | [INFO] Finished at: 2022-07-04T12:05:35+01:00 149 | [INFO] ------------------------------------------------------------------------ 150 | 151 |
152 | 153 |
154 | 155 | #### In the next video I demo how to fork the repo and connect to Gitpod: 156 | 157 | https://user-images.githubusercontent.com/6969588/177877688-f735e152-991d-4c7e-a326-0a9a2969fea9.mp4 158 | 159 | 160 | 161 | 162 | ***✅👏Environment setup is complete if tests passed*** 163 | 164 | --- 165 | 166 | ### Local environment setup 167 | 168 | 1. Sign up for a free [GitHub account](https://github.com/) 169 | 2. [Fork this repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo) 170 | * Make sure you are logged into GitHub 171 | * Click the Fork in the upper right of the GitHub. 172 | * Give the repo a ⭐ while you're here 🤩 173 | 3. Clone **your fork** of the repository to your machine. Must have [Git installed](https://git-scm.com/downloads) 174 | 175 | ```bash 176 | git clone URL_OF_YOUR_FORK 177 | ``` 178 | 179 | Setup environment variables on your system 180 | * [Mac/Linux](https://docs.saucelabs.com/basics/environment-variables/#setting-up-environment-variables-on-macos-and-linux-systems) 181 | * [Windows](https://docs.saucelabs.com/basics/environment-variables/#setting-up-environment-variables-on-windows-systems) 182 | 183 | Run sanity tests 184 | 185 | ```java 186 | mvn clean test -DtestngXmlFile=myDemoTests.xml 187 | ``` 188 | 189 |
190 |
191 | 192 | Click here to see an example console output. 193 | 194 | 195 | [INFO] ------------------------------------------------------- 196 | [INFO] T E S T S 197 | [INFO] ------------------------------------------------------- 198 | [INFO] Running TestSuite 199 | *** BeforeMethod hook. Running method demoTest *** 200 | region is us 201 | *** Start demoTest test *** 202 | *** AfterMethod hook *** 203 | [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.488 s - in TestSuite 204 | [INFO] 205 | [INFO] Results: 206 | [INFO] 207 | [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 208 | [INFO] 209 | [INFO] ------------------------------------------------------------------------ 210 | [INFO] BUILD SUCCESS 211 | [INFO] ------------------------------------------------------------------------ 212 | [INFO] Total time: 3.579 s 213 | [INFO] Finished at: 2022-07-04T12:05:35+01:00 214 | [INFO] ------------------------------------------------------------------------ 215 | 216 |
217 | 218 |
219 | 220 | ***✅👏Environment setup is complete if tests passed*** 221 | 222 | ## Extra resources 223 | 224 | - [Appium options for sauce](https://docs.saucelabs.com/dev/test-configuration-options/#mobile-app-appium-capabilities-required) 225 | - [All appium capabilities](https://appium.io/docs/en/writing-running-appium/caps/) 226 | - [More Appium resources](https://github.com/saucelabs-training/demo-java/blob/main/TRAINING.md) 227 | 228 | ## Conclusions 229 | Please leave [quick and anonymous feedback on this workshop](https://docs.google.com/forms/d/e/1FAIpQLSfhKpfdRU9FuqYMfFyqD3GhjdYADzZikjes7boVErWlru4XBA/viewform) -------------------------------------------------------------------------------- /graphics/Aleksandra_Shineleva.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eyaly/mobile-appium-java-workshop/0c2b3299b956685ca00dd97811309b2db21976fe/graphics/Aleksandra_Shineleva.png -------------------------------------------------------------------------------- /graphics/EyalAvatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eyaly/mobile-appium-java-workshop/0c2b3299b956685ca00dd97811309b2db21976fe/graphics/EyalAvatar.png -------------------------------------------------------------------------------- /graphics/workshop_fork.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eyaly/mobile-appium-java-workshop/0c2b3299b956685ca00dd97811309b2db21976fe/graphics/workshop_fork.mp4 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | mobile-appium-java-workshop 9 | 1.0-SNAPSHOT 10 | 11 | 12 | src/test/resources/config 13 | myDemoTests.xml 14 | 7.4.0 15 | 8.2.0 16 | 17 | 18 | 19 | 20 | 21 | org.testng 22 | testng 23 | ${testng.version} 24 | 25 | 26 | 27 | io.appium 28 | java-client 29 | ${appium.version} 30 | test 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-surefire-plugin 40 | 3.0.0-M4 41 | 42 | 43 | ${testngXmlDir}/${testngXmlFile} 44 | 45 | 46 | 47 | 48 | maven-compiler-plugin 49 | 3.0 50 | 51 | 1.8 52 | 1.8 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/test/java/com/demo/Config.java: -------------------------------------------------------------------------------- 1 | package com.demo; 2 | 3 | public class Config { 4 | public static final String region = System.getProperty("region", "us"); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/demo/DemoTest.java: -------------------------------------------------------------------------------- 1 | package com.demo; 2 | 3 | import org.testng.ITestResult; 4 | import org.testng.Reporter; 5 | import org.testng.annotations.AfterMethod; 6 | import org.testng.annotations.BeforeMethod; 7 | import org.testng.annotations.Test; 8 | 9 | import java.lang.reflect.Method; 10 | import java.net.MalformedURLException; 11 | import java.util.Map; 12 | 13 | import static com.demo.Config.region; 14 | 15 | public class DemoTest { 16 | 17 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 18 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 19 | 20 | 21 | @BeforeMethod 22 | public void setup(Method method) throws MalformedURLException { 23 | 24 | String methodName = method.getName(); 25 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 26 | 27 | switch (region) { 28 | case "us": 29 | System.out.println("region is us"); 30 | break; 31 | case "eu": 32 | default: 33 | System.out.println("region is eu"); 34 | break; 35 | } 36 | 37 | } 38 | 39 | @Test 40 | public void demoTest() { 41 | System.out.println("*** Start demoTest test ***"); 42 | } 43 | 44 | @AfterMethod 45 | public void teardown(ITestResult result) { 46 | System.out.println("*** AfterMethod hook ***"); 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/demo/answers/ex1_CreateAndroidDriver.java: -------------------------------------------------------------------------------- 1 | package com.demo.answers; 2 | 3 | import io.appium.java_client.AppiumDriver; 4 | import io.appium.java_client.android.AndroidDriver; 5 | import org.openqa.selenium.MutableCapabilities; 6 | import org.testng.ITestResult; 7 | import org.testng.annotations.AfterMethod; 8 | import org.testng.annotations.BeforeMethod; 9 | import org.testng.annotations.Test; 10 | 11 | import java.lang.reflect.Method; 12 | import java.net.MalformedURLException; 13 | import java.net.URL; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | import static com.demo.Config.region; 18 | 19 | public class ex1_CreateAndroidDriver { 20 | 21 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 22 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 23 | 24 | private AndroidDriver driver; 25 | 26 | @BeforeMethod 27 | public void setup(Method method) throws MalformedURLException { 28 | 29 | String methodName = method.getName(); 30 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 31 | URL url; 32 | 33 | switch (region) { 34 | case "us": 35 | System.out.println("region is us"); 36 | url = new URL(SAUCE_US_URL); 37 | break; 38 | case "eu": 39 | default: 40 | System.out.println("region is eu"); 41 | url = new URL(SAUCE_EU_URL); 42 | break; 43 | } 44 | 45 | MutableCapabilities capabilities = new MutableCapabilities(); 46 | MutableCapabilities sauceOptions = new MutableCapabilities(); 47 | 48 | //find a device in the cloud 49 | capabilities.setCapability("platformName", "android"); 50 | capabilities.setCapability("automationName", "UiAutomator2"); 51 | capabilities.setCapability("appium:deviceName", "Samsung.*"); 52 | capabilities.setCapability("appium:platformVersion", "12"); 53 | 54 | capabilities.setCapability("appium:app", 55 | "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/Android.SauceLabs.Mobile.Sample.app.2.7.1.apk"); 56 | capabilities.setCapability("appium:appWaitActivity","com.swaglabsmobileapp.MainActivity"); 57 | 58 | // Sauce capabilities 59 | sauceOptions.setCapability("name", methodName); 60 | sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 61 | sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 62 | capabilities.setCapability("sauce:options", sauceOptions); 63 | 64 | driver = new AndroidDriver(url, capabilities); 65 | 66 | } 67 | 68 | @Test 69 | public void demoTest() { 70 | System.out.println("*** Start demoTest test ***"); 71 | } 72 | 73 | @AfterMethod 74 | public void teardown(ITestResult result) { 75 | System.out.println("*** AfterMethod hook ***"); 76 | driver.quit(); 77 | } 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/com/demo/answers/ex2_DevelopAndroidTest.java: -------------------------------------------------------------------------------- 1 | package com.demo.answers; 2 | 3 | import io.appium.java_client.AppiumBy; 4 | import io.appium.java_client.android.AndroidDriver; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.JavascriptExecutor; 7 | import org.openqa.selenium.MutableCapabilities; 8 | import org.openqa.selenium.TimeoutException; 9 | import org.openqa.selenium.support.ui.ExpectedConditions; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | import org.testng.Assert; 12 | import org.testng.ITestResult; 13 | import org.testng.annotations.AfterMethod; 14 | import org.testng.annotations.BeforeMethod; 15 | import org.testng.annotations.Test; 16 | 17 | import java.lang.reflect.Method; 18 | import java.net.MalformedURLException; 19 | import java.net.URL; 20 | import java.time.Duration; 21 | 22 | import static com.demo.Config.region; 23 | 24 | public class ex2_DevelopAndroidTest { 25 | 26 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 27 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 28 | 29 | private AndroidDriver driver; 30 | 31 | @BeforeMethod 32 | public void setup(Method method) throws MalformedURLException { 33 | 34 | String methodName = method.getName(); 35 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 36 | URL url; 37 | 38 | switch (region) { 39 | case "us": 40 | System.out.println("region is us"); 41 | url = new URL(SAUCE_US_URL); 42 | break; 43 | case "eu": 44 | default: 45 | System.out.println("region is eu"); 46 | url = new URL(SAUCE_EU_URL); 47 | break; 48 | } 49 | 50 | MutableCapabilities capabilities = new MutableCapabilities(); 51 | MutableCapabilities sauceOptions = new MutableCapabilities(); 52 | 53 | //find a device in the cloud 54 | capabilities.setCapability("platformName", "android"); 55 | capabilities.setCapability("automationName", "UiAutomator2"); 56 | capabilities.setCapability("appium:deviceName", "Samsung.*"); 57 | capabilities.setCapability("appium:platformVersion", "12"); 58 | 59 | capabilities.setCapability("appium:app", 60 | "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/Android.SauceLabs.Mobile.Sample.app.2.7.1.apk"); 61 | capabilities.setCapability("appium:appWaitActivity","com.swaglabsmobileapp.MainActivity"); 62 | 63 | // Sauce capabilities 64 | sauceOptions.setCapability("name", methodName); 65 | sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 66 | sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 67 | capabilities.setCapability("sauce:options", sauceOptions); 68 | 69 | driver = new AndroidDriver(url, capabilities); 70 | 71 | } 72 | 73 | @Test 74 | public void demoTest() { 75 | System.out.println("*** Start demoTest test ***"); 76 | 77 | // Login 78 | // Accessibility-id test-Username 79 | // Accessibility-id test-Password 80 | // Accessibility-id test-LOGIN 81 | driver.findElement(AppiumBy.accessibilityId("test-Username")).sendKeys("standard_user"); 82 | driver.findElement(AppiumBy.accessibilityId("test-Password")).sendKeys("secret_sauce"); 83 | driver.findElement(AppiumBy.accessibilityId("test-LOGIN")).click(); 84 | 85 | // Verify 86 | // xpath //android.widget.ScrollView[@content-desc="test-PRODUCTS"] 87 | Assert.assertTrue(isOnProductsPage()); 88 | 89 | } 90 | 91 | @AfterMethod 92 | public void teardown(ITestResult result) { 93 | System.out.println("*** AfterMethod hook ***"); 94 | // (3) Add code to check if test passed or failed 95 | try { 96 | ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed")); 97 | } finally { 98 | driver.quit(); 99 | } 100 | } 101 | 102 | public boolean isOnProductsPage() { 103 | 104 | //Create an instance of an explicit wait so that we can dynamically wait for an element 105 | WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); 106 | 107 | //wait for the product field to be visible and store that element into a variable 108 | try { 109 | wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//android.widget.ScrollView[@content-desc=\"test-PRODUCTS\"]"))); 110 | } catch (TimeoutException e){ 111 | return false; 112 | } 113 | return true; 114 | } 115 | 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/com/demo/answers/ex3_CreateIOSDriver.java: -------------------------------------------------------------------------------- 1 | package com.demo.answers; 2 | 3 | import io.appium.java_client.android.AndroidDriver; 4 | import io.appium.java_client.ios.IOSDriver; 5 | import org.openqa.selenium.MutableCapabilities; 6 | import org.testng.ITestResult; 7 | import org.testng.annotations.AfterMethod; 8 | import org.testng.annotations.BeforeMethod; 9 | import org.testng.annotations.Test; 10 | 11 | import java.lang.reflect.Method; 12 | import java.net.MalformedURLException; 13 | import java.net.URL; 14 | 15 | import static com.demo.Config.region; 16 | 17 | public class ex3_CreateIOSDriver { 18 | 19 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 20 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 21 | 22 | private IOSDriver driver; 23 | 24 | @BeforeMethod 25 | public void setup(Method method) throws MalformedURLException { 26 | 27 | String methodName = method.getName(); 28 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 29 | URL url; 30 | 31 | switch (region) { 32 | case "us": 33 | System.out.println("region is us"); 34 | url = new URL(SAUCE_US_URL); 35 | break; 36 | case "eu": 37 | default: 38 | System.out.println("region is eu"); 39 | url = new URL(SAUCE_EU_URL); 40 | break; 41 | } 42 | 43 | MutableCapabilities capabilities = new MutableCapabilities(); 44 | MutableCapabilities sauceOptions = new MutableCapabilities(); 45 | 46 | //find a device in the cloud 47 | capabilities.setCapability("platformName", "iOS"); 48 | capabilities.setCapability("automationName", "XCuiTest"); 49 | capabilities.setCapability("appium:deviceName", "iPhone.*"); 50 | capabilities.setCapability("appium:platformVersion", "14"); 51 | 52 | capabilities.setCapability("appium:app", 53 | "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/iOS.RealDevice.SauceLabs.Mobile.Sample.app.2.7.1.ipa"); 54 | 55 | // Sauce capabilities 56 | sauceOptions.setCapability("name", methodName); 57 | sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 58 | sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 59 | capabilities.setCapability("sauce:options", sauceOptions); 60 | 61 | driver = new IOSDriver(url, capabilities); 62 | 63 | } 64 | 65 | @Test 66 | public void demoTest() { 67 | System.out.println("*** Start demoTest test ***"); 68 | } 69 | 70 | @AfterMethod 71 | public void teardown(ITestResult result) { 72 | System.out.println("*** AfterMethod hook ***"); 73 | driver.quit(); 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/com/demo/answers/ex4_DevelopIOSTest.java: -------------------------------------------------------------------------------- 1 | package com.demo.answers; 2 | 3 | import io.appium.java_client.AppiumBy; 4 | import io.appium.java_client.ios.IOSDriver; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.JavascriptExecutor; 7 | import org.openqa.selenium.MutableCapabilities; 8 | import org.openqa.selenium.TimeoutException; 9 | import org.openqa.selenium.support.ui.ExpectedConditions; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | import org.testng.Assert; 12 | import org.testng.ITestResult; 13 | import org.testng.annotations.AfterMethod; 14 | import org.testng.annotations.BeforeMethod; 15 | import org.testng.annotations.Test; 16 | 17 | import java.lang.reflect.Method; 18 | import java.net.MalformedURLException; 19 | import java.net.URL; 20 | import java.time.Duration; 21 | 22 | import static com.demo.Config.region; 23 | 24 | public class ex4_DevelopIOSTest { 25 | 26 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 27 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 28 | 29 | private IOSDriver driver; 30 | 31 | @BeforeMethod 32 | public void setup(Method method) throws MalformedURLException { 33 | 34 | String methodName = method.getName(); 35 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 36 | URL url; 37 | 38 | switch (region) { 39 | case "us": 40 | System.out.println("region is us"); 41 | url = new URL(SAUCE_US_URL); 42 | break; 43 | case "eu": 44 | default: 45 | System.out.println("region is eu"); 46 | url = new URL(SAUCE_EU_URL); 47 | break; 48 | } 49 | 50 | MutableCapabilities capabilities = new MutableCapabilities(); 51 | MutableCapabilities sauceOptions = new MutableCapabilities(); 52 | 53 | //find a device in the cloud 54 | capabilities.setCapability("platformName", "iOS"); 55 | capabilities.setCapability("automationName", "XCuiTest"); 56 | capabilities.setCapability("appium:deviceName", "iPhone.*"); 57 | capabilities.setCapability("appium:platformVersion", "14"); 58 | 59 | capabilities.setCapability("appium:app", 60 | "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/iOS.RealDevice.SauceLabs.Mobile.Sample.app.2.7.1.ipa"); 61 | 62 | // Sauce capabilities 63 | sauceOptions.setCapability("name", methodName); 64 | sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 65 | sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 66 | capabilities.setCapability("sauce:options", sauceOptions); 67 | 68 | driver = new IOSDriver(url, capabilities); 69 | 70 | } 71 | 72 | @Test 73 | public void demoTest() { 74 | System.out.println("*** Start demoTest test ***"); 75 | 76 | // Login 77 | // Accessibility-id test-Username 78 | // Accessibility-id test-Password 79 | // Accessibility-id test-LOGIN 80 | driver.findElement(AppiumBy.accessibilityId("test-Username")).sendKeys("standard_user"); 81 | driver.findElement(AppiumBy.accessibilityId("test-Password")).sendKeys("secret_sauce"); 82 | driver.findElement(AppiumBy.accessibilityId("test-LOGIN")).click(); 83 | 84 | // Verify 85 | // xpath //android.widget.ScrollView[@content-desc="test-PRODUCTS"] 86 | Assert.assertTrue(isOnProductsPage()); 87 | 88 | } 89 | 90 | @AfterMethod 91 | public void teardown(ITestResult result) { 92 | System.out.println("*** AfterMethod hook ***"); 93 | try { 94 | ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed")); 95 | } finally { 96 | driver.quit(); 97 | } 98 | } 99 | 100 | public boolean isOnProductsPage() { 101 | 102 | //Create an instance of an explicit wait so that we can dynamically wait for an element 103 | WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); 104 | 105 | //wait for the product field to be visible and store that element into a variable 106 | try { 107 | wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//XCUIElementTypeStaticText[@name=\"PRODUCTS\"]"))); 108 | } catch (TimeoutException e){ 109 | return false; 110 | } 111 | return true; 112 | } 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/com/demo/exercises/ex1_CreateAndroidDriver.java: -------------------------------------------------------------------------------- 1 | package com.demo.exercises; 2 | 3 | import io.appium.java_client.android.AndroidDriver; 4 | import org.openqa.selenium.MutableCapabilities; 5 | import org.testng.ITestResult; 6 | import org.testng.annotations.AfterMethod; 7 | import org.testng.annotations.BeforeMethod; 8 | import org.testng.annotations.Test; 9 | 10 | import java.lang.reflect.Method; 11 | import java.net.MalformedURLException; 12 | import java.net.URL; 13 | 14 | import static com.demo.Config.region; 15 | 16 | public class ex1_CreateAndroidDriver { 17 | 18 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 19 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 20 | 21 | // (1) define a driver 22 | //private AndroidDriver driver; 23 | 24 | @BeforeMethod 25 | public void setup(Method method) throws MalformedURLException { 26 | 27 | String methodName = method.getName(); 28 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 29 | URL url; 30 | 31 | switch (region) { 32 | case "us": 33 | System.out.println("region is us"); 34 | url = new URL(SAUCE_US_URL); 35 | break; 36 | case "eu": 37 | default: 38 | System.out.println("region is eu"); 39 | url = new URL(SAUCE_EU_URL); 40 | break; 41 | } 42 | 43 | // (2) create the needed capabilities 44 | // MutableCapabilities capabilities = new MutableCapabilities(); 45 | // MutableCapabilities sauceOptions = new MutableCapabilities(); 46 | 47 | // Capabilities: platformName , automationName, appium:deviceName , appium:platformVersion 48 | // Values: Samsung.* , UiAutomator2, 12, android 49 | 50 | 51 | // capabilities.setCapability("appium:app", 52 | // "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/Android.SauceLabs.Mobile.Sample.app.2.7.1.apk"); 53 | // capabilities.setCapability("appium:appWaitActivity","com.swaglabsmobileapp.MainActivity"); 54 | 55 | // Sauce capabilities 56 | // sauceOptions.setCapability("name", methodName); 57 | // sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 58 | // sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 59 | // capabilities.setCapability("sauce:options", sauceOptions); 60 | // 61 | // driver = new AndroidDriver(url, capabilities); 62 | 63 | } 64 | 65 | @Test 66 | public void demoTest() { 67 | System.out.println("*** Start demoTest test ***"); 68 | } 69 | 70 | @AfterMethod 71 | public void teardown(ITestResult result) { 72 | System.out.println("*** AfterMethod hook ***"); 73 | 74 | // (3) quit the driver 75 | // driver.quit(); 76 | } 77 | 78 | // (4) in resources -> config -> myDemoTests.xml point to this class 79 | // 80 | 81 | // (5) In the terminal run the cmd : "mvn clean test" 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/com/demo/exercises/ex2_DevelopAndroidTest.java: -------------------------------------------------------------------------------- 1 | package com.demo.exercises; 2 | 3 | import io.appium.java_client.AppiumBy; 4 | import io.appium.java_client.android.AndroidDriver; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.JavascriptExecutor; 7 | import org.openqa.selenium.MutableCapabilities; 8 | import org.openqa.selenium.TimeoutException; 9 | import org.openqa.selenium.support.ui.ExpectedConditions; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | import org.testng.Assert; 12 | import org.testng.ITestResult; 13 | import org.testng.annotations.AfterMethod; 14 | import org.testng.annotations.BeforeMethod; 15 | import org.testng.annotations.Test; 16 | 17 | import java.lang.reflect.Method; 18 | import java.net.MalformedURLException; 19 | import java.net.URL; 20 | import java.time.Duration; 21 | 22 | import static com.demo.Config.region; 23 | 24 | public class ex2_DevelopAndroidTest { 25 | 26 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 27 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 28 | 29 | private AndroidDriver driver; 30 | 31 | @BeforeMethod 32 | public void setup(Method method) throws MalformedURLException { 33 | 34 | String methodName = method.getName(); 35 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 36 | URL url; 37 | 38 | switch (region) { 39 | case "us": 40 | System.out.println("region is us"); 41 | url = new URL(SAUCE_US_URL); 42 | break; 43 | case "eu": 44 | default: 45 | System.out.println("region is eu"); 46 | url = new URL(SAUCE_EU_URL); 47 | break; 48 | } 49 | 50 | MutableCapabilities capabilities = new MutableCapabilities(); 51 | MutableCapabilities sauceOptions = new MutableCapabilities(); 52 | 53 | //find a device in the cloud 54 | capabilities.setCapability("platformName", "android"); 55 | capabilities.setCapability("automationName", "UiAutomator2"); 56 | capabilities.setCapability("appium:deviceName", "Samsung.*"); 57 | capabilities.setCapability("appium:platformVersion", "12"); 58 | 59 | capabilities.setCapability("appium:app", 60 | "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/Android.SauceLabs.Mobile.Sample.app.2.7.1.apk"); 61 | capabilities.setCapability("appium:appWaitActivity","com.swaglabsmobileapp.MainActivity"); 62 | 63 | // Sauce capabilities 64 | sauceOptions.setCapability("name", methodName); 65 | sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 66 | sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 67 | capabilities.setCapability("sauce:options", sauceOptions); 68 | 69 | driver = new AndroidDriver(url, capabilities); 70 | 71 | } 72 | 73 | @Test 74 | public void demoTest() { 75 | System.out.println("*** Start demoTest test ***"); 76 | 77 | // (1) Add code to set username and password, click on the login button 78 | // Login 79 | // Accessibility-id test-Username sendKeys standard_user 80 | // Accessibility-id test-Password sendKeys secret_sauce 81 | // Accessibility-id test-LOGIN click 82 | driver.findElement(AppiumBy.accessibilityId("test-Username")).sendKeys("standard_user"); 83 | 84 | // (2) add code to verify we are on the next page 85 | // Verify using Assert.assertTrue 86 | // xpath -> //android.widget.ScrollView[@content-desc="test-PRODUCTS"] 87 | //Assert.assertTrue(isOnProductsPage()); 88 | 89 | } 90 | 91 | @AfterMethod 92 | public void teardown(ITestResult result) { 93 | System.out.println("*** AfterMethod hook ***"); 94 | // (3) Add code to check if test passed or failed 95 | try { 96 | // ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed")); 97 | } finally { 98 | driver.quit(); 99 | } 100 | } 101 | 102 | // public boolean isOnProductsPage() { 103 | // 104 | // //Create an instance of an explicit wait so that we can dynamically wait for an element 105 | // WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); 106 | // 107 | // //wait for the product field to be visible and store that element into a variable 108 | // try { 109 | // wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//android.widget.ScrollView[@content-desc=\"test-PRODUCTS\"]"))); 110 | // } catch (TimeoutException e){ 111 | // return false; 112 | // } 113 | // return true; 114 | // } 115 | 116 | // (4) in resources -> config -> myDemoTests.xml point to this class 117 | // 118 | 119 | // (5) In the terminal run the cmd : "mvn clean test" 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/com/demo/exercises/ex3_CreateIOSDriver.java: -------------------------------------------------------------------------------- 1 | package com.demo.exercises; 2 | 3 | import io.appium.java_client.ios.IOSDriver; 4 | import org.openqa.selenium.MutableCapabilities; 5 | import org.testng.ITestResult; 6 | import org.testng.annotations.AfterMethod; 7 | import org.testng.annotations.BeforeMethod; 8 | import org.testng.annotations.Test; 9 | 10 | import java.lang.reflect.Method; 11 | import java.net.MalformedURLException; 12 | import java.net.URL; 13 | 14 | import static com.demo.Config.region; 15 | 16 | public class ex3_CreateIOSDriver { 17 | 18 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 19 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 20 | 21 | // (1) define a driver 22 | // private IOSDriver driver; 23 | 24 | @BeforeMethod 25 | public void setup(Method method) throws MalformedURLException { 26 | 27 | String methodName = method.getName(); 28 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 29 | URL url; 30 | 31 | switch (region) { 32 | case "us": 33 | System.out.println("region is us"); 34 | url = new URL(SAUCE_US_URL); 35 | break; 36 | case "eu": 37 | default: 38 | System.out.println("region is eu"); 39 | url = new URL(SAUCE_EU_URL); 40 | break; 41 | } 42 | 43 | // (2) create the needed capabilities 44 | // MutableCapabilities capabilities = new MutableCapabilities(); 45 | // MutableCapabilities sauceOptions = new MutableCapabilities(); 46 | 47 | // Capabilities: platformName , automationName, appium:deviceName , appium:platformVersion 48 | // Values: iPhone.* , XCuiTest, 14, iOS 49 | 50 | // capabilities.setCapability("appium:app", 51 | // "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/iOS.RealDevice.SauceLabs.Mobile.Sample.app.2.7.1.ipa"); 52 | 53 | // Sauce capabilities 54 | // sauceOptions.setCapability("name", methodName); 55 | // sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 56 | // sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 57 | // capabilities.setCapability("sauce:options", sauceOptions); 58 | 59 | // driver = new IOSDriver(url, capabilities); 60 | 61 | } 62 | 63 | @Test 64 | public void demoTest() { 65 | System.out.println("*** Start demoTest test ***"); 66 | } 67 | 68 | @AfterMethod 69 | public void teardown(ITestResult result) { 70 | System.out.println("*** AfterMethod hook ***"); 71 | // (3) quit the driver 72 | // driver.quit(); 73 | } 74 | 75 | // (4) in resources -> config -> myDemoTests.xml point to this class 76 | // 77 | 78 | // (5) In the terminal run the cmd : "mvn clean test" 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/com/demo/exercises/ex4_DevelopIOSTest.java: -------------------------------------------------------------------------------- 1 | package com.demo.exercises; 2 | 3 | import io.appium.java_client.AppiumBy; 4 | import io.appium.java_client.ios.IOSDriver; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.JavascriptExecutor; 7 | import org.openqa.selenium.MutableCapabilities; 8 | import org.openqa.selenium.TimeoutException; 9 | import org.openqa.selenium.support.ui.ExpectedConditions; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | import org.testng.Assert; 12 | import org.testng.ITestResult; 13 | import org.testng.annotations.AfterMethod; 14 | import org.testng.annotations.BeforeMethod; 15 | import org.testng.annotations.Test; 16 | 17 | import java.lang.reflect.Method; 18 | import java.net.MalformedURLException; 19 | import java.net.URL; 20 | import java.time.Duration; 21 | 22 | import static com.demo.Config.region; 23 | 24 | public class ex4_DevelopIOSTest { 25 | 26 | private String SAUCE_EU_URL = "https://ondemand.eu-central-1.saucelabs.com/wd/hub"; 27 | private String SAUCE_US_URL = "https://ondemand.us-west-1.saucelabs.com/wd/hub"; 28 | 29 | private IOSDriver driver; 30 | 31 | @BeforeMethod 32 | public void setup(Method method) throws MalformedURLException { 33 | 34 | String methodName = method.getName(); 35 | System.out.println("*** BeforeMethod hook. Running method " + methodName + " ***"); 36 | URL url; 37 | 38 | switch (region) { 39 | case "us": 40 | System.out.println("region is us"); 41 | url = new URL(SAUCE_US_URL); 42 | break; 43 | case "eu": 44 | default: 45 | System.out.println("region is eu"); 46 | url = new URL(SAUCE_EU_URL); 47 | break; 48 | } 49 | 50 | MutableCapabilities capabilities = new MutableCapabilities(); 51 | MutableCapabilities sauceOptions = new MutableCapabilities(); 52 | 53 | //find a device in the cloud 54 | capabilities.setCapability("platformName", "iOS"); 55 | capabilities.setCapability("automationName", "XCuiTest"); 56 | capabilities.setCapability("appium:deviceName", "iPhone.*"); 57 | capabilities.setCapability("appium:platformVersion", "14"); 58 | 59 | capabilities.setCapability("appium:app", 60 | "https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/iOS.RealDevice.SauceLabs.Mobile.Sample.app.2.7.1.ipa"); 61 | 62 | // Sauce capabilities 63 | sauceOptions.setCapability("name", methodName); 64 | sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME")); 65 | sauceOptions.setCapability("accessKey", System.getenv("SAUCE_ACCESS_KEY")); 66 | capabilities.setCapability("sauce:options", sauceOptions); 67 | 68 | driver = new IOSDriver(url, capabilities); 69 | 70 | } 71 | 72 | @Test 73 | public void demoTest() { 74 | System.out.println("*** Start demoTest test ***"); 75 | 76 | // (1) Add code to set username and password, click on the login button 77 | // Login 78 | // Accessibility-id test-Username sendKeys standard_user 79 | // Accessibility-id test-Password sendKeys secret_sauce 80 | // Accessibility-id test-LOGIN click 81 | driver.findElement(AppiumBy.accessibilityId("test-Username")).sendKeys("standard_user"); 82 | 83 | // (2) add code to verify we are on the next page 84 | // Verify using Assert.assertTrue 85 | // xpath -> //XCUIElementTypeStaticText[@name="PRODUCTS"] 86 | //Assert.assertTrue(isOnProductsPage()); 87 | 88 | } 89 | 90 | @AfterMethod 91 | public void teardown(ITestResult result) { 92 | System.out.println("*** AfterMethod hook ***"); 93 | // (3) Add code to check if test passed or failed 94 | try { 95 | // ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed")); 96 | } finally { 97 | driver.quit(); 98 | } 99 | } 100 | 101 | // public boolean isOnProductsPage() { 102 | // 103 | // //Create an instance of an explicit wait so that we can dynamically wait for an element 104 | // WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); 105 | // 106 | // //wait for the product field to be visible and store that element into a variable 107 | // try { 108 | // wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//XCUIElementTypeStaticText[@name=\"PRODUCTS\"]"))); 109 | // } catch (TimeoutException e){ 110 | // return false; 111 | // } 112 | // return true; 113 | // } 114 | 115 | // (4) in resources -> config -> myDemoTests.xml point to this class 116 | // 117 | 118 | // (5) In the terminal run the cmd : "mvn clean test" 119 | 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/test/resources/config/myDemoParallelTests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/config/myDemoTests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | --------------------------------------------------------------------------------