Top

Tips for Healthy Page Object Classes

Tips for Healthy Page Object Classes

It’s the beginning of a new year and people all over the world have made resolutions to become healthier. That’s wonderful! In fact, your frontend tests want in on the action as well.

The most popular design pattern used in web UI test codebases is the Page Object Model (POM) design pattern. This pattern suggests modeling a class to represent a single page of your system under test. Using this model, the class would contain properties that represent the elements of the UI page and methods that interact with these elements.

Given this is the Login Page of our application, let’s discuss tips for building a class using POM.

The Class

We make a single class in our automation framework to represent this page. It’s recommended to ensure the name of the class is representative of the page in the application so that other developers can quickly find the class associated with a given UI page.

So, in this example, we’d make a class called LoginPage.

 

Properties

LoginPage should contain properties for each of the elements on the page that will be used within your tests. The value of these properties are locators to the elements on the actual page. By defining these locators in one place, you won’t need to hardcode them in every place that you use them – thus, eliminating duplication.

 

Methods

In addition to the properties, the class should also contain methods that enable a test to interact with the application, such as setting input fields and clicking buttons. Here are some tips on designing these methods to be optimally used by your tests.

 

Add Getter and Setters

The purpose of POM classes are to set and get the state of your application. So, you’ll need methods to do this.

For example, we definitely need to set the username and password fields, so set methods should be added.

We also need to know the content of the error message, so this will need a getter method.

 

Only Add What’s Currently Needed

Notice, we didn’t add getter and setter methods for every field, because we don’t have a need for them in our tests. Only add what’s currently needed. You can always add more if a new test requires such. This will prevent you from needing to maintain unused code.

 

Transitions Should Return New Objects

You’ll also need methods for clicking links and buttons. However, when your click results in a page change, your method should return a handle to the class representing the UI page you’ve transitioned to.

For example, if clicking the sign-in button will lead to the home page of your application, then your method should return a handle to the class representing that home page.

By providing this, all calling tests know that a transition will occur by calling this method, and the test has a handle to the necessary object to continue interacting with the application.

 

Don’t Be Afraid to Make Convenience Methods

Right now, logging into the application would take at least three method calls (setUsername, setPassword, and clickSignInButton). As these three are commonly used together, it makes sense for your class to also provide a convenience method so that your tests only need to call one method.

Notice we did not implement the logic within this method, but instead called the individual methods. It’s important to have those separate methods available, so that negative tests (e.g. set username but not password) can utilize them.

 

Be Mindful of State

For checkbox elements (or other toggles), simply clicking them may not satisfy the desired intent of the test. For example, what if your test wants the box to be checked, but it’s already checked? Calling a click method would give you the opposite of what you want. Instead, make your method more sophisticated by implementing logic that will only check the box if it’s needed to give the user their desired result. To do this, instead of blindly clicking, accept an argument that specifies intent (i.e. do they want it selected or deselected) and act accordingly.

 

Keep POM Classes Neutral

Your POM class should be a neutral entity that interacts with and gathers information about your application. Be careful to keep your methods neutral and ensure they are generic enough to be used by any test that wishes to interact with the page. This basically means do not include assertions within these methods.

By keeping the methods neutral, they can be used in both positive and negative tests. The test can use the information returned from the class for its own purposes in determining whether that information warrants a pass or fail.

For example, what if our method that gets the error message also fails the test if the message is visible?

I cannot reuse this method for tests where I want to make sure an error message is shown when the username or password is incorrect or not provided. This is because the POM class has taken it upon itself to determine that the display of an error message is a failure; when in these cases, that’s not so. Instead, just return the state and allow the test to determine what that means.

 

 

Healthy Code Makes Healthy Tests

These tips should help you design healthy classes that implement the Page Object Model design pattern. The use of this pattern promotes separation of concerns (e.g. tests vs managing state), reduces code duplication, and provides reusable methods. Happy testing!

Angie Jones
20 Comments
  • Tom
    Thanks for the great article!
    I can see in your code snippets that your properties are By types. What are your thoughts on having these as WebElements? Any preferences?
    I quite like using WebElements as it reduces the need to write driver.findElement in lots of other places. I think this can also improve readability of code as you can have signInButton.click() etc.
    February 6, 2020 at 1:31 am Reply
    • Angie Jones

      If you instantiate at declaration, wouldn’t it look for all those elements at that time? Sometimes those elements are not there yet, as they can be dynamic based on other interactions on the page.

      February 19, 2020 at 8:13 am Reply
  • Cesar M

    This is a great article and very eye-opening. I have been doing it wrong all this time!! Thank you, Angie.

    February 19, 2020 at 6:52 am Reply
  • John

    This is great! I’m just starting and will be good to know.

    February 22, 2020 at 6:13 am Reply
  • Roman
    Hi Angie,
    I would like to ask:
    Why did you recommend to use Page Object without PageFactory without elements and FindBy annotations?
    February 24, 2020 at 8:19 am Reply
  • ali

    Hi angie,

    Thanks for the great article.
    I have a question if I use pom or screenplay, I really don’t know what to do.
    Could you help me with your opinion?
    which prefer?
    May 23, 2020 at 8:25 pm Reply
  • ali
    hi angie sorry another question.
    when the page has many fields,
    What do you do?
    for example, separate the page into child pages
    May 23, 2020 at 8:48 pm Reply
  • Mateusz

    What about returning “this” from page objects methods insted of returning void? By this you gain the possibility to chain acctions.

    October 9, 2020 at 8:10 am Reply
  • Ryla Burges

    What if I wanna store methods in separate action class? how to instantiate variables in that case so that it won’t throw null pointer exception?

    December 15, 2020 at 1:22 am Reply
  • Dihfahsih

    Great stuffs from Angie

    December 22, 2020 at 2:54 am Reply
  • Zeeshan Ali

    is there any method used as POM for sorting array. which return sorted array when called this method in Testng framework

    January 21, 2021 at 8:16 am Reply
  • Dinesh

    Great article Angie!

    One question – Wouldn’t it be better to keep the setter methods like setUsername private? This way, the access to the page interactions can be restricted through the login method only.
    February 11, 2021 at 11:56 am Reply
  • Raja

    Great article!

    I have a question. Below method returns HomePage when login success.
    public HomePage clickSignInButton() {
    driver.findElement(signInButton).click();
    return new HomePage();
    }
    How to use same method but to return LoginPage itself when Login fails and HomePage when Login success
    March 25, 2021 at 2:26 am Reply
    • Angie Jones

      That’s a great question, because clickSignInButton() is assuming success. You don’t *have* to use the object that is returned. If you’re calling clickSignInButton, you’re doing so with a LoginPage object already. So in your test, just continue using that same object, since the app is still on that same page.

      March 25, 2021 at 10:05 am Reply
  • Jorge Rizado
    Nice article with clean advice!
    I have also a question regarding the following method
    public HomePage clickSignInButton() {
    driver.findElement(signInButton).click();
    return new HomePage();
    }
    Don’t we need to pass the driver instance in the HomePage() when we return the object?
    The way I’ve structured my Page Objects requires to pass a driver instance in the constructor method of each page object. Is this a wrong approach?
    And another one related: Have you ever tried to break a page object into smaller ones(components)? What is the best approach on this? For example there is a table or a nav bar that is included in many different pages.
    Thanks a lot for the insights and your time!
    George
    May 10, 2021 at 1:49 am Reply
    • Techie

      I have same query… Did you get the answer for this.. If yes please do share… TIA

      October 13, 2021 at 10:18 pm Reply
  • Owyn Dwight

    Hi Angie,
    Love the posts! Quick question, would you ever declare the By properties as static? And why/why not?
    Thanks in advance!

    May 23, 2021 at 5:58 am Reply
  • Seyi T

    I’m new to this and found this information insightful. Thanks.

    June 15, 2021 at 6:39 pm Reply
  • yasmina

    i would like to know why you make the element locator have private access ?>

    September 16, 2021 at 2:46 pm Reply

Post a Comment