A header widget appears on six pages — one page object per page, or something else?
Asked 9,210 views3 answers
27votes
Our header carries the cart badge, the account menu and a search box, and it is on six pages. Right now the cart badge locator is copy-pasted into six page objects, which was fine until the badge got a new test id and I had to fix it six times.
Splitting it out is obvious. What is not obvious is what the split looks like when the steps are decorators on classes that are registered per page.
Nothing says a page object has to correspond to a URL. Give the header its own class, register it as its own fixture, and put the header steps on it. They then work in any scenario regardless of which page is open, because the fixture only needs the page.
One reason to do it this way beyond the obvious deduplication: the description in a heal context is the key the fragility statistics are grouped under. Six copies of the same locator with six slightly different descriptions give you six thin rows in the heal report instead of one row that says clearly that the cart badge changed.
Second approach, for the case where you do not want the component to own any step text: make it a plain class that takes the page and the healer, and expose it as a field from the page objects that need it.
A getter rather than a field, because a field initialiser runs before the constructor assigns heal. Page objects get away with writing fields only because BasePage has already assigned it by the time the subclass initialises.
Then readonly header = new Header(this.page, this.heal) inside each page object. Locators shared, steps still owned by the page they read best on. I use the fixture version when the steps are genuinely global and this one when they are not.