05 / 10
Page Object
Locator'ları ve akışları sayfa nesnelerinde toplamak, Page Object'e ne konur ne konmaz, assertion tartışması, bileşen nesneleri ve aşırı soyutlamadan kaçınmak.
Sorun: Tekrar Eden Locator'lar
Giriş akışını test eden on test düşünün. Her biri e-posta alanını, parola alanını ve butonu kendisi bulur. Buton metni "Giriş yap"tan "Oturum aç"a değişince on dosyayı düzeltirsiniz.
Page Object bu tekrarı bir sınıfta toplar. Playwright dokümanı iki faydasını sayar: uygulamanıza uygun, üst seviye bir API ile testi yazmayı kolaylaştırır; locator'ları tek yerde toplayarak bakımı kolaylaştırır.1
Martin Fowler kalıbın amacını şöyle anlatır: Page Object, bir insanın sayfada yapabildiği ve görebildiği her şeyi test koduna sunar, alttaki HTML ayrıntısını gizler. Test "e-posta alanına yaz" der; alanın nasıl bulunduğunu bilmez.2
İlk Page Object
// tests/pages/login-page.ts
import type { Locator, Page } from "@playwright/test";
export class LoginPage {
readonly email: Locator;
readonly password: Locator;
readonly submit: Locator;
readonly error: Locator;
constructor(private readonly page: Page) {
const form = page.getByRole("form", { name: "Giriş" });
this.email = form.getByLabel("E-posta");
this.password = form.getByLabel("Parola");
this.submit = form.getByRole("button", { name: "Giriş yap" });
this.error = form.getByRole("alert");
}
async goto() {
await this.page.goto("/login");
}
async login(email: string, password = "parola123") {
await this.email.fill(email);
await this.password.fill(password);
await this.submit.click();
}
}İki tür üye var:
Locator alanları (
email,error): testin doğrulayacağı ya da tek başına kullanacağı elementler. Locator oluşturmak sayfaya dokunmadığı için constructor'da tanımlamak güvenlidir (bkz. İlk test ve locator'lar).Eylem metodları (
goto,login): birkaç adımdan oluşan, kullanıcının diliyle adlandırılmış akışlar.
Test artık niyeti okur:
// tests/login.spec.ts
import { test, expect } from "@playwright/test";
import { LoginPage } from "./pages/login-page";
test("hatalı parola hata mesajı gösterir ve e-postayı korur", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("yonetici@example.com", "yanlis");
await expect(loginPage.error).toHaveText("E-posta veya parola hatalı.");
await expect(loginPage.email).toHaveValue("yonetici@example.com");
});Satıra ve Listeye Metod
Tabloda belirli bir satır gibi parametreli elementler için locator döndüren bir metod yazın:
// tests/pages/orders-page.ts
export class OrdersPage {
readonly table: Locator;
readonly rows: Locator;
readonly statusFilter: Locator;
constructor(private readonly page: Page) {
this.table = page.getByRole("table", { name: "Sipariş listesi" });
this.rows = this.table.getByRole("row").filter({ has: page.getByRole("cell") });
this.statusFilter = page.getByLabel("Durum");
}
row(orderId: string) {
return this.rows.filter({ hasText: orderId });
}
async filterBy(label: string) {
await this.statusFilter.selectOption({ label });
}
async cancel(orderId: string) {
await this.row(orderId).getByRole("button", { name: "İptal et" }).click();
}
}row("SP-1001") hem eylemde (cancel) hem assertion'da kullanılır:
await expect(ordersPage.row("SP-1001")).toContainText("İptal edildi");Assertion Page Object'e Girer mi?
İki görüş var.
Martin Fowler Page Object'in assertion yapmamasını savunur. Görevi sayfanın durumunu sunmaktır; doğrulama testin işidir. Tek istisna, sayfanın her zaman doğru olması gereken bir değişmezini kontrol etmektir.2 Playwright dokümanının örneğinde ise bir eylem metodu expect ile bir sonraki sayfanın açıldığını doğrular.1
Pratik bir ayrım:
| Page Object'e | Teste |
|---|---|
| Eylemin tamamlandığını beklemek (sonraki sayfa geldi mi) | Testin asıl iddiası (mesaj doğru mu, satır iptal edildi mi) |
| Locator ve eylem | Senaryoya özel beklenen değerler |
Testi okuyan kişi neyin doğrulandığını Page Object'e girmeden görebilmelidir. "Asıl iddia testte" kuralı bunu sağlar.
Sayfa Değil, Anlamlı Parça
Adına rağmen Page Object sayfayla birebir eşleşmek zorunda değildir. Martin Fowler sayfadaki anlamlı parçalar için nesne yazmayı önerir: bir albüm listesi sayfası birkaç albüm nesnesi, bir üst bilgi ve bir alt bilgi nesnesi içerebilir.2 Her sayfada tekrar eden bir gezinme menüsü ya da bir tarih seçici kendi nesnesini hak eder:
export class DatePicker {
constructor(private readonly root: Locator) {}
async pick(day: number) {
await this.root.getByRole("button", { name: "Takvimi aç" }).click();
await this.root.getByRole("gridcell", { name: String(day), exact: true }).click();
}
}Kök bir Locator alan nesne sayfanın neresinde olursa olsun çalışır: new DatePicker(page.getByRole("group", { name: "Teslim tarihi" })).
Aşırı Soyutlamadan Kaçının
Page Object bir araçtır, hedef değil. Sık görülen hatalar:
Her elemente metod:
clickSubmitButton(),getEmailInput(). Locator alanını açın;loginPage.submit.click()yeterince okunur.Tek kullanımlık akışlar: Yalnızca bir testte geçen adımı Page Object'e taşımak tekrar azaltmaz, sadece testi okumayı zorlaştırır.
Locator'ı gizleyip boolean döndürmek:
isErrorVisible(): Promise<boolean>web-first assertion'ın beklemesini kaybettirir (bkz. Assertion ve bekleme). Locator döndürün, testteexpectile doğrulayın.
Playwright dokümanı da basit testlerde biraz tekrarın kabul edilebilir olduğunu, okunurluğu artırıyorsa tercih edilebileceğini söyler.3
Tip
Playwright dokümanının Page Object örneği locator'ları page.locator("a", { hasText: "Get started" }) ve CSS seçicilerle yazar. Kalıbı oradan öğrenin, locator'ları bu rehberdeki gibi getByRole ve getByLabel ile yazın.1
Her Testte new Yazmamak
Her testin başında new LoginPage(page) yazmak da bir tekrardır. Bir sonraki derste Page Object'leri fixture olarak vereceğiz; test parametresinde hazır gelecekler:
test("hatalı parola", async ({ loginPage }) => {
await loginPage.goto();
});Kendin Dene
Giriş testlerinizdeki locator'ları bir
LoginPagesınıfına taşıyın. Buton metnini değiştirip kaç dosyayı düzeltmeniz gerektiğine bakın.Bir tablo için
row(id)metodu yazın ve hem bir eylemde hem bir assertion'da kullanın.Sayfanızda tekrar eden bir parça bulun (menü, arama kutusu) ve kök
Locatoralan bir bileşen nesnesi yazın.Page Object'lerinizdeki
Promise<boolean>döndüren metodları bulun ve locator döndürecek şekilde değiştirin.
Detaylı Öğrenmek İçin
Resmi doküman: Playwright, "Page object models"; Playwright'ta kalıbın uygulanışı.1
Yazı: Martin Fowler, "Page Object"; kalıbın amacı, assertion tartışması ve parçalara bölmek.2
Kaynaklar
Page Object sınıfı, locator alanları ve testte kullanımı.
: — 10 Eylül 2013. Kalıbın amacı, assertion'ların yeri, parçalara bölmek ve başka Page Object döndürmek.
Test izolasyonu ve basit testlerde tekrarın kabul edilebilirliği.
Last updated: October 22, 2026
