В автоматизированном тестировании на Protractor управление состоянием является ключевым аспектом для обеспечения стабильности и предсказуемости тестов. Page Object — это паттерн, позволяющий абстрагировать взаимодействие с элементами страницы, а также контролировать их состояние, уменьшая дублирование кода и повышая читаемость тестов.
Page Object обычно содержит свойства, соответствующие элементам страницы. Для управления состоянием рекомендуется использовать геттеры, возвращающие элемент с проверкой его доступности:
class LoginPage {
constructor() {
this.usernameField = element(by.id('username'));
this.passwordField = element(by.id('password'));
this.loginButton = element(by.id('loginBtn'));
}
async getUsernameField() {
await browser.wait(protractor.ExpectedConditions.visibilityOf(this.usernameField), 5000);
return this.usernameField;
}
async getLoginButton() {
await browser.wait(protractor.ExpectedConditions.elementToBeClickable(this.loginButton), 5000);
return this.loginButton;
}
}
Использование ExpectedConditions позволяет
гарантировать, что элемент готов к взаимодействию,
прежде чем выполнять действия.
Для форм и интерактивных элементов важно хранить и отслеживать состояние данных. В Page Object можно создать методы для чтения, установки и проверки значений полей:
class LoginPage {
async setUsername(username) {
const field = await this.getUsernameField();
await field.clear();
await field.sendKeys(username);
}
async getUsername() {
const field = await this.getUsernameField();
return field.getAttribute('value');
}
async setPassword(password) {
const field = await this.passwordField;
await field.clear();
await field.sendKeys(password);
}
}
Такой подход позволяет изолировать логику работы с полями от самих тестов и облегчает поддержку.
Элементы могут быть динамическими, появляясь на странице после определенных действий. Для корректного управления состоянием необходимо регулярно проверять видимость и доступность элементов через методы Page Object:
async isLoginButtonVisible() {
try {
const button = await this.getLoginButton();
return await button.isDisplayed();
} catch (e) {
return false;
}
}
Метод возвращает булевое значение, что упрощает построение условий в
тестах и предотвращает ошибки ElementNotVisible.
Protractor работает с Angular и использует автоматическую синхронизацию, но для сложных страниц с динамическими элементами часто требуется явное ожидание состояния. Page Object должен инкапсулировать логику ожиданий:
async waitForPageToLoad() {
await browser.wait(async () => {
const ready = await element(by.css('body')).isPresent();
return ready;
}, 10000, 'Страница не загрузилась за 10 секунд');
}
Это позволяет тестам оставаться детерминированными, избегая случайных падений из-за незавершенной загрузки.
В Page Object удобно хранить методы для управления состоянием сессии пользователя, что особенно актуально для многопользовательских тестов:
class SessionPage {
async login(username, password) {
await loginPage.setUsername(username);
await loginPage.setPassword(password);
const button = await loginPage.getLoginButton();
await button.click();
await browser.wait(protractor.ExpectedConditions.urlContains('/dashboard'), 5000);
}
async logout() {
const logoutBtn = element(by.id('logoutBtn'));
await browser.wait(protractor.ExpectedConditions.elementToBeClickable(logoutBtn), 5000);
await logoutBtn.click();
}
}
Инкапсуляция действий, связанных с сессией, в отдельном Page Object уменьшает зависимость тестов от конкретной страницы и позволяет переиспользовать код в разных сценариях.
Для компонентов с динамическим поведением, таких как модальные окна или таблицы с пагинацией, важно создавать методы, отражающие состояние компонента, а не только взаимодействие с элементами:
class ModalComponent {
constructor(modalSelector) {
this.modal = element(by.css(modalSelector));
}
async isVisible() {
return await this.modal.isDisplayed();
}
async waitForOpen() {
await browser.wait(protractor.ExpectedConditions.visibilityOf(this.modal), 5000);
}
async close() {
const closeButton = this.modal.element(by.css('.close-btn'));
await closeButton.click();
await browser.wait(protractor.ExpectedConditions.stalenessOf(this.modal), 5000);
}
}
Поддержка таких методов позволяет тестам реагировать на состояние компонентов, а не просто выполнять последовательность кликов.
visibilityOf, elementToBeClickable) перед
выполнением действий.get/set, а не напрямую в тестах.Такой подход к управлению состоянием повышает устойчивость и читаемость тестов, а Page Object становится не просто слоем для поиска элементов, а полноценным инструментом контроля состояния страницы и ее компонентов.