Page Object Model (POM) — это паттерн проектирования, который используется для улучшения структуры тестов в автоматизированном тестировании. В контексте тестирования с Playwright, он помогает создать абстракцию для взаимодействия с веб-страницами, что делает код более поддерживаемым, читаемым и масштабируемым. Вместо того чтобы каждый раз повторно писать код для поиска элементов на странице и взаимодействия с ними, POM организует это в отдельные объекты, представляющие страницы, что снижает дублирование кода и улучшает его поддержку.
Каждая веб-страница или её компонент представляет собой отдельный объект. Эти объекты инкапсулируют все действия и элементы на странице, предоставляя методы для взаимодействия с ними.
В Playwright Page Object Model можно реализовать следующим образом:
// LoginPage.js
class LoginPage {
constructor(page) {
this.page = page;
this.usernameField = page.locator('#username');
this.passwordField = page.locator('#password');
this.loginButton = page.locator('#login');
}
async login(username, password) {
await this.usernameField.fill(username);
await this.passwordField.fill(password);
await this.loginButton.click();
}
}
module.exports = LoginPage;
В данном примере LoginPage инкапсулирует все действия,
связанные с авторизацией, а именно ввод имени пользователя и пароля, а
также клик по кнопке входа.
Повторное использование кода Page Object Model способствует повторному использованию кода. Элементы и действия, которые выполняются на одной странице, можно использовать в различных тестах, что предотвращает дублирование и упрощает поддержку.
Читаемость тестов Поскольку тесты работают с абстракциями, а не с конкретными деталями реализации страницы, их становится проще читать и поддерживать. Методы в объекте страницы имеют имена, которые логично описывают действия, что делает код более осмысленным.
Изоляция изменений Если структура страницы изменится, необходимо обновить только Page Object, а не все тесты. Это уменьшает количество изменений в тестах и улучшает их стабильность.
Упрощение тестов Поскольку взаимодействие с веб-страницей вынесено в отдельные методы, тесты становятся компактными и фокусируются только на логике тестирования.
Рассмотрим типичную структуру проекта с использованием Playwright и Page Object Model:
/tests
/login
login.spec.js
/pages
LoginPage.js
login.spec.js — файл с тестами.LoginPage.js — объект страницы с методами для работы с
элементами на странице авторизации.// login.spec.js
const { test, expect } = require('@playwright/test');
const LoginPage = require('../pages/LoginPage');
test('User can log in with valid credentials', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login('user1', 'password123');
// Проверка, что пользователь успешно вошел
await expect(page.locator('text=Welcome, user1')).toBeVisible();
});
В этом примере тест выполняет следующие шаги:
LoginPage.Единая точка изменения В идеале, каждый элемент страницы (например, кнопки, поля ввода) должен быть представлен как локатор в объекте страницы. Это позволяет централизованно изменять локаторы при изменении структуры страницы.
Методы страницы должны быть абстракциями Методы
в Page Object не должны быть привязаны к конкретной реализации теста.
Например, метод login() должен просто выполнять вход на
страницу, не заботясь о том, что именно тест проверяет.
Минимизация логики в тестах Логика тестов должна быть как можно проще. Тесты не должны содержать детализированную информацию о том, как именно взаимодействовать с элементами страницы — всё это скрыто в Page Object.
В более крупных проектах, когда страницы становятся сложными, рекомендуется разделять страницы на несколько объектов, каждый из которых отвечает за часть страницы. Например, если страница имеет несколько разделов, каждый раздел можно реализовать как отдельный Page Object.
// HeaderPage.js
class HeaderPage {
constructor(page) {
this.page = page;
this.profileButton = page.locator('#profile');
this.logoutButton = page.locator('#logout');
}
async logout() {
await this.logoutButton.click();
}
}
module.exports = HeaderPage;
// LoginPage.js
class LoginPage {
constructor(page) {
this.page = page;
this.usernameField = page.locator('#username');
this.passwordField = page.locator('#password');
this.loginButton = page.locator('#login');
}
async login(username, password) {
await this.usernameField.fill(username);
await this.passwordField.fill(password);
await this.loginButton.click();
}
}
module.exports = LoginPage;
// login.spec.js
const { test, expect } = require('@playwright/test');
const LoginPage = require('../pages/LoginPage');
const HeaderPage = require('../pages/HeaderPage');
test('User can log in and log out', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login('user1', 'password123');
const headerPage = new HeaderPage(page);
await headerPage.logout();
await expect(page.locator('text=Login')).toBeVisible();
});
Локаторы являются важной частью Page Object Model. В Playwright есть несколько способов найти элементы: через CSS-селекторы, текстовые значения, атрибуты и т. д. Рекомендуется использовать наиболее стабильные селекторы, чтобы минимизировать риск того, что тесты будут ломаться при изменениях на веб-странице.
// Пример локатора через CSS-селектор
this.usernameField = page.locator('#username');
// Пример локатора через текст
this.loginButton = page.locator('text=Login');
Для взаимодействия с элементами страницы в Playwright существуют
методы, такие как click(), fill(),
selectOption(), check(),
uncheck(). Каждый метод выполняет действия, соответствующие
ожидаемому результату.
class LoginPage {
async login(username, password) {
await this.usernameField.fill(username);
await this.passwordField.fill(password);
await this.loginButton.click();
}
}
В этом примере метод fill() заполняет поле ввода, а
click() выполняет клик по кнопке.
Playwright работает в асинхронном режиме, и все взаимодействия с элементами страницы являются асинхронными. Методы, которые изменяют состояние страницы, должны быть асинхронными, и тесты должны ожидать завершения этих действий.
class LoginPage {
async login(username, password) {
await this.usernameField.fill(username);
await this.passwordField.fill(password);
await this.loginButton.click();
}
}
Каждый метод, взаимодействующий с элементами, выполняется с
await, чтобы гарантировать правильный порядок
выполнения.
Одной из важных особенностей при работе с Playwright является управление ожиданиями. Иногда действия, такие как клик или ввод данных, могут не выполняться мгновенно из-за загрузки страницы или асинхронных операций. Playwright предоставляет различные методы ожидания, чтобы гарантировать, что элементы готовы к взаимодействию.
// Пример ожидания появления элемента
await this.page.waitForSelector('#dashboard', { state: 'visible' });
Этот код будет ожидать, пока элемент с id dashboard не
станет видимым.
Использование Page Object Model в тестировании с Playwright значительно упрощает организацию тестов, повышает их поддерживаемость и читаемость. Этот паттерн позволяет изол