The Zen of Page Objects: Find Inner Peace and Clean Code

Written by yanalunts | Published 2023/05/09
Tech Story Tags: testing | software-testing | test-automation | e2e-testing | ui-testing | design-patterns | page-object-model | qa-best-practices

TLDRPage Object is a design pattern used in test automation where the application's user interface is broken down into small, reusable components. It includes all the necessary logic and actions that can be performed on that page, such as filling out a form, clicking a button, or navigating to a different page. via the TL;DR App

In this article, we will discuss how to follow the best 7 practices for Page Objects.

What is Page Object?

A Page Object is a the most common design pattern used in test automation. Each page elements and methods are written in separate class. These methods include all the necessary interaction that you need to do on that particular page.

For example, login to the website, search something on the website, add product to the basket — all of these are separate methods in the Page Object Pattern. Later, you can use easily these methods in the your tests instead writing this repetitive code in each test. It’s easy to maintain, easy to write, easy to read and many more useful benefits.

Let’s check the example

In this example, I’m using JavaScript and Playwright.

The main steps to create any Page Object would be:

  1. Create a separate class
  2. Add locators for this class
  3. Create methods to use in the tests
const { Locator } = require('@playwright/test');

class GoogleSearchPage {
  searchInput = new Locator('input[name="q"]');

  constructor(page) {
    this.page = page;
  }

  async goto() {
    const baseUrl = BASE_URL;
    await this.page.goto(baseUrl);
  }

  async setSearchInput(query) {
    const searchInput = await this.searchInput.waitFor();
    await searchInput.fill(query);
  }

  async search(query) {
    await this.setSearchInput(query);
    await this.page.keyboard.press('Enter');
    return new GoogleSearchResultsPage(this.page);
  }
}

It looks good. But we still have many questions as to what are the best practices here. Let’s take a deeper look.

Keeping Your Tests Clean and Your Sanity Intact

1. The first and main best practice is one Page Object for one page

Create a separate Page Object for each page or component. Each Page Object should represent a single page in your application. This is important because it helps keep your code organized and makes it easier to maintain in future. When you have a separate Page Object for each page, you can easily update the methods related to that page, without affecting other parts of your code.

This is the biggest the difference between having the same code in each test and having PO. Overall, creating a separate Page Object for each page or component ensures that your test code remains clean, and easy to maintain. And this is beneficial for you in future or your future colleagues who eventually will start helping you with tests.

2. Separate Page Objects from test code

Keep your Page Objects separate from your test code. Create a separate folder for Page Objects and keep them organised there in alphabetical order. This is a clean solution for you to avoid mess later on.

3. Use descriptive names for methods and locators

Use descriptive and meaningful names for your Page Objects and their methods or anything else inside the page really. This will make your code more readable and easier to understand.

4. Include only methods that interact with the page

Your Page Objects should include only methods that interact with the page for which you created this Page Object.

5. Avoid using any hardcoded values

Avoid using hardcoded values (e.g., URLs, usernames, passwords) in your Page Objects. Use configuration files or environment variables instead. You can also keep your hardcoded values in the separate file with constants. Don’t save the this file with passwords and usernames or any important information on your open GitHub profile.

6. Transitions should return new objects

Eventually, you would need methods to interact with elements on a page. However, when your click leads to a new page, your method should return new page object of page which you navigated to.

For example, when we search for something in Google, once we press the “Enter” button we’re navigating to the new page - GoogleSearchResultsPage(this.page);

7. Locators

Locators as methods should be defined as part of the Page Object class, and should not be hardcoded into the test code. This makes it easier to change the locators if the UI changes and reduces the amount of duplication in the test code.

By following these best practices, you can create a Page Object framework that is easy to maintain, reusable, and provides a high-level, abstract interface.


The lead image for this article was generated by HackerNoon's AI Image Generator via the prompt "a zen monk writing code on a laptop".


Written by yanalunts | QA engineer with passion about chess
Published by HackerNoon on 2023/05/09