Belajar QA Automation Engineer - Page Object Model (POM)
Episode 7 of 28

Belajar QA Automation Engineer - Page Object Model (POM)

Menerapkan Page Object Model untuk maintainability: page objects, abstraction layers, selectors terpusat, dan refactor test suite yang scalable

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Setelah di episode 6 kita memahami Cypress vs Playwright, pada episode ini kita membahas pattern paling penting untuk maintainability: Page Object Model (POM). Tanpa POM, test suite menjadi sulit dipelihara saat aplikasi berkembang.

Apa itu POM?

POM memisahkan locator/interaction dari test logic. Setiap halaman web di-representasikan sebagai class yang berisi selectors dan methods untuk berinteraksi dengan halaman tersebut.

Without POM (BAD)

javascript
// Test langsung pakai selectors — sulit dipelihara
test('login', async ({ page }) => {
  await page.goto('http://localhost:3000/login');
  await page.fill('#email-input', 'user@test.com');
  await page.fill('#password-field', 'password123');
  await page.click('button[type="submit"]');
  await expect(page).toHaveURL('/dashboard');
});
 
// Jika #email-input berubah, harus update di SEMUA tests

With POM (GOOD)

typescript
// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test';
 
export class LoginPage {
  readonly page: Page;
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;
  readonly errorMessage: Locator;
 
  constructor(page: Page) {
    this.page = page;
    this.emailInput = page.getByRole('textbox', { name: 'Email' });
    this.passwordInput = page.getByRole('textbox', { name: 'Password' });
    this.submitButton = page.getByRole('button', { name: 'Login' });
    this.errorMessage = page.locator('.error-message');
  }
 
  async goto() {
    await this.page.goto('/login');
  }
 
  async login(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }
}
typescript
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
 
test('login with valid credentials', async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.goto();
  await loginPage.login('user@test.com', 'password123');
  await expect(page).toHaveURL('/dashboard');
});

POM Structure

text
project/
├── pages/
│   ├── LoginPage.ts
│   ├── DashboardPage.ts
│   ├── ProductsPage.ts
│   ├── CartPage.ts
│   └── CheckoutPage.ts
├── tests/
│   ├── login.spec.ts
│   ├── dashboard.spec.ts
│   └── checkout.spec.ts
└── playwright.config.ts

Advanced POM

Inheritance

typescript
// pages/BasePage.ts
export class BasePage {
  readonly page: Page;
 
  constructor(page: Page) {
    this.page = page;
  }
 
  async waitForLoading() {
    await this.page.locator('.loading').waitFor({ state: 'hidden' });
  }
 
  async getAlertMessage(): Promise<string> {
    return this.page.locator('.alert').textContent() ?? '';
  }
}
 
// pages/LoginPage.ts
export class LoginPage extends BasePage {
  // Inherits BasePage methods
}

Chain Methods

typescript
// Return this untuk method chaining
async fillEmail(email: string) {
  await this.emailInput.fill(email);
  return this;
}
 
async fillPassword(password: string) {
  await this.passwordInput.fill(password);
  return this;
}
 
// Usage
await loginPage.fillEmail('user@test.com')
  .fillPassword('password123')
  .submit();

Tip

POM bukan hanya tentang selectors — juga tentang business logic. Methods seperti login() atau addToCart() mengabstract complexity test.

Praktik: Refactor to POM

typescript
// Refactor existing test ke POM
// 1. Buat page class
// 2. Pindahkan selectors ke page class
// 3. Buat methods untuk interactions
// 4. Update tests untuk use page class
// 5. Verify tests still pass

Penutup

  • POM: separate locator dari test logic → maintainable.
  • Benefits: single source of truth, reusable, readable tests.
  • Structure: one class per page, methods untuk interactions.
  • Advanced: inheritance, chain methods, base page.

Di episode 8 selanjutnya kita akan membahas API testing automation — request/test frameworks, contract testing, dan mocking. Sampai jumpa di episode 8!

Belajar QA Automation Engineer - Page Object Model (POM) | Belajar QA Automation Engineer