The failure mode of classic POM
Teams create one class per page, then add a method for every possible interaction. After a year you have 3,000-line classes full of methods called once. The model is not wrong, the granularity is.
A practical structure for automation frameworks that stays readable after two hundred tests.
Teams create one class per page, then add a method for every possible interaction. After a year you have 3,000-line classes full of methods called once. The model is not wrong, the granularity is.
Real applications are composed of a header, a filter bar, a data table and a modal. Model those. A page object then becomes a thin composition of component objects, and a table component written once is reused by every screen that renders a table.
class DataTable {
constructor(private root: Locator) {}
row(name: string) { return this.root.getByRole('row', { hasText: name }); }
async sortBy(column: string) {
await this.root.getByRole('columnheader', { name: column }).click();
}
}A page object exposes state and actions. The test decides what is correct. Mixing assertions into the object makes them impossible to reuse in a negative scenario.
Tests, components/pages, and a small utility layer for data setup and API helpers. Anything more usually means the framework is being designed for problems the team does not have yet.
Book a free demo class and work through these patterns with a mentor.