2

I am creating a UI test automation framework using POM design pattern. After reading SeleniumHQ page for Page Objects, I am contemplating what all methods should I create inside a Page Object.

Let's take a simple example of login page object consisting of username, password textboxes and submit button. SeleniumHQ link has created the below methods :

1. typeUsername(String username)
2. typePassword(String password)
3. submitLogin()
4. submitLoginExceptionFailure()
5. loginAs(String username, String password)

I am a bit perplexed while looking at these methods. Why should I create first 3 methods(typeUsername, typePassword,submitLogin), when I already am creating a loginAs method. Any thoughts around it ?

SeleniumHQ Link - https://github.com/SeleniumHQ/selenium/wiki/PageObjects

Pasting the code PageObject code for LoginPage :

public class LoginPage {
    private final WebDriver driver;

    public LoginPage(WebDriver driver) {
        this.driver = driver;

        // Check that we're on the right page.
        if (!"Login".equals(driver.getTitle())) {
            // Alternatively, we could navigate to the login page, perhaps logging out first
            throw new IllegalStateException("This is not the login page");
        }
    }

    // The login page contains several HTML elements that will be represented as WebElements.
    // The locators for these elements should only be defined once.
        By usernameLocator = By.id("username");
        By passwordLocator = By.id("passwd");
        By loginButtonLocator = By.id("login");

    // The login page allows the user to type their username into the username field
    public LoginPage typeUsername(String username) {
        // This is the only place that "knows" how to enter a username
        driver.findElement(usernameLocator).sendKeys(username);

        // Return the current page object as this action doesn't navigate to a page represented by another PageObject
        return this;    
    }

    // The login page allows the user to type their password into the password field
    public LoginPage typePassword(String password) {
        // This is the only place that "knows" how to enter a password
        driver.findElement(passwordLocator).sendKeys(password);

        // Return the current page object as this action doesn't navigate to a page represented by another PageObject
        return this;    
    }

    // The login page allows the user to submit the login form
    public HomePage submitLogin() {
        // This is the only place that submits the login form and expects the destination to be the home page.
        // A seperate method should be created for the instance of clicking login whilst expecting a login failure. 
        driver.findElement(loginButtonLocator).submit();

        // Return a new page object representing the destination. Should the login page ever
        // go somewhere else (for example, a legal disclaimer) then changing the method signature
        // for this method will mean that all tests that rely on this behaviour won't compile.
        return new HomePage(driver);    
    }

    // The login page allows the user to submit the login form knowing that an invalid username and / or password were entered
    public LoginPage submitLoginExpectingFailure() {
        // This is the only place that submits the login form and expects the destination to be the login page due to login failure.
        driver.findElement(loginButtonLocator).submit();

        // Return a new page object representing the destination. Should the user ever be navigated to the home page after submiting a login with credentials 
        // expected to fail login, the script will fail when it attempts to instantiate the LoginPage PageObject.
        return new LoginPage(driver);   
    }

    // Conceptually, the login page offers the user the service of being able to "log into"
    // the application using a user name and password. 
    public HomePage loginAs(String username, String password) {
        // The PageObject methods that enter username, password & submit login have already defined and should not be repeated here.
        typeUsername(username);
        typePassword(password);
        return submitLogin();
    }
}
brij
  • 331
  • 1
  • 5
  • 17
  • As simple as that login functionality will be in almost every test script. so what would you prefer to write/call all 3 methods in all scripts or just one `loginAs()`? also if any changes happens around this functionality you may have to change every method in every testcases. but if you using `loginAs()` you just have to change there only – Dev Feb 19 '20 at 07:29
  • Now you will wonder you can combine all 3 methods under `loginAs()` method. No harm in doing that but say you have other flow to validate only password field or username field in that case you might not need of other components hence it is in separate for every webelement. and that is what recommended. Just follow thumb rule i.e. "KISS" – Dev Feb 19 '20 at 07:36
  • Does that mean, each webelement in a page would have at least one method assigned to it (click, text, etc) ? – brij Feb 19 '20 at 08:36
  • Not necessarily, it will depend, How much time the particular element is in use across the framework, is it form element, is it a text that appears on only one page or across the application likewise.. – Dev Feb 19 '20 at 10:31

2 Answers2

2

You might want to check if typing the username only and then clicking the submit button shows a correct error message, or only the password, etc.

I usually look at the page and try to summarize what "actions" the user can do on that page, every action becomes a method. The different actions might be on different "levels". e.g. on a blog website, the user can enter the blog-title and the blog content, that are two actions the user can do, but looking from an other abstraction layer the user wants to "create" a post. So that function might again call other functions.

Basically its like any other programming, you have multiple abstraction layers, that is why you have Page Objects in the first place.

And just use iterative development, create a function that does what you want to test and if you find yourself reusing the same code (or identifier) in other functions, separate those out in a new function

INDIVIDUAL-IT
  • 426
  • 3
  • 11
0

Finely chopping your code into more methods allows for greater atomization. Nothing stops you from grouping the typeUsername(), typePassword() and submitLogin() into login() method.

The upside of doing so is knowing more precisely that your login failed at, say, typing password as opposed to "somewhere on the login page".

Mate Mrše
  • 7,997
  • 10
  • 40
  • 77
  • This is correct. However, applying this to a page with plethora webelements would comprehend creating a lot of methods which might not be suitable to keep in a single file. – brij Feb 19 '20 at 08:56
  • Well, you don't necessarily need to keep them all in a single file. Even though it is called Page Object Model, you can create a POM for only a part of a page, like for a header or footer elements, or navigation bar... – Mate Mrše Feb 19 '20 at 09:04
  • okay, but my assumption here is correct, for every webelement there needs to be a method (either click or text or anything) ? – brij Feb 19 '20 at 10:08
  • I would say: if you are going to use the element/method more than once, create it in POM in order to reduce duplication. Otherwise, you don't need to create them in the POM. – Mate Mrše Feb 19 '20 at 10:11
  • 1
    @brij You can consider methods in Page Object as `services` like `login()` or single steps like `enterPassword()` `enterLogin()`. It's really up to you :) – Fenio Feb 19 '20 at 10:34
  • Got it. Thanks :) – brij Feb 20 '20 at 09:38