├── .github └── allure-img.png ├── .gitignore ├── .travis.yml ├── MIT-LICENSE.txt ├── README.md ├── driver ├── linux │ ├── chromedriver │ └── geckodriver ├── osx │ ├── chromedriver │ └── geckodriver └── windows │ ├── chromedriver.exe │ └── geckodriver.exe ├── pom.xml ├── src ├── main │ ├── java │ │ └── selenium │ │ │ ├── appDomain │ │ │ └── AppDomain.java │ │ │ ├── config │ │ │ └── DomainConfiguration.java │ │ │ ├── driver │ │ │ ├── Driver.java │ │ │ └── DriverManager.java │ │ │ ├── localization │ │ │ └── LocaleText.java │ │ │ └── pageobject │ │ │ ├── HomePage.java │ │ │ └── LoginPage.java │ └── resources │ │ └── locale_en.properties └── test │ ├── java │ └── selenium │ │ ├── Application.java │ │ ├── context │ │ └── Base.java │ │ ├── listeners │ │ └── WebDriverListener.java │ │ ├── testdata │ │ ├── file │ │ │ └── FileLoaderService.java │ │ └── properties │ │ │ └── User.java │ │ └── tests │ │ └── SimpleTestExamples.java │ └── resources │ ├── application-release.properties │ ├── application.properties │ └── testdata │ └── user │ └── user_com.json └── testng.xml /.github/allure-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edinc/java-selenium-framework/fd31c15b7456a64c2b95792bdf3dc7af1a09ca13/.github/allure-img.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | *.iml 3 | *.DS_Store 4 | velocity.log 5 | target 6 | test-output 7 | allure-results -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: osx 2 | language: java 3 | sudo: required 4 | 5 | env: 6 | - MOZ_HEADLESS=1 7 | addons: 8 | firefox: latest 9 | 10 | script: 11 | - mvn clean test -Dspring.profiles.active=live -Dcountry=com -Dbrowser=firefox -Dmode=headless 12 | 13 | notifications: 14 | slack: tehnografija:yGLRFooashh7wutsGmMQFxou -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Edin Cenanovic 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Selenium Framework [![Build Status](https://travis-ci.org/edinc/java-selenium-framework.svg?branch=master)](https://travis-ci.org/edinc/java-selenium-framework) 2 | 3 | The Selenium Java Framework is a good starting point for writing your UI automated tests utilizing Java, 4 | Selenium and Zalenium for running the tests in a CI manner. 5 | 6 | ## Features 7 | ### Multiple domains 8 | Tests can be configured to run against different domains. For example: 9 | https://www.some-site.de and https://www.some-site.fr. 10 | 11 | ### Multiple environments 12 | Similar as for multiple domains the tests can also be run on multiple environments, 13 | for example a staging and a live environment. It is as simple as changing a spring profile parameter. 14 | 15 | ### Localization 16 | Page content can be validated with different languages through a config file. 17 | 18 | ### User data handling 19 | Handling user data within a json file where the appropriate user will be determined by country. 20 | 21 | ### Headless 22 | The option to run the tests in headless mode (without opening a browser). 23 | 24 | ### Zalenium integration 25 | [Zalenium](https://github.com/zalando/zalenium) is a Selenium Grid extension to scale your local grid dynamically with docker containers. 26 | 27 | ### Allure reports integration 28 | [Allure Framework](https://github.com/allure-framework/allure2) is a flexible lightweight multi-language test report tool that shows a very concise representation of what has been tested in a neat web report form 29 | 30 | ### Parallelization 31 | The framework has the ability to run multiple tests in parallel. Setting this up just requires to set the `thread-count` paramenter in `testng.xml`. 32 | 33 | ## Tech Stack 34 | * Java 8 35 | * Maven 36 | * Spring Boot 37 | * TestNG 38 | * Allure 39 | * Zalenium 40 | 41 | ## How-to 42 | ### Local on different browsers 43 | To run the tests on your local machine use the command: 44 | 45 | ``` 46 | mvn clean test -Dspring.profiles.active=live -Dcountry=com -Dbrowser=chrome 47 | ``` 48 | 49 | The parameters explained: 50 | * `spring.profiles.active` - defines on which environment the tests will run 51 | * `country` - defines on which domain the tests will run 52 | * `browser` - defines the browser (`chrome/firefox`) 53 | 54 | 55 | ### With Zalenium 56 | To be able to run the tests on Zalenium (which is basically just a dockerized Selenium Grid), first Zalenium has to be started. 57 | ``` 58 | # Pull docker-selenium 59 | docker pull elgalu/selenium 60 | 61 | # Pull Zalenium 62 | docker pull dosel/zalenium 63 | 64 | docker run --rm -ti --name zalenium -p 4444:4444 \ 65 | -v /var/run/docker.sock:/var/run/docker.sock \ 66 | -v /tmp/videos:/home/seluser/videos \ 67 | --privileged dosel/zalenium start 68 | ``` 69 | 70 | After Zalenium is running just the browser parameter has to be changed in order to run the tests 71 | 72 | ``` 73 | mvn clean test -Dspring.profiles.active=live -Dcountry=com -Dbrowser=zalenium 74 | ``` 75 | 76 | ### Headless 77 | The latest versions of the Chrome and Firefox browsers have the feature to run browsers in headless mode. This speeds up the running time of the tests immensely. For running the tests using the headlless mode feature: 78 | 79 | ``` 80 | mvn clean test -Dspring.profiles.active=live -Dcountry=com -Dbrowser=chrome -Dmode=headless 81 | ``` 82 | 83 | where as browser either `chrome` or `firefox` can be selected. 84 | 85 | ### Running the tests on a different OS 86 | Currently the tests are configured to run just on MacOS. But this can be changed [here](https://github.com/edinc/java-selenium-framework/blob/master/src/main/java/selenium/driver/DriverManager.java#L21) , the relative path just has to be replaced with the appropriate driver for that OS. 87 | 88 | ## Reports 89 | 90 | Reporting of the tests results is one of the most important aspects of a framework. It doesn't matter how many and good your tests are when they are not enough visible. In this framework Allure was used to generate 91 | visually rich and insightful reports. 92 | 93 | ![Allure Report](.github/allure-img.png) 94 | 95 | Allure has to be installed before being able to show test results: 96 | 97 | ``` 98 | $ brew untap qameta/allure 99 | $ brew update 100 | $ brew install allure 101 | ``` 102 | 103 | After every test run the results are automatically stored in an `allure-results` directory. The results then can be seen locally by running: 104 | 105 | ``` 106 | allure serve 107 | ``` 108 | 109 | or in all popular CI's with the help of allure plugins. 110 | ## Contact 111 | 112 | Open a github issue or for suggestions a Pull Request straight away. -------------------------------------------------------------------------------- /driver/linux/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edinc/java-selenium-framework/fd31c15b7456a64c2b95792bdf3dc7af1a09ca13/driver/linux/chromedriver -------------------------------------------------------------------------------- /driver/linux/geckodriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edinc/java-selenium-framework/fd31c15b7456a64c2b95792bdf3dc7af1a09ca13/driver/linux/geckodriver -------------------------------------------------------------------------------- /driver/osx/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edinc/java-selenium-framework/fd31c15b7456a64c2b95792bdf3dc7af1a09ca13/driver/osx/chromedriver -------------------------------------------------------------------------------- /driver/osx/geckodriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edinc/java-selenium-framework/fd31c15b7456a64c2b95792bdf3dc7af1a09ca13/driver/osx/geckodriver -------------------------------------------------------------------------------- /driver/windows/chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edinc/java-selenium-framework/fd31c15b7456a64c2b95792bdf3dc7af1a09ca13/driver/windows/chromedriver.exe -------------------------------------------------------------------------------- /driver/windows/geckodriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edinc/java-selenium-framework/fd31c15b7456a64c2b95792bdf3dc7af1a09ca13/driver/windows/geckodriver.exe -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | testng.xml 9 | 1.8.12 10 | 11 | 12 | java.selenium 13 | java-selenium-framework 14 | 1.0-SNAPSHOT 15 | 16 | 17 | 18 | edinc 19 | Edin Cenanovic 20 | cenanovice@gmail.com 21 | 22 | 23 | 24 | 25 | 26 | org.seleniumhq.selenium 27 | selenium-java 28 | 3.12.0 29 | 30 | 31 | org.hamcrest 32 | hamcrest-all 33 | 1.3 34 | test 35 | 36 | 37 | com.saucelabs 38 | saucerest 39 | 1.0.35 40 | 41 | 42 | org.testng 43 | testng 44 | 6.11 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter 49 | 1.3.1.RELEASE 50 | 51 | 52 | org.springframework 53 | spring-web 54 | 4.2.4.RELEASE 55 | 56 | 57 | org.springframework 58 | spring-test 59 | 4.2.4.RELEASE 60 | 61 | 62 | io.qameta.allure 63 | allure-testng 64 | 2.0-BETA19 65 | test 66 | 67 | 68 | org.apache.commons 69 | commons-lang3 70 | 3.4 71 | 72 | 73 | com.fasterxml.jackson.core 74 | jackson-databind 75 | 2.9.10.3 76 | test 77 | 78 | 79 | 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-surefire-plugin 85 | 2.20.1 86 | 87 | 88 | ${suiteXmlFile} 89 | 90 | 91 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" 92 | 93 | 94 | 95 | usedefaultlisteners 96 | false 97 | 98 | 99 | 100 | 101 | 102 | org.aspectj 103 | aspectjweaver 104 | ${aspectj.version} 105 | 106 | 107 | 108 | 109 | org.apache.maven.plugins 110 | maven-compiler-plugin 111 | 3.1 112 | 113 | javac-with-errorprone 114 | true 115 | utf-8 116 | 1.8 117 | 1.8 118 | 119 | 120 | 121 | org.codehaus.plexus 122 | plexus-compiler-javac-errorprone 123 | 2.5 124 | 125 | 126 | 127 | 128 | 129 | 130 | src/main/resources 131 | 132 | 133 | src/test/resources 134 | 135 | 136 | src/main/java 137 | 138 | **/*.java 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | io.qameta.allure 148 | allure-maven 149 | 2.8 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /src/main/java/selenium/appDomain/AppDomain.java: -------------------------------------------------------------------------------- 1 | package selenium.appDomain; 2 | 3 | import org.apache.commons.lang3.builder.ToStringBuilder; 4 | 5 | import java.util.Locale; 6 | 7 | public enum AppDomain { 8 | 9 | DE("de", 17, new Locale("de")), 10 | UK("uk", 43, new Locale("en")), 11 | FR("fr", 18, new Locale("fr")), 12 | NL("nl", 35, new Locale("nl")), 13 | BE("be", 36, new Locale("nl", "BE")), 14 | BEFR("befr", 37, new Locale("fr", "BE")), 15 | COM("com", 38, new Locale("en")), 16 | AT("at", 39, new Locale("de", "AT")), 17 | CH("ch", 40, new Locale("de", "CH")), 18 | CHFR("chfr", 41, new Locale("fr", "CH")), 19 | IT("it", 44, new Locale("it")), 20 | PL("pl", 45, new Locale("pl")), 21 | DEV("dev", 17, new Locale("dev")); 22 | 23 | 24 | private final String countryCode; 25 | private final Locale locale; 26 | private final int appDomainId; 27 | 28 | 29 | AppDomain(String countyCode, int appDomainId, Locale locale) { 30 | 31 | this.appDomainId = appDomainId; 32 | this.countryCode = countyCode; 33 | this.locale = locale; 34 | } 35 | 36 | public String getCountryCode() { 37 | return countryCode; 38 | } 39 | 40 | public Locale getLocale() { 41 | return locale; 42 | } 43 | 44 | public static AppDomain fromCountryCode(final String countryCode) { 45 | for (final AppDomain tld : AppDomain.values()) { 46 | if (tld.getCountryCode().equalsIgnoreCase(countryCode)) { 47 | return tld; 48 | } 49 | } 50 | 51 | switch (countryCode) { 52 | 53 | case "co.uk": 54 | case "gb": 55 | return UK; 56 | 57 | default: 58 | throw new IllegalArgumentException("No constant with countryCode" + countryCode + "found"); 59 | } 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return new ToStringBuilder(this) 65 | .append("countryCode", countryCode) 66 | .append("locale", locale) 67 | .append("appDomainID", appDomainId) 68 | .toString(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/selenium/config/DomainConfiguration.java: -------------------------------------------------------------------------------- 1 | package selenium.config; 2 | 3 | import selenium.appDomain.AppDomain; 4 | import com.google.common.base.Preconditions; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.core.env.Environment; 9 | 10 | @Configuration 11 | public class DomainConfiguration { 12 | 13 | public static final AppDomain APP_DOMAIN = getAppDomain(); 14 | 15 | @Autowired 16 | private Environment env; 17 | 18 | private static AppDomain getAppDomain() { 19 | final String countryCode = System.getProperty("country"); 20 | Preconditions.checkNotNull(countryCode, "\"country\" system property missing"); 21 | return AppDomain.fromCountryCode(countryCode); 22 | } 23 | 24 | @Bean(name = "appUrl") 25 | public String appUrl() { 26 | return env.getProperty("appUrl." + APP_DOMAIN.getCountryCode()); 27 | } 28 | 29 | @Bean(name = "browser") 30 | public String browser() { 31 | return env.getProperty("browser"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/selenium/driver/Driver.java: -------------------------------------------------------------------------------- 1 | package selenium.driver; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.PageFactory; 6 | import org.openqa.selenium.support.ui.ExpectedConditions; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | public class Driver { 10 | 11 | WebDriver driver; 12 | 13 | public Driver(WebDriver driver) { 14 | 15 | PageFactory.initElements(driver, this); 16 | this.driver = driver; 17 | } 18 | 19 | private static ThreadLocal webDriver = new ThreadLocal<>(); 20 | 21 | public static WebDriver getDriver() { 22 | 23 | return webDriver.get(); 24 | } 25 | 26 | public static void setWebDriver(WebDriver driver) { 27 | 28 | webDriver.set(driver); 29 | } 30 | 31 | protected void waitForElement(WebElement element) { 32 | 33 | WebDriverWait wait = new WebDriverWait(driver, 15); 34 | WebElement target = wait.until(ExpectedConditions.visibilityOf(element)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/selenium/driver/DriverManager.java: -------------------------------------------------------------------------------- 1 | package selenium.driver; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.chrome.ChromeDriver; 5 | import org.openqa.selenium.chrome.ChromeOptions; 6 | import org.openqa.selenium.firefox.FirefoxDriver; 7 | import org.openqa.selenium.firefox.FirefoxOptions; 8 | import org.openqa.selenium.remote.DesiredCapabilities; 9 | import org.openqa.selenium.remote.RemoteWebDriver; 10 | 11 | import java.net.MalformedURLException; 12 | import java.net.URL; 13 | 14 | public class DriverManager { 15 | 16 | private static final String HEADLESS = "headless"; 17 | public static WebDriver createInstance(String browserName, String appUrl, String methodName) throws MalformedURLException { 18 | final String browserMode = System.getProperty("mode"); 19 | WebDriver driver = null; 20 | if(browserName.toLowerCase().contains("firefox")) { 21 | System.setProperty("webdriver.gecko.driver", "driver/osx/geckodriver"); 22 | if(browserMode !=null && browserMode.equals(HEADLESS)){ 23 | FirefoxOptions firefoxOptions = new FirefoxOptions(); 24 | firefoxOptions.addArguments("--headless"); 25 | driver = new FirefoxDriver(firefoxOptions); 26 | }else { 27 | driver = new FirefoxDriver(); 28 | } 29 | 30 | } 31 | if(browserName.toLowerCase().contains("chrome")) { 32 | System.setProperty("webdriver.chrome.driver", "driver/osx/chromedriver"); 33 | if(browserMode !=null && browserMode.equals(HEADLESS)){ 34 | ChromeOptions chromeOptions = new ChromeOptions(); 35 | chromeOptions.addArguments("--headless"); 36 | driver = new ChromeDriver(chromeOptions); 37 | }else { 38 | driver = new ChromeDriver(); 39 | } 40 | 41 | } 42 | if(browserName.toLowerCase().contains("zalenium")) { 43 | DesiredCapabilities cap = DesiredCapabilities.chrome(); 44 | cap.setCapability("name", methodName); 45 | driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), cap); 46 | } 47 | driver.navigate().to(appUrl); 48 | return driver; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/selenium/localization/LocaleText.java: -------------------------------------------------------------------------------- 1 | package selenium.localization; 2 | 3 | import selenium.config.DomainConfiguration; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.nio.charset.Charset; 7 | import java.util.Locale; 8 | import java.util.ResourceBundle; 9 | 10 | @Component 11 | public class LocaleText { 12 | 13 | private static final Locale LOCALE = DomainConfiguration.APP_DOMAIN.getLocale(); 14 | 15 | 16 | public static String get(final String key) { 17 | 18 | /************************************************************************* 19 | ** The resource bundle by default uses the ISO 8859-1 character encoding 20 | ** Making it compatible with the commonly used UTF-8 format 21 | *************************************************************************/ 22 | 23 | final String value = ResourceBundle.getBundle("locale", LOCALE).getString(key); 24 | final byte[] utf8Bytes = value.getBytes(Charset.forName("ISO-8859-1")); 25 | return new String(utf8Bytes, Charset.forName("UTF-8")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/selenium/pageobject/HomePage.java: -------------------------------------------------------------------------------- 1 | package selenium.pageobject; 2 | 3 | import org.openqa.selenium.WebElement; 4 | import org.openqa.selenium.support.FindBy; 5 | import selenium.driver.Driver; 6 | import org.openqa.selenium.WebDriver; 7 | 8 | public class HomePage extends Driver { 9 | 10 | public HomePage(WebDriver driver) { 11 | 12 | super(driver); 13 | } 14 | 15 | @FindBy(css = "a[href='/login']") 16 | private WebElement loginPageLink; 17 | 18 | public String getPageTitle() { 19 | return getDriver().getTitle(); 20 | } 21 | 22 | public void goToLoginPage() { 23 | 24 | waitForElement(loginPageLink); 25 | loginPageLink.click(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/selenium/pageobject/LoginPage.java: -------------------------------------------------------------------------------- 1 | package selenium.pageobject; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import selenium.driver.Driver; 7 | 8 | public class LoginPage extends Driver { 9 | 10 | public LoginPage(WebDriver driver) { 11 | super(driver); 12 | } 13 | 14 | @FindBy(id = "username") 15 | private WebElement usernameField; 16 | 17 | @FindBy(id = "password") 18 | private WebElement passwordField; 19 | 20 | @FindBy(css = "button[type='submit']") 21 | private WebElement submitButton; 22 | 23 | public void login(String username, String password) { 24 | usernameField.sendKeys(username); 25 | passwordField.sendKeys(password); 26 | submitButton.click(); 27 | } 28 | 29 | public String getCurrentUrl() { 30 | return getDriver().getCurrentUrl(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/resources/locale_en.properties: -------------------------------------------------------------------------------- 1 | homePage.title=The Internet -------------------------------------------------------------------------------- /src/test/java/selenium/Application.java: -------------------------------------------------------------------------------- 1 | package selenium; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(final String[] args) throws Exception { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/selenium/context/Base.java: -------------------------------------------------------------------------------- 1 | package selenium.context; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.boot.test.SpringApplicationConfiguration; 7 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; 8 | import org.testng.annotations.Listeners; 9 | import selenium.Application; 10 | import selenium.listeners.WebDriverListener; 11 | import selenium.testdata.file.FileLoaderService; 12 | 13 | @Listeners(WebDriverListener.class) 14 | @SpringApplicationConfiguration(Application.class) 15 | public abstract class Base extends AbstractTestNGSpringContextTests { 16 | 17 | @Autowired 18 | @Qualifier("appUrl") 19 | protected String appUrl; 20 | 21 | @Autowired 22 | @Qualifier("browser") 23 | protected String browser; 24 | 25 | @Autowired 26 | protected FileLoaderService fileLoaderService; 27 | 28 | @Value("${spring.profiles.active}") 29 | String profile; 30 | 31 | public String getProfile() { 32 | 33 | return profile; 34 | } 35 | 36 | public String getAppUrl() { 37 | return appUrl; 38 | } 39 | 40 | public String getBrowser() { 41 | return browser; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/selenium/listeners/WebDriverListener.java: -------------------------------------------------------------------------------- 1 | package selenium.listeners; 2 | 3 | import selenium.driver.Driver; 4 | import selenium.driver.DriverManager; 5 | import io.qameta.allure.Attachment; 6 | import org.apache.commons.io.FileUtils; 7 | import org.apache.commons.io.IOUtils; 8 | import org.openqa.selenium.OutputType; 9 | import org.openqa.selenium.TakesScreenshot; 10 | import org.openqa.selenium.WebDriver; 11 | import org.testng.IInvokedMethod; 12 | import org.testng.IInvokedMethodListener; 13 | import org.testng.ITestResult; 14 | import selenium.context.Base; 15 | 16 | import java.io.File; 17 | import java.io.FileInputStream; 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.net.MalformedURLException; 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | 24 | public class WebDriverListener implements IInvokedMethodListener { 25 | 26 | @Override 27 | public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { 28 | 29 | if(method.isTestMethod()) { 30 | 31 | String browserName = ((Base)method.getTestMethod().getInstance()).getBrowser(); 32 | try { 33 | WebDriver driver = DriverManager.createInstance(browserName, ((Base)method.getTestMethod().getInstance()).getAppUrl(), method.getTestMethod().getMethodName()); 34 | System.out.println("Initializing webdriver session --> Thread ID: " + Thread.currentThread().getId()); 35 | System.out.println("Running test --> " + method.getTestMethod().getMethodName()); 36 | Driver.setWebDriver(driver); 37 | } catch (MalformedURLException e) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public void afterInvocation(IInvokedMethod method, ITestResult testResult) { 45 | 46 | if(method.isTestMethod()) { 47 | 48 | WebDriver driver = Driver.getDriver(); 49 | if(driver != null) { 50 | 51 | try { 52 | takeScreenshotOnFailure(testResult); 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | System.out.println("Closing webdriver session: " + Thread.currentThread().getId()); 57 | driver.quit(); 58 | } 59 | } 60 | } 61 | 62 | public void takeScreenshotOnFailure(ITestResult testResult) throws IOException { 63 | 64 | if(testResult.getStatus() == ITestResult.FAILURE) { 65 | 66 | File screenShot = ((TakesScreenshot) Driver.getDriver()).getScreenshotAs(OutputType.FILE); 67 | File destination = new File("target/failure-screenshots/" + testResult.getName() + "-" 68 | + new SimpleDateFormat("dd-MM-yyyy HH-mm-ss").format(new Date()) + ".png"); 69 | FileUtils.copyFile(screenShot, destination); 70 | 71 | InputStream screenShotStream = new FileInputStream(destination); 72 | byte[] screen = IOUtils.toByteArray(screenShotStream); 73 | 74 | saveScreenshot(screen); 75 | } 76 | } 77 | 78 | @Attachment(value = "Screenshot of the failure", type = "image/png") 79 | public byte[] saveScreenshot(byte[] screenShot) { 80 | 81 | return screenShot; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/selenium/testdata/file/FileLoaderService.java: -------------------------------------------------------------------------------- 1 | package selenium.testdata.file; 2 | 3 | 4 | 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import selenium.config.DomainConfiguration; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.core.io.Resource; 9 | import org.springframework.core.io.ResourceLoader; 10 | import org.springframework.stereotype.Service; 11 | import selenium.testdata.properties.User; 12 | 13 | import java.io.IOException; 14 | 15 | @Service 16 | public class FileLoaderService { 17 | 18 | private static final String TEST_DATA_FOLDER = "testdata"; 19 | private static final String USER_FOLDER = "user"; 20 | 21 | private final ObjectMapper objectMapper; 22 | private final ResourceLoader resourceLoader; 23 | 24 | @Autowired 25 | public FileLoaderService(ObjectMapper objectMapper, ResourceLoader resourceLoader) { 26 | this.objectMapper = objectMapper; 27 | this.resourceLoader = resourceLoader; 28 | } 29 | 30 | public User getUser(final String fileNameWithoutCountryCodeAndExtention) { 31 | return load(USER_FOLDER + "/" + fileNameWithoutCountryCodeAndExtention + "_" 32 | + DomainConfiguration.APP_DOMAIN.getCountryCode() + ".json", User.class); 33 | } 34 | 35 | private T load(final String filename, final Class type) { 36 | try{ 37 | final Resource resource = resourceLoader.getResource(getFullPath(filename)); 38 | return objectMapper.readValue(resource.getInputStream(), type); 39 | }catch (final IOException e) { 40 | throw new RuntimeException("Failed to load test data", e); 41 | } 42 | } 43 | 44 | private String getFullPath(final String filename) { 45 | return TEST_DATA_FOLDER + "/" + filename; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/selenium/testdata/properties/User.java: -------------------------------------------------------------------------------- 1 | package selenium.testdata.properties; 2 | 3 | import org.apache.commons.lang3.builder.ToStringBuilder; 4 | 5 | public class User { 6 | private String email; 7 | private String username; 8 | private String password; 9 | private String gender; 10 | private String firstname; 11 | private String lastname; 12 | private String address; 13 | private String zip; 14 | private String city; 15 | private String cardtype; 16 | private String cardnumber; 17 | private String expiremonth; 18 | private String expireyear; 19 | private String ccvnumber; 20 | private String country; 21 | private String telephone; 22 | 23 | public String getPassword() { 24 | return password; 25 | } 26 | 27 | public void setPassword(final String password) { 28 | this.password = password; 29 | } 30 | 31 | public String getEmail() { 32 | return email; 33 | } 34 | 35 | public void setEmail(final String email) { 36 | this.email = email; 37 | } 38 | 39 | public String getUsername() {return username; } 40 | 41 | public void setUsername(final String username) { this.username = username; } 42 | 43 | public String getGender() { 44 | return gender; 45 | } 46 | 47 | public void setGender(final String gender) { 48 | this.gender = gender; 49 | } 50 | 51 | public String getFirstname() { 52 | return firstname; 53 | } 54 | 55 | public void setFirstname(final String firstname) { 56 | this.firstname = firstname; 57 | } 58 | 59 | public String getLastname() { 60 | return lastname; 61 | } 62 | 63 | public void setLastname(final String lastname) { 64 | this.lastname = lastname; 65 | } 66 | 67 | public String getAddress() { 68 | return address; 69 | } 70 | 71 | public void setAddress(String address) { 72 | this.address = address; 73 | } 74 | 75 | public String getZip() { 76 | return zip; 77 | } 78 | 79 | public void setZip(String zip) { 80 | this.zip = zip; 81 | } 82 | 83 | public String getCity() { 84 | return city; 85 | } 86 | 87 | public void setCity(String city) { 88 | this.city = city; 89 | } 90 | 91 | public String getCardtype() { 92 | return cardtype; 93 | } 94 | 95 | public void setCardtype(String cardtype) { 96 | this.cardtype = cardtype; 97 | } 98 | 99 | public String getCardnumber() { 100 | return cardnumber; 101 | } 102 | 103 | public void setCardnumber(String cardnumber) { 104 | this.cardnumber = cardnumber; 105 | } 106 | 107 | public String getExpiremonth() { 108 | return expiremonth; 109 | } 110 | 111 | public void setExpiremonth(String expiremonth) { 112 | this.expiremonth = expiremonth; 113 | } 114 | 115 | public String getExpireyear() { 116 | return expireyear; 117 | } 118 | 119 | public void setExpireyear(String expireyear) { 120 | this.expireyear = expireyear; 121 | } 122 | 123 | public String getCcvnumber() { 124 | return ccvnumber; 125 | } 126 | 127 | public void setCcvnumber(String ccvnumber) { 128 | this.ccvnumber = ccvnumber; 129 | } 130 | 131 | public String getCountry() { 132 | return country; 133 | } 134 | 135 | public void setCountry(String country) { 136 | this.country = country; 137 | } 138 | 139 | public String getTelephone() { 140 | return telephone; 141 | } 142 | 143 | public void setTelephone(String telephone) { 144 | this.telephone = telephone; 145 | } 146 | 147 | @Override 148 | public String toString() { 149 | return new ToStringBuilder(this) 150 | .append("email", email) 151 | .append("password", password) 152 | .build(); 153 | } 154 | } 155 | 156 | -------------------------------------------------------------------------------- /src/test/java/selenium/tests/SimpleTestExamples.java: -------------------------------------------------------------------------------- 1 | package selenium.tests; 2 | 3 | import selenium.driver.Driver; 4 | import io.qameta.allure.Description; 5 | import selenium.localization.LocaleText; 6 | import org.testng.annotations.Test; 7 | import selenium.pageobject.HomePage; 8 | import selenium.context.Base; 9 | import selenium.pageobject.LoginPage; 10 | import selenium.testdata.properties.User; 11 | 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.equalTo; 14 | 15 | public class SimpleTestExamples extends Base { 16 | 17 | @Test(description = "Page title test") 18 | @Description("Checks if the page title is correct") 19 | public void pageTitleTest() { 20 | 21 | HomePage homePage = new HomePage(Driver.getDriver()); 22 | assertThat(homePage.getPageTitle(), equalTo(LocaleText.get("homePage.title"))); 23 | } 24 | 25 | @Test(description = "Authentication test") 26 | @Description("Checks if user is able to log in") 27 | public void loginTest() { 28 | 29 | User user = fileLoaderService.getUser("user"); 30 | 31 | HomePage homePage = new HomePage(Driver.getDriver()); 32 | homePage.goToLoginPage(); 33 | 34 | LoginPage loginPage = new LoginPage(Driver.getDriver()); 35 | loginPage.login(user.getUsername(), user.getPassword()); 36 | 37 | assertThat(loginPage.getCurrentUrl(), equalTo(appUrl + "secure")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/resources/application-release.properties: -------------------------------------------------------------------------------- 1 | appUrl.com=http://the-internet.herokuapp.com/ -------------------------------------------------------------------------------- /src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | appUrl.com=http://the-internet.herokuapp.com/ -------------------------------------------------------------------------------- /src/test/resources/testdata/user/user_com.json: -------------------------------------------------------------------------------- 1 | { 2 | "gender": "MALE", 3 | "username": "tomsmith", 4 | "firstname": "Selenium", 5 | "lastname": "TestUser", 6 | "telephone": "0123456789", 7 | "email": "some@email.com", 8 | "password": "SuperSecretPassword!", 9 | "address": "Am Treptower Park 28", 10 | "zip": "12435", 11 | "city": "Berlin", 12 | "cardtype": "VISA", 13 | "cardnumber": "4111 1111 1111 1111", 14 | "expiremonth": "08", 15 | "expireyear": "2018", 16 | "ccvnumber": "737" 17 | } -------------------------------------------------------------------------------- /testng.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------