Companion Page Objects package reusable test interactions with UI widgets and ship beside the widgets, helping teams discover and share automation without duplicating component knowledge. section 15.2.4 section 15.2.8
A practical design combines familiar Page Object structure with Screenplay-style composition:
- Inject the widget’s host element so callers can reuse the abstraction in different contexts. section 15.2.4
- Expose methods that return tasks for interactions and question adapters for widget state, rather than returning only raw element operations. section 15.2.4
- Publish the test code with the widget module under a separate entry point, keeping shared test dependencies away from production code. section 15.2.8
A toaster companion
A Toaster companion can locate a toast message, derive its status from CSS classes, and provide a dismissMessage task that waits for the message, clicks it, and waits for it to disappear. Higher-level tests can compose these tasks and questions without repeating the widget’s selectors or interaction details. section 15.2.4
Listing 15.10 Companion Page Objects
import { By, Click, CssClasses, PageElement } from '@serenity-js/web'
import { QuestionAdapter, Task, Wait } from '@serenity-js/core'
import { isPresent, not } from '@serenity-js/assertions'
export class Toaster {
constructor(private readonly hostElement: QuestionAdapter<PageElement>) {}
message = () =>
PageElement.located(By.css(`.toast-message`))
.of(this.hostElement).describedAs('message');
status = () =>
CssClasses.of(this.hostElement)
.filter(cssClass => cssClass.startsWith('toast-'))
.map(cssClass => cssClass.replace('toast-', ''))
.slice(0, 1)[0]
.describedAs('toaster status') as QuestionAdapter<string>
dismissMessage = () =>
Task.where(`#actor dismisses the message`,
Wait.until(this.message(), isPresent()),
Click.on(this.message()),
Wait.until(this.message(), not(isPresent())),
)
}
Inspect the companion implementation to see host-element injection, Page Element queries, CSS-class state extraction, and a composed dismissal task. section 15.2.4
