Page Object (2013)
Posted4 months agoActive4 months ago
martinfowler.comTechstory
calmmixed
Debate
80/100
Page Object PatternUI TestingTest Automation
Key topics
Page Object Pattern
UI Testing
Test Automation
The discussion revolves around Martin Fowler's 2013 article on Page Object pattern, debating its effectiveness in UI testing and test automation.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
4d
Peak period
24
96-108h
Avg / period
12.5
Comment distribution25 data points
Loading chart...
Based on 25 loaded comments
Key moments
- 01Story posted
Sep 11, 2025 at 1:26 AM EDT
4 months ago
Step 01 - 02First comment
Sep 15, 2025 at 1:44 AM EDT
4d after posting
Step 02 - 03Peak activity
24 comments in 96-108h
Hottest window of the conversation
Step 03 - 04Latest activity
Sep 15, 2025 at 2:32 PM EDT
4 months ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
ID: 45208102Type: storyLast synced: 11/20/2025, 3:10:53 PM
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
I’m not certain that it buys enough to justify an extra layer of indirection in every front-end test though. Having a collection of selectors with meaningful names seems to get you about half the value without that extra layer.
So in almost every project the Cypress tests are a procedural mess, while the Playwright tests are mostly well structured.
I know that Cypress has other patterns for dealing with this but they never seem to get applied.
--
1: https://playwright.dev/docs/pom
Hadn't considered the Page Object Model and will definitely have to consider how to incorporate that for those who want to do things that way.
---
1: https://github.com/zikani03/basi
Another note on your specific example: You are probably in the US and only have a single-language project. I am a Frontend Contractor in Europe and for the past 10 years didn't have a single project that was single language, hence the "hasText" selector would always be off-limits. Instead, very often we used the react-intl identificator as text content for code execution - which would make the above example look much more unreadable without POs, while with POs the code looks the same (just your PO looks different).
This argument also applies to using a function for abstraction.
I've just written a few dozen e2e tests with Playwright. The code looks like:
Each of those lines is 3 to 20 lines of Playwright code. Aggressive DRY is bad, but Page Object Models are usually worth it to reduce duplication and limit churn from UI changes.It was a few years ago, and very AngularJS focused, but I posted something along these lines: https://charemza.name/blog/posts/angularjs/e2e/consider-not-...
In summary: having thing look cleaner at a glance is not helping if you’re (almost) always going to need to do more than glancing
As usually, there is a balance to be found.
What to Submit On-Topic: Anything that good hackers would find interesting. That includes more than hacking and startups. If you had to reduce it to a sentence, the answer might be: anything that gratifies one's intellectual curiosity.
Off-Topic: Most stories about politics, or crime, or sports, or celebrities, unless they're evidence of some interesting new phenomenon. Videos of pratfalls or disasters, or cute animal pictures. If they'd cover it on TV news, it's probably off-topic.
This one seems reasonable.
[1] https://news.ycombinator.com/newsguidelines.html
I also find them very developer-centric — testers get forced into upfront design work that doesn’t fit how they naturally test, and many struggle with it. I’ve had better results by expressing behavior directly and keeping UI concerns thin, instead of using a wrapper around page structure.
However, the following design, thanks to Clojure's language design, helped address a rather nasty situation.
A tightly scoped Domain Specific Language, over some Types of PageObjects, all of which compose arbitrarily (without breaking value semantics). So, if you wanted the `value` of a Modal box having all sorts of switches, form fields etc., you'd call `value` on it, and it would call `value` on all of its constituents, and return the immutable hash-map snapshot of whatever state it found.
Concrete example (in the deck and demo linked below): And then an implementation like this: Deck: https://github.com/adityaathalye/slideware/blob/master/desig...Talk + Demo: https://www.youtube.com/watch?v=hwoLON80ZzA&list=PLG4-zNACPC...
I also commented about it here: https://news.ycombinator.com/item?id=45161410 (Clojure's solution to the Expression problem).
That said, UI testing is a hot mess in general (especially for SPAs). I prefer to avoid automating anything but the "happy paths". IME, exploratory testing is better at sussing out corner cases, and "emergent" misbehaviours. So I do that, in addition to the "happy path" suites. Cue: James Bach et. al. https://www.satisfice.com/
Also I am warming up to server-generated HTML, because I can unit-test that, if I can use `hiccup` syntax + HTMX. In that case, I just make all request handlers spit out HTML fragments as Clojure data, and test those responses in my test suite.
I'm sorry, but if your testers are not comfortable getting involved in the early design stages of your software in a 21st century world, then there's at least a 90% chance that their primary role at your company is perpetuating organizational dysfunction.
Most of my career has been defined by cleaning up the gargantuan messes the culture of "throw tickets over the wall to QA" created, and it has been very, very ugly. It defies common sense how culture around tools and processes for dev and ops roles continues to evolve over time, but for some reason testers are still trying to test software off in a silo, like it's released once or twice a year on CD-ROM.
You might be asking too much of them to the point they become a burden.
1. Page Object Model should not contain any test-related stuff. It should abstract common page interactions:
etcThen what you do in your tests is:
> and make even trivial UI changes ripple through dozens of files.2. Given my previous example, if you changed the login or registration form you'd only update the implementation of `registerUser`.
In any case I also want to emphasize: POMs are very useful when collecting and reusing the data (e.g. in the previous example `login()` would take no params and reuse those declared before), you can achieve 95% of their functionality with plain simple helper functions.
If a webpage is an iceberg, the buttons and menus and dropdowns are the visible part. If I understand this page object, that’s what he proposes testing.
But the bit I care about is the bit underneath that will compose REST calls from those UI elements and sometimes make subsequent REST calls from the result of the previous ones.
That is the tricky bit to test, and the bit where we *still* fall back to manual testing and recorded demos for qa.
I was hoping this was a suggestion for a better selenium.
Playwright also implements fixtures and Page Object Model:
https://playwright.dev/docs/pom
I worked at a place where a well meaning QA tech rewrote the test suite to use page objects. It was a total mess and I undid most of that work in the end. It just moved a bunch of xpath expressions a long way from the rest of the test code, and it was all single use anyway.
But anyway if you were in that situation, duplication of selectors and labels and other implementation details of a page that were liable to change across a bunch of tests was an _absolute nightmare_ to deal with when you'd get a massive report of failures with bad error messages and often incorrect stack traces. Being able to fix all those errors by changing a selector in a single page object governing all of them was indeed better than the alternative.
In the era of Cucumber, page objects were yet another level of indirection around what was a far-too-indirect process to provide the kind of feedback loop you'd need for it to be valuable. Especially as part of a development workflow.
In an MVC conception, the UX model becomes a top layer of abstraction of the domain model. It's a natural place to be because for modern apps, users expect "more than forms", i.e.: different ways of cutting up the domain data, presented in different ways, ...
This is something that component-based frontend frameworks struggle with a bit: the hierarchical layout of the DOM doesn't always reflect the interrelations in data between parts of a user experience. Prop drilling is just a reflection of this fact and perhaps it's why we're seeing a rise in the use of state stores. It's not really about state, that's just the technical symptom, it's really about providing a way of defining a (in-browser) data model based on the user experience itself rather than the particularities of the UI substrate.