Sparround

Classes and OOP basics

A class is a template that keeps data (fields) and behaviour (methods) together. In test automation the main use of classes is the Page Object Model: one class per page, locators as fields, user operations as methods.

The core elements:

  • class LoginPage { ... } — the declaration
  • constructor(page) — setup that runs once when the object is created, on new LoginPage(page)
  • Methods — async login(user, pass) { ... }
  • Fields — this.email = ...
  • Private fields#token (native JavaScript) or private token (TypeScript): inaccessible from outside
  • static members — called on the class without an instance: TestData.defaultUser()
ConstructWhat it doesExample in a POM
constructor(page)prepares locators when the object is createdthis.submit = page.getByRole('button')
extends / super()inherits from another class; super() calls the parent constructorclass LoginPage extends BasePage
#privateFieldvisible only inside the class#baseUrl — tests cannot touch it
static methodcalled without an instanceTestUser.random()
arrow class fieldbinds this to the instance permanentlyget = (path) => fetch(...)

Inheritance or composition?

Inheritance expresses "X is a kind of Y": LoginPage extends BasePage. The benefit is obvious (shared open(), waitForLoad() in one place), but a deep hierarchy (3+ levels) makes a POM heavy: finding where a method is defined gets hard, and a change in the parent unexpectedly breaks every page.

Composition expresses "X has a Y": inside LoginPage, this.header = new HeaderComponent(page). For reusable UI components (header, modal, table, filter panel) composition is exactly the right choice.

A practical rule: one level of BasePage inheritance plus composition for everything else. That is the balance that works for most teams.

The `this` trap — a very common interview topic. When you detach a method from its object and pass it as a callback (items.map(api.get)), this is lost and becomes undefined. Three fixes: wrap it in an arrow (p => api.get(p)), use api.get.bind(api), or write the class field as an arrow (get = (p) => ...).

A second rule for POMs: page object methods should expose actions, not assertions. Keep assertions in the test file — then reading the test tells you what it verifies.

📚 Sources and documentation