Page Object Model (POM) является фундаментальной концепцией при автоматизации тестирования веб-приложений. Она направлена на структурирование кода тестов, улучшение читаемости и уменьшение дублирования. Одним из ключевых аспектов POM является композиция Page Objects, которая позволяет строить более гибкую, поддерживаемую и модульную архитектуру тестов.
Композиция Page Objects заключается в том, что один объект страницы может включать в себя другие объекты, представляющие логические или визуальные компоненты страницы. Это особенно важно для крупных приложений, где одна страница состоит из нескольких повторяющихся блоков, таких как формы, таблицы, меню или виджеты.
Преимущества композиции:
В Protractor базовый компонент часто создается как отдельный класс или модуль, инкапсулирующий локаторы и методы работы с элементами.
class InputField {
constructor(locator) {
this.field = element(locator);
}
async enterText(text) {
await this.field.clear();
await this.field.sendKeys(text);
}
async getValue() {
return this.field.getAttribute('value');
}
}
В этом примере InputField представляет собой
компонент ввода текста, который можно использовать на
любой странице, где есть текстовое поле.
Композиция становится полезной, когда Page Object использует несколько таких компонентов для представления сложной страницы.
class LoginPage {
constructor() {
this.usernameInput = new InputField(by.id('username'));
this.passwordInput = new InputField(by.id('password'));
this.loginButton = element(by.buttonText('Login'));
}
async login(username, password) {
await this.usernameInput.enterText(username);
await this.passwordInput.enterText(password);
await this.loginButton.click();
}
}
Здесь LoginPage композирует два объекта
InputField, представляя логическую структуру страницы. Такой
подход улучшает читаемость и позволяет переиспользовать
InputField на других страницах.
Для более крупных страниц часто применяются вложенные компоненты. Например, таблица с пагинацией и фильтрацией может быть выделена в отдельный объект, который затем используется в Page Object страницы:
class TableComponent {
constructor(tableLocator) {
this.table = element(tableLocator);
}
async getRowText(rowIndex) {
return this.table.all(by.css('tr')).get(rowIndex).getText();
}
async clickRow(rowIndex) {
await this.table.all(by.css('tr')).get(rowIndex).click();
}
}
class UsersPage {
constructor() {
this.userTable = new TableComponent(by.id('usersTable'));
this.addUserButton = element(by.id('addUser'));
}
async addUser() {
await this.addUserButton.click();
}
async getUserName(rowIndex) {
return this.userTable.getRowText(rowIndex);
}
}
Преимущества такого подхода:
При использовании композиции важно правильно управлять локаторами, чтобы обеспечить изоляцию компонентов. Обычно каждый компонент получает локатор корневого элемента, относительно которого определяются дочерние элементы.
class ModalDialog {
constructor(rootLocator) {
this.root = element(rootLocator);
this.title = this.root.element(by.css('.modal-title'));
this.closeButton = this.root.element(by.css('.close'));
}
async getTitle() {
return this.title.getText();
}
async close() {
await this.closeButton.click();
}
}
Такой подход позволяет:
В Protractor все операции с элементами являются асинхронными. При
композиции важно правильно использовать
async/await в методах компонентов и Page
Object:
async loginAndVerify(username, password, expectedName) {
await this.loginPage.login(username, password);
const actualName = await this.dashboardPage.getUserName();
expect(actualName).toEqual(expectedName);
}
Неправильное управление асинхронностью может привести к нестабильным тестам и ошибкам, связанным с обращением к элементам до их появления на странице.
click, sendKeys).Композиция Page Objects позволяет создавать чистую и поддерживаемую структуру тестов, делая их легко расширяемыми и стабильными при изменении интерфейса. Правильное применение этого подхода существенно повышает качество автоматизации и ускоряет работу над тестами.