Page Object Model with Playwright

September 19, 2024

blog

Modern web pages are growing increasingly more complex with intricate features and multiple elements per page to track. Creating test suites for these web pages can seem like a daunting task especially when looking at a well-established application from a high level. Just like the best way to eat an elephant is one bite at a time, the best way to test a web-based application is one page at a time with Page Object Model.

This design pattern can be applied to a variety of browser-based end-to-end testing frameworks such as Cypress, Selenium, etc. and the programming languages they support. In this article, I will be using the testing framework Playwright with Node.js to illustrate the effectiveness of Page Object Model. I have linked a repository I made for demonstration purposes below.

I will be testing against a website called the-internet.herokuapp.com (which I will refer to as "the-internet" going forward). The-internet is an open source training web application made for the purpose of practicing browser-based automation. I have linked the-internet's repository below for those who wish to contribute new functionality for testers to practice with automation tools.

Reference Links:

The Philosophy of Page Object Model

The main premise behind Page Object Model is simple: each page of a website is represented by a class. Each class should contain page elements for a specific page stored as properties and methods to interact with those elements programmatically. For example, all the steps to log into a website can be written as a method/group of methods in a home page class.

Another nice feature of Page Object Model is that it can facilitate object-oriented programming practices within the end-to-end testing repository. If there is a web page that shares a large portion of elements and/or functionality with another page, it can inherit from the parent page to reduce code repetition. A realistic use case for this would be testing a website that contains a variety of forms that users to fill out with similar fields or workflows.

There's No Place Like Home... Page...

On the-internet landing page, there are only a few headers and banners before a long list of links to pages designed for practicing automated browser testing. Page Object Model allows me to verify all the elements of the home page are present as well as navigate to any of the linked pages easily and dynamically.

the-internet landing page with the first few links

Building the Home Page Class

Below is a template for what the-internet HomePage class could look like with Page Object Model in Playwright. It includes elements from the home page to verify successful navigation once Playwright loads the browser and goes to the URL. There is also a method to click into any of the linked pages by passing the name of the page as the argument.

Now that I can successfully navigate to the home page of the test website consistently, I can begin click into other pages and start testing their functionalities.

Adding and Removing Elements Tests

The first page on the-internet with testable features is the Add/Remove Elements page. When the Add Element button is clicked, a new Delete button appears. Clicking on the Delete button removes it.

Add/Remove Elements page with one element added

In keeping with Page Object Model, I created a new class specifically for the Add/Remove Elements page where I can dynamically add or remove elements with custom methods. I also added a check so that I cannot remove more elements than I have added.

Maximum Testing Without Maximum Effort

This is where Page Object Model shines. For testing the Add/Remove Elements page tests, I can write multiple tests with minimal code changes between test cases using objects of the webpage classes which store the core functionalities.

Below is how I organized all the tests for the Add/Remove Elements page as an example of how the Page Object Model scales with multiple test cases in a suite. I scope the Add/Remove Elements page test suite with the test.describe block and call the test.beforeEach hook to navigate to the correct page from the home page prior to test execution. For most of the test cases, only a single variable gets updated between test cases.

I replicated the Add/Remove Elements test cases without using Page Object Model in the file addRemoveNonPOM.spec.js to emphasize how efficient this design pattern can be for end-to-end testing architecture. Page Object Model really cuts down on the amount of repeated code between test cases and organizes page functionality in an intuitive way.

Page Object Model and Inheritance

When there are web pages with a significant amount of overlapping characteristics, inheritance can greatly reduce the risk of duplicated code across the testing repository. Core functionality can be stored in a broad parent class and distributed systematically to more specialized child classes.

The Floating Menu and Infinite Scroll pages within the-internet both have large text bodies and require scrolling down the page to test.

Floating Menu page
Infinite Scroll page

Parent Class Implementation

I started by creating a parent class called ScrollablePage where I added two methods for moving down a web page. Page elements can also be added to the parent class and inherited by its children. If a new page is developed in the future that would benefit from scrolling down the page to test, ScrollablePage class can be inherited to simplify test development.

Now all that is needed to complete the InfiniteScroll and FloatingMenu classes for testing are inheriting the ScrollablePage parent class and adding the page elements specific to the child class as properties to verify during testing.

With scrolling implemented in the ScrollablePage class and the webpage elements defined in the FloatingMenu class, I can test that the menu options are still visible when scrolling below the page header.

Final Thoughts

Page Object Model is the ideal design and organization strategy for structuring robust end-to-end test suites. It allows compartmentalization of page elements within individual classes but also enough flexibility to share functionality through inheritance. It expertly facilitates an architecture for scaling testing repositories to meet the demands for large web-based applications testing. I encourage everyone who works with browser-based test automation to adopt Page Object Model for their end-to-end testing repositories whether it is with Playwright or another browser testing framework of choice.