├── .gitignore
├── README.md
├── pom.xml
├── regressions_testng.xml
├── src
├── main
│ └── java
│ │ ├── helper
│ │ └── Browser.java
│ │ └── pages
│ │ ├── HomePage.java
│ │ ├── SearchResultPage.java
│ │ └── shared
│ │ ├── Element.java
│ │ ├── HeaderSection.java
│ │ └── Page.java
└── test
│ └── java
│ ├── helper
│ └── TestHelper.java
│ └── tests
│ └── HomePageTests.java
└── test-automation-java.iml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.ear
17 | *.zip
18 | *.tar.gz
19 | *.rar
20 |
21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
22 | hs_err_pid*
23 |
24 | .idea/
25 | target/
26 | bbc-tests.iml
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Test Automation with Java
2 | Web test automation example project using IntelliJ IDEA Community, Java, Maven, TestNG, Selenium 3, Appium and Page Object Model (POM)
3 |
4 | ## Test Subject
5 | I've picked [www.bbc.co.uk](www.bbc.co.uk) as a test subject for no particular reason.
6 | It's is a large site and does have variety of features that we can play around with.
7 |
8 | ## Libraries and Frameworks
9 | Version for some of these can be found in the [POM](https://github.com/opantsjoha/test-automation-java/blob/master/pom.xml) file.
10 | * Selenium - Web automation
11 | * Appium - Mobile automation
12 | * Maven - Build and package management
13 | * TestNG - Test execution and Reporting
14 |
15 | ## Tools
16 | Using [IntelliJ IDEA Community](https://www.jetbrains.com/idea/) version.
17 | I've previously used Eclipse and found it to be a little bit slower and not as intuitive, you're free to try both and decide for yourself. Also there are a lot of comparison articles out there already.
18 |
19 | ## Programming Language
20 | I'm using [Java SE](http://www.oracle.com/technetwork/java/javase/downloads/index.html) version jdk1.8.0_111 and it works very well.
21 | There are a couple of good reasons to use Java:
22 | * It's been around for a while so there are a lot of solutions for most problems and if not then somebody from the community will be able to suggest an answer quickly.
23 | * It's OpenSource - there are large, well supported communities sharing free libraries.
24 | * Because of the above two points it's possible to automate (testing) checking for iOS (Web and Native), Android (Web and Native) and Web platforms.
25 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | qa.example.java
6 | test-automation-java
7 | 1.0-SNAPSHOT
8 |
9 |
10 |
11 | org.apache.maven.plugins
12 | maven-compiler-plugin
13 | 3.6.1
14 |
15 | 1.8
16 | 1.8
17 |
18 |
19 |
20 |
21 | jar
22 |
23 | test-automation-tests
24 | http://maven.apache.org
25 |
26 |
27 | UTF-8
28 |
29 |
30 |
31 |
32 | Regression
33 |
34 |
35 |
36 | org.apache.maven.plugins
37 | maven-surefire-plugin
38 | 2.20
39 |
40 |
41 | regressions_testng.xml
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.seleniumhq.selenium
53 | selenium-support
54 | 3.4.0
55 |
56 |
57 | net.sourceforge.htmlcleaner
58 | htmlcleaner
59 | 2.21
60 |
61 |
62 | net.sourceforge.jexcelapi
63 | jxl
64 | 2.6.12
65 |
66 |
67 | org.apache.logging.log4j
68 | log4j-core
69 | 2.8.2
70 |
71 |
72 | io.appium
73 | java-client
74 | 4.1.2
75 |
76 |
77 | org.seleniumhq.selenium
78 | selenium-java
79 | 3.4.0
80 |
81 |
82 | org.testng
83 | testng
84 | 6.11
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/regressions_testng.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/main/java/helper/Browser.java:
--------------------------------------------------------------------------------
1 | package helper;
2 |
3 | import io.appium.java_client.remote.MobileCapabilityType;
4 | import org.openqa.selenium.WebDriver;
5 | import org.openqa.selenium.chrome.ChromeOptions;
6 | import org.openqa.selenium.firefox.FirefoxDriver;
7 | import org.openqa.selenium.firefox.FirefoxProfile;
8 | import org.openqa.selenium.remote.DesiredCapabilities;
9 | import org.openqa.selenium.remote.RemoteWebDriver;
10 | import pages.HomePage;
11 |
12 | import java.net.MalformedURLException;
13 | import java.net.URL;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | /**
17 | * Created by opantsjoha on 02/07/2017.
18 | */
19 | public class Browser {
20 |
21 |
22 | public Browser(String browserName, String baseUrl) {
23 | setBrowser(browserName);
24 | setBaseUrl(baseUrl);
25 | Initialise(getBrowser());
26 | }
27 |
28 | private void Initialise(String browser) {
29 | capabilities = new DesiredCapabilities();
30 | seleniumFolderPath = System.getProperty("user.home") + "/Documents/umservices/selenium3/";
31 |
32 | switch (browser) {
33 | case "Chrome":
34 | ChromeOptions chrome_options = new ChromeOptions();
35 | chrome_options.addArguments("--disable-geolocation");
36 | chrome_options.addArguments("--incognito");
37 | System.setProperty("webdriver.chrome.driver", seleniumFolderPath + "chromedriver");
38 | capabilities.setBrowserName("chrome");
39 | capabilities.setCapability(ChromeOptions.CAPABILITY, chrome_options);
40 | // _driver = new ChromeDriver(capabilities);
41 | break;
42 | case "Safari":
43 | capabilities.setBrowserName("safari");
44 |
45 | // _driver = new SafariDriver();
46 | break;
47 | case "Firefox":
48 | FirefoxProfile ff_profile = new FirefoxProfile();
49 | ff_profile.setPreference("geo.prompt.testing", true);
50 | ff_profile.setPreference("geo.prompt.testing.allow", true);
51 | System.setProperty("webdriver.gecko.driver", seleniumFolderPath + "geckodriver");
52 | capabilities.setBrowserName("firefox");
53 | capabilities.setCapability(FirefoxDriver.PROFILE, ff_profile);
54 |
55 | // _driver = new FirefoxDriver(capabilities);
56 | break;
57 | case "InternetExplorer":
58 | System.setProperty("webdriver.ie.driver", seleniumFolderPath + "IEDriverServer.exe");
59 | capabilities.setBrowserName("internet explorer");
60 | break;
61 | case "Edge":
62 | System.setProperty("webdriver.edge.driver", seleniumFolderPath + "MicrosoftWebDriver.exe");
63 | capabilities.setBrowserName("edge");
64 | break;
65 | case "Safari_iOS":
66 | capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone 5");
67 | capabilities.setCapability(MobileCapabilityType.APPIUM_VERSION, "1.6.5");
68 | capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
69 | capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "XCUITest");
70 | capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
71 | break;
72 | default:
73 | System.out.println("Invalid browser passed in: " + browser);
74 | break;
75 | }
76 |
77 | try {
78 | _driver = new RemoteWebDriver(new URL("http://0.0.0.0:4444/wd/hub"), capabilities);
79 | } catch (MalformedURLException e) {
80 | e.printStackTrace();
81 | }
82 | _driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
83 | }
84 |
85 | public void navigateTo(String url) {
86 | _driver.get(url);
87 | }
88 |
89 | public void navigateToBaseUrl() {
90 | _driver.get(getBaseUrl());
91 | }
92 |
93 | public String getBrowser() {
94 | return this.browserName;
95 | }
96 |
97 | private void setBrowser(String browserName) {
98 | this.browserName = browserName;
99 | }
100 |
101 | private void setBaseUrl(String baseUrl) {
102 | this.baseUrl = baseUrl;
103 | }
104 |
105 | public String getBaseUrl() {
106 | return this.baseUrl;
107 | }
108 |
109 | public HomePage HomePage() {
110 | if (homePage == null) {
111 | homePage = new HomePage(this);
112 | }
113 | return homePage;
114 | }
115 |
116 | // Public properties
117 | public WebDriver _driver;
118 |
119 | // Private properties
120 | private DesiredCapabilities capabilities;
121 | private String browserName;
122 | private String baseUrl;
123 | private String seleniumFolderPath;
124 | private HomePage homePage;
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/pages/HomePage.java:
--------------------------------------------------------------------------------
1 | package pages;
2 |
3 | import helper.Browser;
4 | import pages.shared.Page;
5 |
6 | /**
7 | * Created by opantsjoha on 02/07/2017.
8 | */
9 | public class HomePage extends Page {
10 |
11 | public HomePage(Browser browser) {
12 | super(browser);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/pages/SearchResultPage.java:
--------------------------------------------------------------------------------
1 | package pages;
2 |
3 | import helper.Browser;
4 | import org.openqa.selenium.WebElement;
5 | import org.openqa.selenium.support.FindBy;
6 | import pages.shared.Page;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Created by opantsjoha on 02/07/2017.
12 | */
13 | public class SearchResultPage extends Page {
14 | public SearchResultPage(Browser browser) {
15 | super(browser);
16 | }
17 |
18 | // List of all search results
19 | @FindBy(id = "search-content")
20 | private List searchResultList;
21 |
22 | public int getSearchResultSize() {
23 | return searchResultList.size();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/pages/shared/Element.java:
--------------------------------------------------------------------------------
1 | package pages.shared;
2 |
3 | import helper.Browser;
4 | import org.openqa.selenium.JavascriptExecutor;
5 | import org.openqa.selenium.WebDriver;
6 | import org.openqa.selenium.WebElement;
7 | import org.openqa.selenium.support.PageFactory;
8 | import org.openqa.selenium.support.ui.WebDriverWait;
9 |
10 | /**
11 | * Created by opantsjoha on 02/07/2017.
12 | */
13 | public class Element {
14 |
15 | public Element(Browser browser) {
16 | this.browser = browser;
17 | driver = browser._driver;
18 | PageFactory.initElements(driver, this);
19 | }
20 |
21 | // Draws a red border around the found element. Does not set it back anyhow.
22 | public WebElement highlightElement(WebElement elem) {
23 | // draw a border around the found element
24 | if (driver instanceof JavascriptExecutor) {
25 | ((JavascriptExecutor) driver).executeScript("arguments[0].style.border='3px solid red'", elem);
26 | }
27 | return elem;
28 | }
29 |
30 | protected WebDriver driver;
31 | protected WebDriverWait wait;
32 | protected Browser browser;
33 | protected static int DURATION = 5000;
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/pages/shared/HeaderSection.java:
--------------------------------------------------------------------------------
1 | package pages.shared;
2 |
3 | import helper.Browser;
4 | import org.openqa.selenium.WebElement;
5 | import org.openqa.selenium.support.FindBy;
6 |
7 | /**
8 | * Created by opantsjoha on 02/07/2017.
9 | */
10 | public class HeaderSection extends Element {
11 |
12 | public HeaderSection(Browser browser) {
13 | super(browser);
14 | }
15 |
16 | @FindBy(id = "orb-search-q")
17 | private WebElement searchField;
18 |
19 | // This search button is actually useless - as it just opens another search box
20 | @FindBy(id = "orb-search-button")
21 | private WebElement searchButton;
22 |
23 | @FindBy(className = "se-searchbox__submit")
24 | private WebElement searchSubmitButton;
25 |
26 | public void setSearchField(String value) {
27 | searchField.sendKeys(value);
28 | }
29 |
30 | public void clickOnSearchButton() {
31 | // this element only appears when something is input into search field.
32 | searchSubmitButton.click();
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/pages/shared/Page.java:
--------------------------------------------------------------------------------
1 | package pages.shared;
2 |
3 | import helper.Browser;
4 |
5 | /**
6 | * Created by opantsjoha on 02/07/2017.
7 | */
8 | public class Page extends Element {
9 | public Page(Browser browser) {
10 | super(browser);
11 | }
12 |
13 | // Create HeaderSection object when called.
14 | public HeaderSection HeaderSection(){
15 | if(headerSection == null){
16 | headerSection = new HeaderSection(browser);
17 | }
18 | return headerSection;
19 | }
20 |
21 | private HeaderSection headerSection;
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/helper/TestHelper.java:
--------------------------------------------------------------------------------
1 | package helper;
2 |
3 | /**
4 | * Created by opantsjoha on 02/07/2017.
5 | */
6 | public class TestHelper {
7 | }
8 |
--------------------------------------------------------------------------------
/src/test/java/tests/HomePageTests.java:
--------------------------------------------------------------------------------
1 | package tests;
2 |
3 | import helper.Browser;
4 | import helper.TestHelper;
5 | import org.testng.annotations.*;
6 |
7 | /**
8 | * Created by opantsjoha on 02/07/2017.
9 | */
10 | public class HomePageTests extends TestHelper {
11 |
12 | Browser browser;
13 |
14 | @Parameters({"browserName", "baseUrl"})
15 | @BeforeClass(groups = {"web"})
16 | public void setUp(String browserName, String baseUrl) {
17 | browser = new Browser(browserName, baseUrl);
18 | browser.navigateToBaseUrl();
19 | }
20 |
21 | @Test(groups = {"web"})
22 | public void searchTest() throws InterruptedException {
23 | browser.HomePage().HeaderSection().setSearchField("Cooking");
24 | browser.HomePage().HeaderSection().clickOnSearchButton();
25 | // todo: add assert
26 | }
27 |
28 | @AfterClass(groups = {"web"})
29 | public void tearDown() {
30 | browser._driver.quit();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/test-automation-java.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------