@qawolf/pom provides Page Object Model (POM) infrastructure for
Playwright: base classes for page objects, a central
registry that lets page objects construct one another without circular imports,
and automatic installation of popup and route-interception hooks.
Requirements
- Node.js
>=22.22
- ES modules — the package is ESM-only (
"type": "module"). Import it from
ESM code and use explicit .js specifiers in relative imports.
- Peer dependencies
@qawolf/flows — used by EntryPointPageObject to launch the browser.
playwright — for the Page / Locator types your page objects use.
Install
Defining a page object
Extend BasePageObject. It stores the Playwright Page (available as
this.page) and provides this.create(...) for constructing other page
objects. Keep selectors in a private locators getter.
The page registry
Registering
Create one module that registers every page object, and import it for its side
effects before you construct any page object. Register lazily with a module
loader so a page object’s module is only loaded when it is first used:
The loader must resolve to a module that exports the class under the same
name it was registered with. Eager registration also works when you already
hold the class value:
Constructing
createPage builds a registered page object for a given Page. Import the
registration module first so the registry is populated:
Inside a page object, use the protected this.create(...) instead — it shares
the current Page and routes through the same registry, which is what lets
page objects reference each other without importing each other’s classes as
values (avoiding circular imports). Use import type only for annotations:
create / createPage are async because lazily registered modules load on
first use.
Typing this.create(...)
By default this.create("LoginPage") returns any. Augment the
RegisteredPages interface — declared for exactly this purpose — to make the
name-to-type mapping known, and create becomes fully typed. This is
incremental: names you don’t list keep the any fallback.
Now await this.create("LoginPage") is typed as LoginPage.
Entry points and page hooks
An entry point is the page object that owns browser startup. Extend
EntryPointPageObject and expose a create() that launches the browser
(initializeBrowser), builds the instance (createFromPage), and installs
page hooks:
A page object can own popups to auto-dismiss or routes to intercept by
overriding popupHandlers() / routeInterceptors() on its class:
installPageHooks() collects these across every registered page object,
not just the entry point. Overrides are detected by an own-property check on the
registered class’s prototype, so declare popupHandlers() /
routeInterceptors() directly on the class you register — an override inherited
from a base class is not picked up.
When registering lazily, pass { providesPageHooks: false } for page objects
you know declare no hooks, so hook installation can skip loading their modules:
Exports
Last modified on July 7, 2026