If you’re using Playwright with Page Objects, you’ve probably seen something like this:
this.delayedTaskByArticleNo = (articleNo: string) =>
this.page.locator('div.grid-cols', { hasText: articleNo });
It works.
But it’s a bad pattern.
This article explains what this pattern is, why it causes problems, and what to do instead.

What Is This Pattern Called?
That code is a parameterized locator factory defined in the constructor.
Key traits:
- It’s dynamic (takes parameters)
- It’s defined as an arrow function
- It lives inside the constructor
- It returns a Locator
It’s often confused with “dynamic locators”, but that’s not the real issue.
The problem is where it lives and how it’s structured.
Why This Is a Problem
1. Constructors Should Be Dumb
A constructor should:
- Assign this.page
- Define static locators
That’s it.
When you put logic, parameters, or behavior into the constructor, you turn setup code into business logic.
That makes the class harder to reason about.
2. It Hides Locator Intent
When everything is defined in the constructor:
- You can’t quickly see what locators exist
- IDE navigation is worse
- Code reviews become slower
Reading a page object should feel like reading a map.
Constructor factories turn it into a maze.
3. It Blurs Responsibilities
A locator factory is behavior, not structure.
Putting it in the constructor mixes:
- Object initialization
- Query logic
- Runtime decisions
This violates separation of concerns.
4. It Scales Poorly
As the page grows, constructors turn into long blocks of:
- Arrow functions
- Parameters
- Inline logic
At that point, nobody wants to touch it.
That’s how tech debt starts.
The Better Pattern: Locator Accessor Methods
Instead of defining parameterized locators in the constructor, move them into explicit methods.
Bad
constructor(page: Page) {
this.page = page;
this.segmentByIndex = (index: number) =>
this.page.locator('dl.mb-3').nth(index);
}
Good
getSegmentWithForbiddenTermAtIndex(index: number): Locator {
return this.page.locator('dl.mb-3').nth(index);
}
Why This Is Better
1. Clear Separation
- Constructor = setup
- Methods = behavior
Simple mental model.
2. Better Readability
Methods:
- Have names
- Have return types
- Can be documented
- Are easy to search and review
You immediately understand intent.
3. Easier Refactoring
When locators are methods:
- You can change implementation without touching construction
- You can add logging, guards, or assertions later
- You can deprecate patterns safely
4. Better Team Consistency
Once enforced, everyone writes page objects the same way.
Less debate.
Less “personal style”.
More predictable code.
Rule of Thumb
Use this simple rule:
If a locator needs parameters, it must be a method, not a constructor property.
Static locator?
- Constructor is fine.
Dynamic locator?
- Method only.
No exceptions.
Final Take
Parameterized locator factories in constructors are not “wrong”, but they are lazy shortcuts that hurt long-term maintainability.
Locator accessor methods:
- Scale better
- Read better
- Age better
Your future self (and your teammates) will thank you.