</>

Technology

Playwright

Difficulty

Intermediate

Interview Question

How do you implement Page Object Model (POM) in Playwright with TypeScript?

Answer

Page Object Model in Playwright with TypeScript

The Page Object Model pattern separates element locators and actions from test logic, making tests readable and maintainable.

Base Page Class (Optional but Recommended)

TypeScript
// pages/BasePage.ts
import { Page } from '@playwright/test';

export abstract class BasePage {
  constructor(protected page: Page) {}

  async navigate(path: string): Promise<void> {
    await this.page.goto(path);
  }

  async waitForPageLoad(): Promise<void> {
    await this.page.waitForLoadState('domcontentloaded');
  }
}

Login Page Object

TypeScript
// pages/LoginPage.ts
import { Page, Locator, expect } from '@playwright/test';
import { BasePage } from './BasePage';

export class LoginPage extends BasePage {
  // Locators as properties
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly signInButton: Locator;
  readonly errorMessage: Locator;
  readonly forgotPasswordLink: Locator;

  constructor(page: Page) {
    super(page);
    this.emailInput        = page.getByLabel('Email');
    this.passwordInput     = page.getByLabel('Password');
    this.signInButton      = page.getByRole('button', { name: 'Sign in' });
    this.errorMessage      = page.getByTestId('error-message');
    this.forgotPasswordLink = page.getByRole('link', { name: 'Forgot Password?' });
  }

  async goto(): Promise<void> {
    await this.page.goto('/login');
  }

  async login(email: string, password: string): Promise<void> {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.signInButton.click();
  }

  async expectError(message: string): Promise<void> {
    await expect(this.errorMessage).toBeVisible();
    await expect(this.errorMessage).toContainText(message);
  }
}

Dashboard Page Object

TypeScript
// pages/DashboardPage.ts
import { Page, Locator, expect } from '@playwright/test';
import { BasePage } from './BasePage';

export class DashboardPage extends BasePage {
  readonly welcomeHeading: Locator;
  readonly userAvatar: Locator;
  readonly logoutButton: Locator;
  readonly navItems: Locator;

  constructor(page: Page) {
    super(page);
    this.welcomeHeading = page.getByRole('heading', { name: /Welcome/ });
    this.userAvatar     = page.getByTestId('user-avatar');
    this.logoutButton   = page.getByRole('button', { name: 'Logout' });
    this.navItems       = page.locator('nav a');
  }

  async goto(): Promise<void> {
    await this.page.goto('/dashboard');
  }

  async logout(): Promise<void> {
    await this.logoutButton.click();
    await expect(this.page).toHaveURL('/login');
  }

  async expectUserLoggedIn(name: string): Promise<void> {
    await expect(this.welcomeHeading).toContainText(name);
    await expect(this.userAvatar).toBeVisible();
  }
}

Test Using Page Objects

TypeScript
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
import { DashboardPage } from '../pages/DashboardPage';

test.describe('Login Flow', () => {
  let loginPage: LoginPage;
  let dashboardPage: DashboardPage;

  test.beforeEach(async ({ page }) => {
    loginPage    = new LoginPage(page);
    dashboardPage = new DashboardPage(page);
    await loginPage.goto();
  });

  test('valid login navigates to dashboard', async () => {
    await loginPage.login('user@test.com', 'pass123');
    await expect(loginPage.page).toHaveURL('/dashboard');
    await dashboardPage.expectUserLoggedIn('Jane');
  });

  test('invalid credentials shows error', async () => {
    await loginPage.login('wrong@test.com', 'wrongpass');
    await loginPage.expectError('Invalid credentials');
  });

  test('user can logout', async () => {
    await loginPage.login('user@test.com', 'pass123');
    await dashboardPage.logout();
    await expect(loginPage.page).toHaveURL('/login');
  });
});

Project Structure

CODE
playwright-project/
ā”œā”€ā”€ pages/
│   ā”œā”€ā”€ BasePage.ts
│   ā”œā”€ā”€ LoginPage.ts
│   ā”œā”€ā”€ DashboardPage.ts
│   └── ProductPage.ts
ā”œā”€ā”€ tests/
│   ā”œā”€ā”€ login.spec.ts
│   └── products.spec.ts
ā”œā”€ā”€ fixtures.ts
└── playwright.config.ts

Follow AutomateQA

Related Topics