Page Object Model
Когда тестов становится много, локаторы и действия выносят в отдельные классы — это паттерн Page Object.
Page Object Model (POM) — паттерн, при котором каждая страница приложения описывается классом: внутри — её локаторы и действия, а тесты вызывают понятные методы.
Проблема, которую решает POM
Допустим, локатор кнопки входа повторяется в двадцати тестах. Дизайнер переименовал кнопку — придётся править двадцать мест. А если каждый тест ещё и сам прописывает шаги входа, дублирование разрастается. POM собирает всё, что связано со страницей, в одном месте, и тесты перестают зависеть от деталей вёрстки.
Как выглядит Page Object
Класс страницы хранит ссылку на page, объявляет локаторы и предоставляет методы-действия с понятными именами.
// pages/LoginPage.ts
import { Page, Locator, expect } 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.getByLabel('Email');
this.passwordInput = page.getByLabel('Пароль');
this.submitButton = page.getByRole('button', { name: 'Войти' });
this.errorMessage = page.getByRole('alert');
}
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();
}
async expectError(text: string) {
await expect(this.errorMessage).toHaveText(text);
}
}Тест становится читаемым
Теперь тест говорит о поведении, а не о кнопках и полях. Технические детали спрятаны в Page Object.
import { test } from '@playwright/test';
import { LoginPage } from './pages/LoginPage';
test('ошибка при неверном пароле', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login('[email protected]', 'wrong-password');
await loginPage.expectError('Неверный email или пароль');
});Чем это хорошо
| Свойство | Польза |
| Локаторы в одном месте | смена вёрстки — правка одного файла |
| Понятные методы | тест читается как сценарий |
| Переиспользование | login() вызывается из многих тестов |
Когда POM нужен, а когда нет
POM окупается, когда тестов много и они работают с одними и теми же страницами. Для пары простых тестов он избыточен — добавит слоёв без пользы. Не превращайте Page Object в «свалку»: метод вроде fillEmailThenClickSubmitThenWait() — признак того, что вы складываете в класс саму логику теста. Page Object описывает страницу (какие на ней элементы и какие базовые действия), а сценарий — что и в каком порядке проверять — остаётся в тесте.
POM и фикстуры вместе
На практике Page Object часто отдают через фикстуру из прошлого урока — тогда тест получает готовый объект страницы и не создаёт его вручную. Это сочетание двух приёмов: фикстура управляет жизненным циклом, Page Object — структурой страницы.
Итог
- POM выносит локаторы и действия страницы в отдельный класс.
- Тесты вызывают понятные методы (
login,expectError) вместо повторения локаторов. - Смена вёрстки правится в одном месте — в классе страницы.
- Применяйте POM при большом числе тестов; не складывайте в него логику сценариев.