Skip to content

When is the Page Object Model actually useful in Playwright?

Implementing the Page Object Model (POM) for every single automated test scenario often feels like a chore, but not everything needs to be wrapped in a class.

3 min read
Playwright
E2E Testing
Page Objects
Frontend
Testing

Implementing the Page Object Model (POM) for every single automated test scenario often feels like a chore, but not everything needs to be wrapped in a class. If you go about it the wrong way, you end up building a "second framework" that just becomes a headache to maintain.

The real strength of Playwright is testing things that are hard to replicate with mocking: using actual cookies for login, navigating between pages, or handling third-party redirects. This is where POM helps reduce code repetition. But if you overdo it, your page objects become a burden rather than a tool.

My rule of thumb is simple: keep page objects thin. Their only job is to give a name to what the user sees—like a login page or settings—and provide basic actions. For example, just create a submitValidCredentials() function; don't let getByTestId('btn-primary-2') leak all over your test files. One crucial thing: don't put assertions inside your objects. Let the object know how to click a button, but let the test file decide what the expected outcome is.

Use POM when you have repeating flows, like selecting an organization or opening a project across multiple test files. It’s also useful as a single point of control if a UI label suddenly changes. However, if a flow only happens once and isn't likely to change, just write it directly in the test file. Don't force it into an object if it just ends up bloating your code.

A common mistake I see is creating massive "god objects" with dozens of methods. That’s no longer a helper; it’s a standalone framework that’s prone to breaking if you don't maintain it perfectly.

Regarding locators, I prefer using role and name, only falling back to test-id as a last resort. Relying purely on test-id can be a sign that your product's accessibility isn't actually that great.

It’s also important to distinguish between global elements—like navigation bars or toast messages—and page-specific elements. For things that appear everywhere, a small, single helper is enough. One more tip: don't hide "waiting" logic inside your objects. Using sleep or manual retries inside a page object will only create flaky tests that are a pain to debug.

The bottom line: don't over-mock in your E2E tests. If you stub out every single network connection, you’re basically just running integration tests on a slow browser. Save the mocking for unit tests and let Playwright test what actually happens in the real world.