├── .gitignore ├── .sauce.yml ├── .travis.yml ├── Jenkinsfile ├── README.md ├── pom.xml └── src └── test └── java └── com └── yourcompany ├── Pages └── GuineaPigPage.java └── Tests ├── FollowLinkTest.java ├── TestBase.java └── TextInputTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | target 3 | .idea 4 | *.iml 5 | .DS_Store -------------------------------------------------------------------------------- /.sauce.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: "java" 3 | maven-version: "3.3" 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | before_install: 5 | - export | grep SAUCE_ 6 | script: mvn clean test 7 | env: 8 | global: 9 | - BUILD_TAG=$TRAVIS_REPO_SLUG+$TRAVIS_BUILD_NUMBER 10 | - SAUCE_USERNAME=sauce_examples 11 | addons: 12 | jwt: 13 | secure: i6R/B/3F45mhSfu0/7iFmcWYHv97lp+mR35qqmXJ0SstIcmgtAKxSrxh9nTzi+Cy8arX1MRwGYrSTFZh9wGGREkJ52hfzZe3VFWDbqdmX/oPxI5xU/50kYKyMl0D5L3dKerhvkBvUVEY+AC6vSkurQ46bfzF0i//hW4ymhUElUnvc72Kj85SKMIu+sWitDVu4LZPkdDiPSq7ExnPMg2mwfSALLR2BwoAwZ8IYff0r30RsJQqhRzrkoBoX4WU2PTHnZbUlYE1yXiAPmsWrASEB+GsqpKgscPpi1jZYdjYNDedOpTv/pDCfLuyGk48v2MqJHEUc77ASLh9H9HBt9a+lwGanwdnxVE6ywsr+pbb1bKG5PmC4RcskZfpvxa6Saosj/+LdPHXcujjaKJhiHOG0C/x6FdqYeYdzjBXiy0WbY2d4Ht6IGOZoE5gU7AMUt8hQq3ygaqJ8Y8c2C7n00BQ2NbrBxrDsJs4soi6oFSrSkGqz9viLg3y8GHvmrGTKuXjoSiaD48Vidr+KHaL5mlHPVbvQEY4OT0YB79O1scZ53pNLH8vKGPoYOepDIZBnv4UBK2BmGdxfPEcLbSnK5uh6SG6qZN3qQzETL/jPGAzIqVn0zcfjWdgwrNrZgGuZhUpcQbhJPoG+g8F6+KHJL/UQf+bqnTEIh1fPjCklcZ/+KQ= 14 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | def mvnHome = tool 'Maven' 3 | 4 | // Mark the code checkout 'stage'.... 5 | stage 'Checkout' 6 | // Get some code from a GitHub repository 7 | git url: 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Selenium.git' 8 | stage 'Compile' 9 | sh "${mvnHome}/bin/mvn compile" 10 | stage 'Test' 11 | sauce('saucelabs') { 12 | sauceconnect(useGeneratedTunnelIdentifier: true, verboseLogging: true) { 13 | sh "${mvnHome}/bin/mvn test" 14 | } 15 | } 16 | stage 'Collect Results' 17 | step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml']) 18 | step([$class: 'SauceOnDemandTestPublisher']) 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Java-Junit-Selenium 2 | [![Travis Status](https://travis-ci.org/saucelabs-sample-test-frameworks/Java-Junit-Selenium.svg?branch=master)](https://travis-ci.org/saucelabs-sample-test-frameworks/Java-Junit-Selenium) 3 | 4 | This code is provided on an "AS-IS” basis without warranty of any kind, either express or implied, including without limitation any implied warranties of condition, uninterrupted use, merchantability, fitness for a particular purpose, or non-infringement. Your tests and testing environments may require you to modify this framework. Issues regarding this framework should be submitted through GitHub. For questions regarding Sauce Labs integration, please see the Sauce Labs documentation at https://wiki.saucelabs.com/. This framework is not maintained by Sauce Labs Support. 5 | 6 | ### Environment Setup 7 | 8 | 1. Global Dependencies 9 | * Install [Maven](https://maven.apache.org/install.html) 10 | * Or Install Maven with [Homebrew](http://brew.sh/) (Easier) 11 | ``` 12 | $ brew install maven 13 | ``` 14 | 2. Sauce Labs Credentials 15 | * In the terminal, export your Sauce Labs credentials as environmental variables: 16 | ``` 17 | $ export SAUCE_USERNAME= 18 | $ export SAUCE_ACCESS_KEY= 19 | ``` 20 | 3. Project Dependencies 21 | * Check that packages are available 22 | ``` 23 | $ cd Java-Junit-Selenium 24 | $ mvn test-compile 25 | ``` 26 | * You may also want to run the command below to check for outdated dependencies. Please be sure to verify and review updates before editing your pom.xml file as they may not be compatible with your code. 27 | ``` 28 | $ mvn versions:display-dependency-updates 29 | ``` 30 | 31 | ### Running Tests 32 | 33 | #####Testing in Parallel: 34 | ``` 35 | $ mvn test 36 | ``` 37 | [Sauce Labs Dashboard](https://saucelabs.com/beta/dashboard/) 38 | 39 | ### Advice/Troubleshooting 40 | 1. It may be useful to use a Java IDE such as IntelliJ or Eclipse to help troubleshoot potential issues. 41 | 2. There may be additional latency when using a remote webdriver to run tests on Sauce Labs. Timeouts and/or waits may need to be increased. 42 | * [Selenium tips regarding explicit waits](https://wiki.saucelabs.com/display/DOCS/Best+Practice%3A+Use+Explicit+Waits) 43 | 44 | ### Resources 45 | ##### [Sauce Labs Documentation](https://wiki.saucelabs.com/) 46 | 47 | ##### [SeleniumHQ Documentation](http://www.seleniumhq.org/docs/) 48 | 49 | ##### [Junit Documentation](http://junit.org/javadoc/latest/index.html) 50 | 51 | ##### [Java Documentation](https://docs.oracle.com/javase/7/docs/api/) 52 | 53 | ##### [Stack Overflow](http://stackoverflow.com/) 54 | * A great resource to search for issues not explicitly covered by documentation. 55 | 56 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | java-junit-selenium 6 | com.saucelabs 7 | 1.0-SNAPSHOT 8 | jar 9 | java-junit-selenium 10 | A sample Maven project that demonstrates how to integrate Sauce OnDemand with WebDriver tests 11 | that run using JUnit 12 | 13 | 14 | 15 | 16 | junit 17 | junit 18 | 4.12 19 | test 20 | 21 | 22 | org.seleniumhq.selenium 23 | selenium-java 24 | 2.53.1 25 | test 26 | 27 | 28 | com.saucelabs 29 | sauce_junit 30 | 2.1.20 31 | test 32 | 33 | 34 | 35 | 36 | 37 | maven-compiler-plugin 38 | 3.0 39 | 40 | 1.7 41 | 1.7 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-surefire-plugin 47 | 48 | classes 49 | 40 50 | 51 | false 52 | 53 | 2.12.4 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/test/java/com/yourcompany/Pages/GuineaPigPage.java: -------------------------------------------------------------------------------- 1 | package com.yourcompany.Pages; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import org.openqa.selenium.support.PageFactory; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | import org.openqa.selenium.support.ui.ExpectedConditions; 9 | 10 | public class GuineaPigPage { 11 | 12 | @FindBy(linkText = "i am a link") 13 | private WebElement theActiveLink; 14 | 15 | @FindBy(id = "your_comments") 16 | private WebElement yourCommentsSpan; 17 | 18 | @FindBy(id = "comments") 19 | private WebElement commentsTextAreaInput; 20 | 21 | @FindBy(id = "submit") 22 | private WebElement submitButton; 23 | 24 | public WebDriver driver; 25 | public static String url = "https://saucelabs-sample-test-frameworks.github.io/training-test-page"; 26 | 27 | public static GuineaPigPage visitPage(WebDriver driver) { 28 | GuineaPigPage page = new GuineaPigPage(driver); 29 | page.visitPage(); 30 | return page; 31 | } 32 | 33 | public GuineaPigPage(WebDriver driver) { 34 | this.driver = driver; 35 | PageFactory.initElements(driver, this); 36 | } 37 | 38 | public void visitPage() { 39 | this.driver.get(url); 40 | } 41 | 42 | public void followLink() { 43 | this.theActiveLink.click(); 44 | } 45 | 46 | public void submitComment(String text) { 47 | this.commentsTextAreaInput.sendKeys(text); 48 | this.submitButton.click(); 49 | 50 | // Race condition for time to populate yourCommentsSpan 51 | WebDriverWait wait = new WebDriverWait(this.driver, 15); 52 | wait.until(ExpectedConditions.textToBePresentInElement(yourCommentsSpan, text)); 53 | } 54 | 55 | public String getSubmittedCommentText() { 56 | return this.yourCommentsSpan.getText(); 57 | } 58 | 59 | public boolean isOnPage() { 60 | String title = "I am a page title - Sauce Labs"; 61 | return this.driver.getTitle() == title; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/yourcompany/Tests/FollowLinkTest.java: -------------------------------------------------------------------------------- 1 | package com.yourcompany.Tests; 2 | 3 | import com.yourcompany.Pages.*; 4 | import org.junit.Test; 5 | import org.openqa.selenium.InvalidElementStateException; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | public class FollowLinkTest extends TestBase { 10 | 11 | public FollowLinkTest(String os, 12 | String version, String browser, String deviceName, String deviceOrientation) { 13 | super(os, version, browser, deviceName, deviceOrientation); 14 | } 15 | 16 | /** 17 | * Runs a simple test verifying link can be followed. 18 | * @throws InvalidElementStateException 19 | */ 20 | @Test 21 | public void verifyLinkTest() throws InvalidElementStateException { 22 | GuineaPigPage page = GuineaPigPage.visitPage(driver); 23 | 24 | page.followLink(); 25 | 26 | assertFalse(page.isOnPage()); 27 | } 28 | } -------------------------------------------------------------------------------- /src/test/java/com/yourcompany/Tests/TestBase.java: -------------------------------------------------------------------------------- 1 | package com.yourcompany.Tests; 2 | 3 | import com.saucelabs.common.SauceOnDemandAuthentication; 4 | 5 | import org.junit.*; 6 | import org.junit.rules.TestName; 7 | import org.junit.runner.RunWith; 8 | import org.openqa.selenium.WebDriver; 9 | import org.openqa.selenium.remote.CapabilityType; 10 | import org.openqa.selenium.remote.DesiredCapabilities; 11 | import org.openqa.selenium.remote.RemoteWebDriver; 12 | 13 | import com.saucelabs.junit.ConcurrentParameterized; 14 | import com.saucelabs.junit.SauceOnDemandTestWatcher; 15 | 16 | import java.net.URL; 17 | import java.util.LinkedList; 18 | 19 | import com.saucelabs.common.SauceOnDemandSessionIdProvider; 20 | 21 | 22 | 23 | /** 24 | * Demonstrates how to write a JUnit test that runs tests against Sauce Labs using multiple browsers in parallel. 25 | *

26 | * The test also includes the {@link SauceOnDemandTestWatcher} which will invoke the Sauce REST API to mark 27 | * the test as passed or failed. 28 | * 29 | * @author Neil Manvar 30 | */ 31 | @Ignore 32 | @RunWith(ConcurrentParameterized.class) 33 | public class TestBase implements SauceOnDemandSessionIdProvider { 34 | 35 | public static String username = System.getenv("SAUCE_USERNAME"); 36 | public static String accesskey = System.getenv("SAUCE_ACCESS_KEY"); 37 | public static String seleniumURI; 38 | public static String buildTag; 39 | /** 40 | * Constructs a {@link SauceOnDemandAuthentication} instance using the supplied user name/access key. To use the authentication 41 | * supplied by environment variables or from an external file, use the no-arg {@link SauceOnDemandAuthentication} constructor. 42 | */ 43 | public SauceOnDemandAuthentication authentication = new SauceOnDemandAuthentication(username, accesskey); 44 | 45 | /** 46 | * JUnit Rule which will mark the Sauce Job as passed/failed when the test succeeds or fails. 47 | */ 48 | @Rule 49 | public SauceOnDemandTestWatcher resultReportingTestWatcher = new SauceOnDemandTestWatcher(this, authentication); 50 | 51 | @Rule 52 | public TestName name = new TestName() { 53 | public String getMethodName() { 54 | return String.format("%s", super.getMethodName()); 55 | } 56 | }; 57 | 58 | protected String browser; 59 | protected String os; 60 | protected String version; 61 | protected String deviceName; 62 | protected String deviceOrientation; 63 | protected String sessionId; 64 | protected WebDriver driver; 65 | 66 | /** 67 | * Constructs a new instance of the test. The constructor requires three string parameters, which represent the operating 68 | * system, version and browser to be used when launching a Sauce VM. The order of the parameters should be the same 69 | * as that of the elements within the {@link #browsersStrings()} method. 70 | * @param os 71 | * @param version 72 | * @param browser 73 | * @param deviceName 74 | * @param deviceOrientation 75 | */ 76 | 77 | public TestBase(String os, String version, String browser, String deviceName, String deviceOrientation) { 78 | super(); 79 | this.os = os; 80 | this.version = version; 81 | this.browser = browser; 82 | this.deviceName = deviceName; 83 | this.deviceOrientation = deviceOrientation; 84 | } 85 | 86 | /** 87 | * @return a LinkedList containing String arrays representing the browser combinations the test should be run against. The values 88 | * in the String array are used as part of the invocation of the test constructor 89 | */ 90 | @ConcurrentParameterized.Parameters 91 | public static LinkedList browsersStrings() { 92 | LinkedList browsers = new LinkedList(); 93 | 94 | browsers.add(new String[]{"Windows 10", "14.14393", "MicrosoftEdge", null, null}); 95 | browsers.add(new String[]{"Windows 10", "49.0", "firefox", null, null}); 96 | browsers.add(new String[]{"Windows 7", "11.0", "internet explorer", null, null}); 97 | browsers.add(new String[]{"OS X 10.11", "10.0", "safari", null, null}); 98 | browsers.add(new String[]{"OS X 10.10", "54.0", "chrome", null, null}); 99 | return browsers; 100 | } 101 | 102 | /** 103 | * Constructs a new {@link RemoteWebDriver} instance which is configured to use the capabilities defined by the {@link #browser}, 104 | * {@link #version} and {@link #os} instance variables, and which is configured to run against ondemand.saucelabs.com, using 105 | * the username and access key populated by the {@link #authentication} instance. 106 | * 107 | * @throws Exception if an error occurs during the creation of the {@link RemoteWebDriver} instance. 108 | */ 109 | @Before 110 | public void setUp() throws Exception { 111 | DesiredCapabilities capabilities = new DesiredCapabilities(); 112 | 113 | capabilities.setCapability(CapabilityType.BROWSER_NAME, browser); 114 | capabilities.setCapability(CapabilityType.VERSION, version); 115 | capabilities.setCapability("deviceName", deviceName); 116 | capabilities.setCapability("device-orientation", deviceOrientation); 117 | capabilities.setCapability(CapabilityType.PLATFORM, os); 118 | 119 | String methodName = name.getMethodName(); 120 | capabilities.setCapability("name", methodName); 121 | 122 | //Getting the build name. 123 | //Using the Jenkins ENV var. You can use your own. If it is not set test will run without a build id. 124 | if (buildTag != null) { 125 | capabilities.setCapability("build", buildTag); 126 | } 127 | this.driver = new RemoteWebDriver( 128 | new URL("https://" + username+ ":" + accesskey + seleniumURI +"/wd/hub"), 129 | capabilities); 130 | 131 | this.sessionId = (((RemoteWebDriver) driver).getSessionId()).toString(); 132 | } 133 | 134 | @After 135 | public void tearDown() throws Exception { 136 | driver.quit(); 137 | } 138 | 139 | /** 140 | * @return the value of the Sauce Job id. 141 | */ 142 | @Override 143 | public String getSessionId() { 144 | return sessionId; 145 | } 146 | 147 | @BeforeClass 148 | public static void setupClass() { 149 | //get the uri to send the commands to. 150 | seleniumURI = "@ondemand.saucelabs.com:443"; 151 | //If available add build tag. When running under Jenkins BUILD_TAG is automatically set. 152 | //You can set this manually on manual runs. 153 | buildTag = System.getenv("BUILD_TAG"); 154 | if (buildTag == null) { 155 | buildTag = System.getenv("SAUCE_BUILD_NAME"); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/test/java/com/yourcompany/Tests/TextInputTest.java: -------------------------------------------------------------------------------- 1 | package com.yourcompany.Tests; 2 | 3 | import com.yourcompany.Pages.*; 4 | import org.junit.Test; 5 | import org.openqa.selenium.InvalidElementStateException; 6 | import static org.hamcrest.CoreMatchers.containsString; 7 | 8 | import java.util.UUID; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | public class TextInputTest extends TestBase { 13 | 14 | public TextInputTest(String os, 15 | String version, String browser, String deviceName, String deviceOrientation) { 16 | super(os, version, browser, deviceName, deviceOrientation); 17 | } 18 | 19 | /** 20 | * Runs a simple test verifying if the comment input is functional. 21 | * @throws InvalidElementStateException 22 | */ 23 | @Test 24 | public void verifyCommentInputTest() throws InvalidElementStateException { 25 | String commentInputText = UUID.randomUUID().toString(); 26 | 27 | GuineaPigPage page = GuineaPigPage.visitPage(driver); 28 | page.visitPage(); 29 | page.submitComment(commentInputText); 30 | 31 | assertThat(page.getSubmittedCommentText(), containsString(commentInputText)); 32 | } 33 | } --------------------------------------------------------------------------------