В автоматизированном тестировании веб-приложений часто возникает ситуация, когда сценарий проверки зависит от нескольких последовательных страниц. Правильная организация таких тестов обеспечивает стабильность, читаемость и поддержку кода. WebdriverIO предоставляет возможности для управления зависимостями между страницами через паттерны проектирования, структуры Page Object и асинхронное взаимодействие с элементами.
Page Object Model (POM) — основной паттерн для управления страницами в WebdriverIO. Каждая страница приложения описывается отдельным классом, который содержит:
Пример класса страницы:
class LoginPage {
get usernameInput() { return $('#username'); }
get passwordInput() { return $('#password'); }
get loginButton() { return $('#login'); }
async open() {
await browser.url('/login');
}
async login(username, password) {
await this.usernameInput.setValue(username);
await this.passwordInput.setValue(password);
await this.loginButton.click();
return new DashboardPage(); // возвращаем следующую страницу
}
}
Важный момент: методы, которые приводят к переходу на новую страницу, должны возвращать объект следующей страницы. Это упрощает управление зависимостями между страницами и позволяет строить цепочки действий.
WebdriverIO работает на базе асинхронных команд. Для корректного управления зависимостями необходимо учитывать моменты загрузки страниц и элементов. Основные методы:
waitForExist — ожидание появления элемента в DOM;waitForDisplayed — ожидание видимости элемента;waitUntil — универсальное ожидание произвольного
условия.Пример использования при переходе между страницами:
class DashboardPage {
get profileLink() { return $('#profile'); }
async openProfile() {
await this.profileLink.waitForDisplayed({ timeout: 5000 });
await this.profileLink.click();
return new ProfilePage();
}
}
Это гарантирует, что следующий шаг теста будет выполняться только после полной готовности страницы.
Для сложных сценариев тесты часто строятся в виде цепочек вызовов методов Page Object. Такой подход минимизирует дублирование кода и делает тесты читаемыми:
it('должен корректно пройти авторизацию и открыть профиль', async () => {
const loginPage = new LoginPage();
const dashboardPage = await loginPage.open().then(() => loginPage.login('user', 'pass'));
const profilePage = await dashboardPage.openProfile();
await expect(profilePage.profileHeader).toBeDisplayed();
});
Преимущество: каждый метод управляет своим контекстом и возвращает следующий объект страницы, что делает тест устойчивым к изменениям навигации.
Иногда зависимости между страницами связаны не только с переходами, но и с состоянием приложения. Например, после логина могут быть доступны определённые данные или виджеты. В таких случаях используют:
isDisplayed,
isEnabled, getText;reset, logout).Пример контроля состояния:
class ProfilePage {
get profileHeader() { return $('h1.profile-title'); }
async isLoaded() {
return this.profileHeader.waitForDisplayed({ timeout: 3000 });
}
}
Метод isLoaded используется перед любыми действиями на
странице, что снижает вероятность ошибок из-за несоответствия
состояния.
Для крупных приложений удобно вынести общие операции в отдельные утилитные классы или сервисы. Это позволяет:
Пример сервиса авторизации:
class AuthService {
static async loginAsUser(username, password) {
const loginPage = new LoginPage();
await loginPage.open();
return loginPage.login(username, password);
}
}
Теперь тесты могут вызывать сервис, не заботясь о деталях навигации.
Эти подходы минимизируют ошибки, связанные с асинхронной загрузкой и сложными последовательностями страниц.
Управление зависимостями между страницами в WebdriverIO строится на строгом разделении ответственности между объектами страниц, правильной обработке асинхронности и централизованной логике навигации. Соблюдение этих принципов позволяет создавать масштабируемые, надёжные и легко поддерживаемые автоматизированные тесты.