In this article, we will discuss how to follow the best 7 practices for Page Objects.
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
In this example, I’m using JavaScript and Playwright.
The main steps to create any Page Object would be:
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.
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.
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.
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.
Your Page Objects should include only methods that interact with the page for which you created this Page Object.
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.
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);
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".