├── README.md
├── page-objects.iml
├── pom.xml
└── src
└── test
└── java
└── com
└── example
├── pageobjects
├── BaseObjectPage.java
├── GitHubHomePage.java
├── GitHubJoinPage.java
└── GitHubLoginPage.java
├── setup
├── CustomLoadableComponent.java
├── PageLoadHelper.java
├── SeleniumBaseTest.java
└── SeleniumDriver.java
└── test
├── GitHubJoinTest.java
└── GitHubLoginTest.java
/README.md:
--------------------------------------------------------------------------------
1 | Page Object Pattern with Loadable Component
2 | ==========================================
3 | This project is an example of building a test automation framework using WebDriver, Java, TestNG, Maven with InteliJ (or Eclipse).
4 |
5 | There are a several of key concepts demonstrated in this project:
6 |
7 | - Page Objects Pattern
8 | - Abstracting the test setup into a SeleniumBaseTest class
9 | - Implementing Custom LoadableComponent
10 | - Organized Selenium WebDriver setup
11 | - Using TestNG and Maven to run the tests
12 |
13 | Please contact me if you have any questions or suggestions.
14 |
--------------------------------------------------------------------------------
/page-objects.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 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | page-objects-example
7 | page-objects-example
8 | 1.0
9 |
10 |
11 | UTF-8
12 |
13 |
14 |
15 |
16 | org.seleniumhq.selenium
17 | selenium-java
18 | 2.53.0
19 |
20 |
21 | org.testng
22 | testng
23 | 6.9.10
24 | test
25 |
26 |
27 | org.seleniumhq.selenium
28 | selenium-server
29 | 2.53.0
30 |
31 |
32 | org.seleniumhq.selenium
33 | selenium-firefox-driver
34 | 2.53.0
35 |
36 |
37 |
38 |
39 |
40 | org.apache.maven.plugins
41 | maven-compiler-plugin
42 |
43 | 1.6
44 | 1.6
45 |
46 |
47 |
48 |
49 | org.apache.maven.plugins
50 | maven-resources-plugin
51 | 2.6
52 |
53 |
54 | UTF-8
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/test/java/com/example/pageobjects/BaseObjectPage.java:
--------------------------------------------------------------------------------
1 | package com.example.pageobjects;
2 |
3 | import static com.example.setup.SeleniumDriver.getDriver;
4 |
5 | import com.example.setup.CustomLoadableComponent;
6 | import org.openqa.selenium.By;
7 | import org.openqa.selenium.NoSuchElementException;
8 | import org.openqa.selenium.WebDriver;
9 | import org.openqa.selenium.WebElement;
10 | import org.openqa.selenium.support.PageFactory;
11 |
12 |
13 | /**
14 | * Created by Sargis on 4/3/16.
15 | */
16 |
17 | public abstract class BaseObjectPage> extends CustomLoadableComponent {
18 | private WebDriver driver;
19 | private static final String BASE_URL = "https://github.com";
20 |
21 | public BaseObjectPage(WebDriver driver) {
22 | this.driver = driver;
23 | }
24 |
25 | public T openPage(Class clazz) {
26 | T page = PageFactory.initElements(getDriver(), clazz);
27 | getDriver().get(BASE_URL + getPageUrl());
28 | return page.get();
29 | }
30 |
31 | public abstract String getPageUrl();
32 |
33 | public void open(String url) {
34 | driver.get(url);
35 | }
36 |
37 | public WebElement find(By locator) {
38 | return driver.findElement(locator);
39 | }
40 |
41 | public void type(By inputLocator, String text) {
42 | find(inputLocator).sendKeys(text);
43 | }
44 |
45 | public void type(WebElement input, String text) {
46 | input.sendKeys(text);
47 | }
48 |
49 | public void click(By locator) {
50 | find(locator).click();
51 | }
52 |
53 | public void click(WebElement element) {
54 | element.click();
55 | }
56 |
57 | public boolean isElementDisplayed(WebElement element) {
58 | try {
59 | return element.isDisplayed();
60 | } catch (NoSuchElementException e) {
61 | return false;
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/test/java/com/example/pageobjects/GitHubHomePage.java:
--------------------------------------------------------------------------------
1 | package com.example.pageobjects;
2 |
3 | import com.example.setup.PageLoadHelper;
4 | import org.openqa.selenium.By;
5 |
6 | import static com.example.setup.SeleniumDriver.getDriver;
7 |
8 | /**
9 | * Page object GitHub home page.
10 | *
11 | * Created by Sargis on 4/3/16.
12 | */
13 |
14 | public class GitHubHomePage extends BaseObjectPage {
15 |
16 |
17 | public GitHubHomePage() {
18 | super(getDriver());
19 | }
20 |
21 | @Override
22 | public String getPageUrl() {
23 | return "";
24 | }
25 |
26 | public GitHubLoginPage goToLoginPage() {
27 | return new GitHubLoginPage().openPage(GitHubLoginPage.class);
28 | }
29 |
30 | public GitHubHomePage open() {
31 | return new GitHubHomePage().openPage(GitHubHomePage.class);
32 | }
33 |
34 | @Override
35 | protected void load() {
36 |
37 | }
38 |
39 | @Override
40 | protected void isLoaded() throws Error {
41 | PageLoadHelper.isLoaded().
42 | isElementIsVisible(By.cssSelector("input[name='user[login]']")).
43 | isElementIsClickable(By.cssSelector("input[name='user[login]']"));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/com/example/pageobjects/GitHubJoinPage.java:
--------------------------------------------------------------------------------
1 | package com.example.pageobjects;
2 |
3 | import com.example.setup.PageLoadHelper;
4 | import org.openqa.selenium.By;
5 | import org.openqa.selenium.WebElement;
6 | import org.openqa.selenium.support.FindBy;
7 |
8 | import static com.example.setup.SeleniumDriver.getDriver;
9 |
10 | /**
11 | * Created by sargis on 6/19/16.
12 | */
13 | public class GitHubJoinPage extends BaseObjectPage {
14 | @FindBy(id = "user_login")
15 | WebElement usernameField;
16 |
17 | @FindBy(id = "user_email")
18 | WebElement emailField;
19 |
20 | @FindBy(id = "user_password")
21 | WebElement passwordField;
22 |
23 | @FindBy(className = "flash-error")
24 | WebElement errorBox;
25 |
26 | @FindBy(id = "signup_button")
27 | WebElement joinButton;
28 |
29 |
30 | public GitHubJoinPage() {
31 | super(getDriver());
32 | }
33 |
34 | public void registerNewUser(String username, String email, String password) {
35 | type(usernameField, username);
36 | type(emailField, email);
37 | type(passwordField, password);
38 | click(joinButton);
39 | }
40 |
41 | public boolean isLoginError() {
42 | return isElementDisplayed(errorBox);
43 | }
44 |
45 | @Override
46 | public String getPageUrl() {
47 | return "/join";
48 | }
49 |
50 | @Override
51 | protected void load() {
52 |
53 | }
54 |
55 |
56 | @Override
57 | protected void isLoaded() throws Error {
58 | PageLoadHelper.isLoaded().
59 | isElementIsVisible(By.cssSelector("input[id='user_login']")).
60 | isElementIsClickable(By.cssSelector("input[id='user_login']"));
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/test/java/com/example/pageobjects/GitHubLoginPage.java:
--------------------------------------------------------------------------------
1 | package com.example.pageobjects;
2 |
3 | import com.example.setup.PageLoadHelper;
4 | import org.openqa.selenium.By;
5 | import org.openqa.selenium.WebElement;
6 | import org.openqa.selenium.support.FindBy;
7 |
8 | import static com.example.setup.SeleniumDriver.getDriver;
9 |
10 | /**
11 | * Page object GitHub login page
12 | *
13 | * Created by Sargis on 4/3/16.
14 | */
15 | public class GitHubLoginPage extends BaseObjectPage {
16 |
17 | @FindBy(id = "login_field")
18 | WebElement loginField;
19 |
20 | @FindBy(name = "password")
21 | WebElement passwordField;
22 |
23 | @FindBy(name = "commit")
24 | WebElement commitButton;
25 |
26 | @FindBy(className = "flash-error")
27 | WebElement errorBox;
28 |
29 | public GitHubLoginPage() {
30 | super(getDriver());
31 | }
32 |
33 | @Override
34 | public String getPageUrl() {
35 | return "/login";
36 | }
37 |
38 | public void login(String login, String password) {
39 | type(loginField, login);
40 | type(passwordField, password);
41 | click(commitButton);
42 | }
43 |
44 | public boolean isLoginError() {
45 | return isElementDisplayed(errorBox);
46 | }
47 |
48 | public String getErrorMessage() {
49 | return errorBox.getText();
50 | }
51 |
52 | @Override
53 | protected void load() {
54 |
55 | }
56 |
57 | @Override
58 | protected void isLoaded() throws Error {
59 | PageLoadHelper.isLoaded().
60 | isElementIsVisible(By.cssSelector("#login_field")).
61 | isElementIsClickable(By.cssSelector("#login_field"));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/com/example/setup/CustomLoadableComponent.java:
--------------------------------------------------------------------------------
1 | package com.example.setup;
2 |
3 | import org.openqa.selenium.WebDriver;
4 | import org.openqa.selenium.support.ui.ExpectedCondition;
5 | import org.openqa.selenium.support.ui.FluentWait;
6 | import org.openqa.selenium.support.ui.Wait;
7 |
8 | import java.util.concurrent.TimeUnit;
9 |
10 | import static com.example.setup.SeleniumDriver.getDriver;
11 |
12 | /**
13 | * Custom Loadable Component
14 | *
15 | * Created by sargis on 4/3/16.
16 | */
17 | public abstract class CustomLoadableComponent> {
18 | private WebDriver driver;
19 |
20 | private static final int LOAD_TIMEOUT = 30;
21 | private static final int REFRESH_RATE = 2;
22 |
23 | @SuppressWarnings("unchecked")
24 | public T get() {
25 | try {
26 | isLoaded();
27 | return (T) this;
28 | } catch (Error e) {
29 | // This is the extra line of code
30 | System.out.println("Error encountered during page load: " + e.getMessage());
31 | load();
32 | }
33 |
34 | isLoaded();
35 |
36 | return (T) this;
37 | }
38 |
39 | protected abstract void load();
40 |
41 | protected abstract void isLoaded() throws Error;
42 |
43 | protected void waitForPageToLoad(ExpectedCondition pageLoadCondition) {
44 | Wait wait = new FluentWait(getDriver())
45 | .withTimeout(LOAD_TIMEOUT, TimeUnit.SECONDS)
46 | .pollingEvery(REFRESH_RATE, TimeUnit.SECONDS);
47 |
48 | wait.until(pageLoadCondition);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/com/example/setup/PageLoadHelper.java:
--------------------------------------------------------------------------------
1 | package com.example.setup;
2 |
3 | import org.openqa.selenium.By;
4 | import org.openqa.selenium.WebDriverException;
5 | import org.openqa.selenium.support.ui.ExpectedConditions;
6 | import org.openqa.selenium.support.ui.WebDriverWait;
7 |
8 | import static com.example.setup.SeleniumDriver.getDriver;
9 |
10 | /**
11 | * PageLoadHelper
12 | *
13 | * Created by Sargis on 4/3/16.
14 | */
15 | public class PageLoadHelper {
16 | public static PageLoadHelper isLoaded() {
17 | PageLoadHelper loadHelper = new PageLoadHelper();
18 | return loadHelper;
19 | }
20 |
21 |
22 | public PageLoadHelper isElementIsClickable(By by) {
23 | try {
24 | new WebDriverWait(getDriver(), 10).until(ExpectedConditions.elementToBeClickable(by));
25 | return this;
26 | } catch (WebDriverException e) {
27 | throw new Error("Element is not clickable");
28 | }
29 | }
30 |
31 | public PageLoadHelper isElementIsVisible(By by) {
32 | try {
33 | new WebDriverWait(getDriver(), 10).until(ExpectedConditions.visibilityOfElementLocated(by));
34 | return this;
35 | } catch (WebDriverException e) {
36 | throw new Error("Element is not visible");
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/com/example/setup/SeleniumBaseTest.java:
--------------------------------------------------------------------------------
1 | package com.example.setup;
2 |
3 | import org.testng.annotations.AfterClass;
4 |
5 | import static com.example.setup.SeleniumDriver.getDriver;
6 |
7 | /**
8 | * SeleniumBaseTest
9 | *
10 | * Created by Sargis on 4/3/16.
11 | */
12 | public class SeleniumBaseTest {
13 | @AfterClass
14 | public static void tearDown() {
15 | getDriver().close();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/com/example/setup/SeleniumDriver.java:
--------------------------------------------------------------------------------
1 | package com.example.setup;
2 |
3 | import org.openqa.selenium.WebDriver;
4 | import org.openqa.selenium.firefox.FirefoxDriver;
5 |
6 | /**
7 | * Selenium driver wrapper
8 | *
9 | * Created by Sargis on 4/3/16.
10 | */
11 | public class SeleniumDriver {
12 |
13 | static WebDriver driver;
14 |
15 | public static WebDriver getDriver() {
16 | if (driver == null) {
17 | driver = new FirefoxDriver();
18 | }
19 | return driver;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/com/example/test/GitHubJoinTest.java:
--------------------------------------------------------------------------------
1 | package com.example.test;
2 |
3 | import com.example.pageobjects.GitHubJoinPage;
4 | import com.example.setup.SeleniumBaseTest;
5 | import org.testng.annotations.Test;
6 |
7 | import static org.testng.Assert.assertTrue;
8 |
9 | /**
10 | * Created by sargis on 6/19/16.
11 | */
12 | public class GitHubJoinTest extends SeleniumBaseTest {
13 | @Test
14 | public void usernameExistTest() {
15 | //navigate to login page
16 | GitHubJoinPage joinPage = new GitHubJoinPage().openPage(GitHubJoinPage.class);
17 |
18 | //try to login
19 | joinPage.registerNewUser("user", "emial@mail.com", "password");
20 | assertTrue(joinPage.isLoginError(), "Error message should be visible!");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/com/example/test/GitHubLoginTest.java:
--------------------------------------------------------------------------------
1 | package com.example.test;
2 |
3 | import static org.testng.Assert.assertEquals;
4 | import static org.testng.Assert.assertTrue;
5 |
6 | import com.example.pageobjects.GitHubHomePage;
7 | import com.example.pageobjects.GitHubLoginPage;
8 | import com.example.setup.SeleniumBaseTest;
9 | import org.testng.annotations.Test;
10 |
11 |
12 | public class GitHubLoginTest extends SeleniumBaseTest {
13 |
14 | @Test
15 | public void shouldNotLoginWithWrongCredentials() {
16 | //navigate to login page
17 | GitHubHomePage homePage = new GitHubHomePage().open();
18 | GitHubLoginPage loginPage = homePage.goToLoginPage();
19 |
20 | //try to login
21 | loginPage.login("user", "password");
22 |
23 | //assert there is an error message
24 | assertTrue(loginPage.isLoginError(), "Error message was not displayed!");
25 | assertEquals(loginPage.getErrorMessage(), "Incorrect username or password.", "Error message was incorrect!");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------