·7 min read
Let's test dark mode and reduced motion
Emulate dark mode and reduced motion in Playwright, then assert the styles the browser actually applied. Run the same checks against two broken CSS variants.

Published: · 3 min read
Choose fields, getters, or methods for Playwright locators without confusing stored locators with stored elements.
On this page
A page object groups reusable actions for part of your app. For example, a checkout page object might expose its Save button.
Should it store that button's locator in a field? Or should a getter create the locator when you need it?
A locator describes how to find an element. That distinction makes the choice easier.
Imagine a page that redraws its Save button after an edit. The old button disappears, and a new button takes its place.
A stored locator can still find the new matching button. Playwright finds the current element each time you use the locator for an action. Its locator documentation explains this behavior.
You aren't storing the original button itself. You're storing the description Playwright uses to find it.
For a fixed button, a field can be enough. A field stores a value on your page object.
This illustrative JavaScript fragment assigns a locator when the page object is created:
constructor(page) {
this.save = page.getByRole('button', {
name: 'Save', exact: true
});
}
The getByRole call describes the button by its role and name. Later, this.save.click() finds the current matching button and clicks it.
This fragment belongs inside a class. It isn't a complete test or an executed demonstration.
Playwright's page object example uses stored locator fields too.
A getter runs a function when you read a property. It can return a locator each time you ask for it.
Here is the equivalent illustrative fragment:
constructor(page) {
this.page = page;
}
get save() {
return this.page.getByRole('button', {
name: 'Save', exact: true
});
}
Reading this.save runs the getter. Calling this.save.click() then uses the returned locator.
Both fragments describe the same button on the same page. The getter rebuilds that description on each access. The field retains the description created earlier.
Neither requires the button to exist when you create the locator. The page redraw alone doesn't make the getter necessary.
MDN's getter reference explains the underlying language behavior.
Now imagine a page object that stores the currently selected product name. You build a locator using that name, then change the name later.
The stored locator still contains the value used when you created it. Finding the current element doesn't mean rereading your page object's other properties.
A getter can build a fresh locator from the current name. That can be useful when the page object's state drives the search.
I'd make the input visible in the method call. For example, buyButtonFor('Notebook') tells the reader which product the test means.
That's a design preference, not a Playwright requirement. A getter can be clear when the changing state is already obvious.
For a fixed Save button, I'd start with a stored locator. When the search depends on an input, I'd consider a method accepting that input.
If reading current page-object state is the goal, a getter may fit. Keep the chosen pattern consistent enough for another person to follow.
There are limits to this explanation. A locator won't repair a changed button name or an ambiguous match. Both versions still need a valid page and a correct description of the target.
Before changing an existing page object, identify the behavior you want to improve. A redraw by itself doesn't require rewriting stored locators as getters.
Anton Gulin is the AI QA Architect, the first person to claim this title on LinkedIn. He builds AI-powered test automation systems where AI agents and human engineers collaborate on quality. Former Apple SDET (Apple.com / Apple Card pre-release testing). Find him at anton.qa or on LinkedIn.
Get notified when I publish something new, and unsubscribe at any time.
·7 min read
Emulate dark mode and reduced motion in Playwright, then assert the styles the browser actually applied. Run the same checks against two broken CSS variants.

·6 min read
Run a small Playwright example and compare two recording settings. Inspect the original failed attempt after its retry passes.

·7 min read
Record a browser task with Playwright, then add a saved-result check. Run the same test against broken and working saves.
