Playwright is a modern, open-source framework for web automation developed by Microsoft. It supports multiple browsers and programming languages, making it a popular choice for end-to-end testing. With features like auto-waiting and built-in retries, Playwright helps you write stable, cross-browser tests.
What is the Page Object Model (POM)?
Page Object Model (POM) is a test automation design pattern that encapsulates web elements and page-specific operations into classes called "page objects." Instead of scattering selectors and interactions across test scripts, POM centralizes and abstracts them within dedicated classes. This structure offers several advantages:
1. Clarity
Tests read like a high-level scenario ("log in," "create issue," "verify result") rather than step-by-step UI actions.
2. Maintainability
When a locator or workflow changes, you update it in one place (the page object) instead of every test.
3. Reusability
Common actions, such as filling a login form, can be reused by multiple test cases without rewriting locators.
Why Use POM in End-to-End Testing?
1. Cleaner Tests
By calling page object methods (e.g., loginPage.login()
) rather than handling selectors in each test, your tests remain short and descriptive.
2. Reduced Duplication
You encapsulate repeated UI flows—like login or form submissions—so you only need to write them once.
3. Scalability
As your application grows, adding new page objects is straightforward. Large test suites become easier to navigate and maintain.
Overall, POM makes your test code more robust against UI changes and easier to reason about. This pattern directly addresses one of the biggest challenges faced by test automation engineers - maintaining brittle test scripts that break when the UI changes.
Implementing POM in Playwright (With Jira as an Example)
Below is a simplified structure for a Jira-like scenario, demonstrating how you might model three pages: LoginPage
, DashboardPage
, and IssuePage
. We assume basic familiarity with TypeScript/JavaScript.
Project Structure
jiraLoginPage.ts
jiraDashboardPage.ts
jiraIssuePage.ts
Best Practices for Structuring Page Object Classes
1. Dedicated Classes
Create one class per page or component. This keeps your code organized and each class focused.
2. Centralized Locators
Define locators at the top of your class, clearly named to reflect each element's purpose.
3. Granular Methods
Page methods should correspond to a meaningful user action (e.g., loginPage.login()
rather than many smaller steps).
4. Avoid Business Logic
Keep page objects focused on UI interactions. Actual assertions or complicated logic should reside in your test files or separate utility layers.
5. Optional Base Page
A base class can hold common helpers and reduce duplication in multiple pages.
For more details on organizing your tests effectively, check out our guide on Test Grouping in Playwright, which complements the Page Object Model approach.
Handling Complex Interactions
Modern web apps often include dynamic elements, AJAX updates, and modals. POM works well with Playwright's built-in waiting features:
- Auto-Waiting: Playwright's
Locator
methods (like.fill()
,.click()
) automatically wait for elements to be visible and enabled. - Explicit Waits: If pages load data asynchronously, use
page.waitForSelector()
orwaitForResponse()
in your page object methods to ensure elements are ready. - Conditional Elements: For things like tooltips or dropdowns that appear on hover, encapsulate the hover and wait steps in one method.
By placing these waits in your page objects, your test files remain simple while still handling complex UI scenarios reliably. This approach can help reduce test flakiness, one of the most frustrating aspects of test automation.
Example Test Using POM (Jira Workflow)
Below is how a test might look, bringing the page objects together:
In this test:
- We instantiate the
JiraLoginPage
andJiraDashboardPage
objects with the same Playwrightpage
. - Each page object method abstracts the necessary selectors and interactions.
- Assertions remain in the test layer.
Alternatives to the POM Approach
Although POM is a widely adopted pattern, there are a few notable alternatives and variations you may consider:
1. Screenplay Pattern
The Screenplay Pattern models user interactions as "tasks" and "interactions." Instead of classes for each page, you define "actors" performing tasks like Navigate
or EnterCredentials
. This shifts focus from pages to user actions, often improving test readability. However, it can be more complex to set up.
2. Component/Widget Objects
Some teams prefer smaller "widget" objects for specific components—like a date picker or search box—and reuse them across pages. This is somewhat of an extension of POM but more granular. Instead of large page files, you focus on reusable UI fragments. It still shares the same principles of encapsulation but organizes your code differently.
3. Direct Locator-Based Tests
You could write tests directly with locators and no abstraction, especially for small or short-lived projects. This can be faster to implement initially, but typically becomes hard to maintain at scale. It's most suitable for tiny projects or proof-of-concept tests where longevity isn't a concern.
4. BDD with Gherkin
Behavior-driven development (BDD) tools like Cucumber let you write human-readable scenarios in Gherkin and map steps to code. While still possible to incorporate POM inside step definitions, some teams build minimal or no "page object" layers and rely heavily on step definitions. This can be effective for collaboration but may mix business logic and UI details if not carefully managed.
Whether you stick to POM or opt for alternatives can depend on project size, team preference, and code maintenance requirements. Many advanced teams even combine patterns, for instance, by using smaller component objects within a broader POM approach, or layering Screenplay tasks on top of page objects.
For teams exploring modern testing approaches, AI-powered testing tools can complement these patterns by helping to generate and maintain tests, especially when combined with session recording for E2E testing.
Common Mistakes and How to Avoid Them
1. Mixing Assertions in Page Objects
Keep verifications in the test layer. Page objects are for actions, while tests handle pass/fail checks.
2. Duplicate Locators
Avoid repeating selectors across multiple pages. If you have a common navigation bar, make a shared component or base page.
3. Overly Large Methods
Don't cram too many steps into a single method. Each should represent one meaningful user action.
4. Bypassing the POM
Writing locators directly in the test defeats the purpose. Make sure all UI interactions live in page objects.
5. Ignoring Dynamic Waits
If a page uses AJAX or dynamic content, incorporate explicit waits (or rely on Playwright's built-in locator waits) to prevent flaky tests.
Final Thoughts
Page Object Model is a proven method for organizing tests in Playwright. By separating UI selectors and actions into page objects, you gain significant advantages in code readability, maintainability, and scalability. Combined with Playwright's powerful waiting features, POM-based tests become clear, robust, and efficient. In most scenarios, POM strikes a great balance between simplicity and maintainability. If you're building long-lived end-to-end tests in Playwright—especially for larger applications like Jira—adopting a well-structured POM approach will likely pay off in the long run.
For additional insights on test maintenance challenges and solutions, explore our article on Test Automation Challenges Engineers Face, which addresses common pain points in maintaining automated test suites.
Ready to improve your Playwright testing approach? Consider exploring Posium's AI-powered testing tools, which can help automatically generate tests while adhering to patterns like Page Object Model.
Written by
Naomi Chopra