Manuals / Test Automation / Ch 8

C · StructureIntermediate65 min read

8. Page objects, data, and waits

Test Automation · 48 pages source format

Structure is kindness to future-you. Hide selectors behind intent, seed data via API, and wait for conditions — never sleep.

What you'll learn

  • POM / screenplay ideas
  • Fixture data
  • Deterministic waits

Extract a page object

Methods named like user intent: loginAs(user), addItem(name). Selectors live in one place.

// Conceptual POM
class LoginPage {
  constructor(page) { this.page = page; }
  async loginAs(user, pass) {
    await this.page.getByPlaceholder("Username").fill(user);
    await this.page.getByPlaceholder("Password").fill(pass);
    await this.page.getByRole("button", { name: "Login" }).click();
  }
}

Do this now

Refactor your login test into a LoginPage with loginAs(username, password) method.

Clear?

Data without shared pollution

Unique emails, API create/delete, or transactional resets. Shared “admin” users create ghosts.

Do this now

Generate a unique user per run (timestamp or uuid). Document data strategy in DATA.md.

Pro tip. Prefer API setup + UI assert for speed.

Clear?

Ban hard sleeps

Wait for network idle, element visible, or response. Sleeps hide races until CI load exposes them.

Do this now

Find any waitForTimeout/sleep/Thread.sleep. Replace with a condition wait. Zero tolerance policy.

Clear?

Test isolation

Each test should setup and teardown its own state. Order-dependent suites are debt.

Do this now

Run your tests in random order. Fix any that fail when shuffled.

Clear?

Checklist