Page Object Model (POM) — один из ключевых паттернов в автоматизированном тестировании, позволяющий структурировать код так, чтобы тесты оставались читаемыми, поддерживаемыми и масштабируемыми. В WebdriverIO POM реализуется через классы и модули, которые инкапсулируют работу с конкретными страницами или компонентами интерфейса.
Каждая страница приложения должна иметь отдельный класс, который содержит:
Селекторы элементов Селекторы инкапсулируются в геттеры. Это упрощает их переиспользование и изменение при обновлении UI.
class LoginPage {
get inputUsername() { return $('#username'); }
get inputPassword() { return $('#password'); }
get btnSubmit() { return $('button[type="submit"]'); }
}Методы действий Методы класса выполняют действия над элементами страницы, скрывая детали взаимодействия. Методы должны быть атомарными, с одной логической задачей.
async login(username, password) {
await this.inputUsername.setValue(username);
await this.inputPassword.setValue(password);
await this.btnSubmit.click();
}Методы проверки состояния Для улучшения читаемости тестов полезно включать методы, возвращающие состояние страницы.
async isLoginButtonEnabled() {
return this.btnSubmit.isEnabled();
}login(),
openDashboard().class HeaderComponent {
get profileMenu() { return $('#profileMenu'); }
async openProfile() {
await this.profileMenu.click();
}
}
Использование компонент повышает переиспользуемость кода и снижает дублирование.
Инкапсуляция селекторов Никогда не использовать селекторы напрямую в тестах. Все селекторы должны быть внутри Page Object.
Минимизация логики в тестах Тесты должны
описывать сценарии на высоком уровне:
loginPage.login('user', 'pass'), а не управлять каждым
полем отдельно.
Согласованное именование методов Использовать
глаголы, отражающие действие: click, open,
fill, submit. Это улучшает
читаемость.
Возвращение Page Objects при навигации Методы, которые ведут на другую страницу, должны возвращать новый экземпляр соответствующего Page Object:
async goToDashboard() {
await $('a[href="/dashboard"]').click();
return new DashboardPage();
}Асинхронность Все методы взаимодействия с
элементами должны использовать async/await. Это
предотвращает проблемы с таймингами и синхронизацией.
/tests
/specs
login.spec.js
dashboard.spec.js
/pages
login.page.js
dashboard.page.js
/components
header.component.js
footer.component.js
Переиспользование общих компонентов Общие элементы, такие как хедер или футер, выносятся в отдельные компоненты. Страницы импортируют их для взаимодействия.
Файлы конфигурации и константы URL страниц,
тестовые данные и часто используемые селекторы можно хранить в отдельном
файле constants.js, чтобы избежать жесткой привязки к
данным.
Обработка динамических элементов:
class TableComponent {
get rows() { return $$('table tbody tr'); }
async getRowByText(text) {
for (const row of await this.rows) {
if ((await row.getText()).includes(text)) {
return row;
}
}
return null;
}
}
Композиция Page Objects:
class DashboardPage {
constructor() {
this.header = new HeaderComponent();
this.footer = new FooterComponent();
}
async openUserProfile() {
await this.header.openProfile();
}
}
Page Object Model в WebdriverIO обеспечивает масштабируемость и поддержку тестовой инфраструктуры. Строгое следование принципам инкапсуляции, разделения компонентов и асинхронности позволяет создавать надежные и легко читаемые автотесты.