Mateusz Żur
Mateusz Żur

Reputation: 21

Am I doing correct with page object model in Selenium?

I'm trying to automate prestashop test cases by Selenium WebDriver. Am I doing it correct, especially with page object model?

This is my HomePagePOM class:

package pageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.Alert;

public class HomePagePOM {
    private static WebElement element = null;
    private static WebDriver driver = null;
    public static String correctLogin = "aaaa";

    public static void enterPage(WebDriver driver) {
        driver.get("http://website.com");
    }

    public static WebElement homeLogo(WebDriver driver) {
        element = driver.findElement(By.id("header_logo"));
        return element;
    }

    public static WebElement searchBar(WebDriver driver) {
        element = driver.findElement(By.id("search_query_top"));
        return element;
    }

    public static WebElement searchBarButton(WebDriver driver) {
        element = driver.findElement(By.name("submit_search"));
        return element;
    }

    public static WebElement contactUs(WebDriver driver) {
        element = driver.findElement(By.id("contact-link"));
        return element;
    }

    public static WebElement signIn(WebDriver driver) {
        element = driver.findElement(By.className("header_user_info"));
        return element;
    }

}

This is my LoginPagePOM class:

package pageObjects;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class LoginPagePOM {
    private static WebElement element = null;
    private static WebDriver driver = null;
    public static String correctLogin = "client";
    public static String incorrectLogin = "client_incorrect";
    public static String correctPassword = "pass_correct";
    public static String incorrectPassword = "pass_incorrect";

    public static WebElement createAccountField(WebDriver driver) {
        element = driver.findElement(By.id("email_create"));
        return element;
    }
    public static WebElement registeredEmailField(WebDriver driver) {
        element = driver.findElement(By.id("email"));
        return element;
    }
    public static WebElement registeredPasswordField(WebDriver driver) {
        element = driver.findElement(By.id("passwd"));
        return element;
    }
    public static WebElement registeredSubmitButton(WebDriver driver) {
        element = driver.findElement(By.id("SubmitLogin"));
        return element;
    }
    public static WebElement createAccountButton(WebDriver driver) {
        element = driver.findElement(By.id("SubmitCreate"));
        return element;
    }
}

And this is my LoginPageCorrectLogin class, which execute one single test case - correct login to the prestashop website:

package testCases;
import pageObjects.HomePagePOM;
import pageObjects.LoginPagePOM;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class LoginPageCorrectLogin {
    public static WebDriver driver = null;
    public static WebElement element = null;
    public static void main(String[] args) {
        driver = new FirefoxDriver();

        HomePagePOM.enterPage(driver); //Enter home site
        HomePagePOM.signIn(driver).click(); //Find Sign In option and click
        LoginPagePOM.registeredEmailField(driver).sendKeys(LoginPagePOM.correctLogin); // Input correct login to field
        LoginPagePOM.registeredPasswordField(driver).sendKeys(LoginPagePOM.correctPassword); //Input correct password to field
        LoginPagePOM.registeredSubmitButton(driver).click(); // Click on submit button
    }

}

I'm begginer at Selenium, but I want to using best practises. Is it correct? For this example I will create other classes like LoginPageCorrectPassword, LoginPageIncorrectLogin and LoginPageIncorrectPassword.
Any advice about page model object will be very helpful.

Upvotes: 1

Views: 677

Answers (2)

sevenFLiP
sevenFLiP

Reputation: 188

When you write your objects, encapsulate all the elements as much as you can so that the methods are not tied to accessing the raw elements. They should be more of an action.

Here's what I came up from looking at your code above.

First, I created a browser object to deal with browser related actions. Browser specific actions are things like maximize, resize, clear cookies, etc.

public class Browser {

    public static Browser newBrowser(WebDriver driver) {
        return new Browser(driver);
    }

    private final WebDriver driver;
    private Browser(WebDriver driver) {
        this.driver = driver;
    }

    public HomePage gotoHomePage() {
        driver.get("http://website.com");
        return new HomePage(driver);
    }
}

Here's a simpler version of Homepage. Your method should describe an action. It's easier to read that way.

public class HomePage {

    private final WebDriver driver;
    public HomePage(WebDriver driver) {
        this.driver = driver;
    }

    public LoginPage signIn() {
        driver.findElement(By.className("header_user_info")).click();
        return new LoginPage(driver);
    }
}

Next is the login page. If you do notice, I have two versions of login method, for success and for failures. Maybe it's just me but when I do automation, I already know what the outcome of the action and all I'm doing is translating that to be automated. So, login with failure might go to a different page and successful login might go to a different page. Well, we need to deal with them on both cases so that our objects won't break. The most important thing to remember is that conditionals (if-else) should be minimized in your test cases.

public class LoginPage {
    public static String correctLogin = "client";
    public static String incorrectLogin = "client_incorrect";
    public static String correctPassword = "pass_correct";
    public static String incorrectPassword = "pass_incorrect";

    private final WebDriver driver;
    public LoginPage(WebDriver driver) {
        super();
        this.driver = driver;
    }

    public FailurePage registerAndFail(String email, String password) {
        driver.findElement(By.id("email")).sendKeys(email);
        driver.findElement(By.id("passwd")).sendKeys(password);
        driver.findElement(By.id("SubmitLogin")).submit();
        return new FailurePage(driver);
    }

    public SuccessPage registerAndSucceed(String email, String password) {
        driver.findElement(By.id("email")).sendKeys(email);
        driver.findElement(By.id("passwd")).sendKeys(password);
        driver.findElement(By.id("SubmitLogin")).submit();
        return new SuccessPage(driver);
    }
}

And here's how you will write the test.

public class LoginPageCorrectLogin {

    public static void main(String[] args) {
        Browser browser = Browser.newBrowser(new FirefoxDriver());
        HomePage homepage = browser.gotoHomePage();
        // assertions here
        LoginPage loginPage = homepage.signIn();
        //assertions here
        SuccessPage sucessPage = loginPage.registerAndSucceed(LoginPage.correctLogin, LoginPage.correctPassword);
        // assertions here
    }

}

Upvotes: 1

OCary
OCary

Reputation: 3311

As this is an open ended question, here are some general pointers:

  1. You probably won't want multiple pages for correct password, incorrect password, etc as those most likely really aren't different pages.
  2. Move your strings, like URL and usernames/passwords to a string-table/resource-file/config-file/something. Having them set in the code means you are forced to edit code if, for instance, a password changes; there are many other negatives as well.
  3. Make general actions into your Page object. Simple example:
    LoginPagePOM.login(username, password, isValidLogin) This way you won't have the login code repeated everywhere, it is easier to understand, and you'll only have to change 1 spot if/when your login page chan

Upvotes: 3

Related Questions