Page Object Models trade off clarity for encapsulation. Concrete example [1]. They can make tests look "cleaner" but often obscure what's actually happening. For example:
await page.getStarted(); // what does this actually do?
The second version is explicit and self-documenting. Tests don't always benefit from aggressive DRY, but I've seen teams adopt POMs to coordinate between SDETs and SWEs.
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.
I am working on a tool[1] to try to make working with playwright a bit more ergonomic and approachable. Sorry to shamelessly plug but I'd love feedback on if it is even a good idea/direction.
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.
Is much more readable, and on typing "page." you will see what props on your PO are available.
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).
It's not a trade-off of clarity just to save developers some extra typing. It's actually improving the clarity by bringing the thing you care about to the foreground: the getting started page having a table of contents with specific items.
--
1: https://playwright.dev/docs/pom