Лучшие практики Page Objects

Page Object Model (POM) — один из ключевых паттернов в автоматизированном тестировании, позволяющий структурировать код так, чтобы тесты оставались читаемыми, поддерживаемыми и масштабируемыми. В WebdriverIO POM реализуется через классы и модули, которые инкапсулируют работу с конкретными страницами или компонентами интерфейса.


Структура Page Object

Каждая страница приложения должна иметь отдельный класс, который содержит:

  1. Селекторы элементов Селекторы инкапсулируются в геттеры. Это упрощает их переиспользование и изменение при обновлении UI.

    class LoginPage {
        get inputUsername() { return $('#username'); }
        get inputPassword() { return $('#password'); }
        get btnSubmit() { return $('button[type="submit"]'); }
    }
  2. Методы действий Методы класса выполняют действия над элементами страницы, скрывая детали взаимодействия. Методы должны быть атомарными, с одной логической задачей.

    async login(username, password) {
        await this.inputUsername.setValue(username);
        await this.inputPassword.setValue(password);
        await this.btnSubmit.click();
    }
  3. Методы проверки состояния Для улучшения читаемости тестов полезно включать методы, возвращающие состояние страницы.

    async isLoginButtonEnabled() {
        return this.btnSubmit.isEnabled();
    }

Разделение уровней взаимодействия

  • Page Objects для страниц — содержат действия на уровне страницы, например, login(), openDashboard().
  • Components Objects для повторно используемых блоков — содержат методы для работы с навигацией, модальными окнами, таблицами.
class HeaderComponent {
    get profileMenu() { return $('#profileMenu'); }
    async openProfile() {
        await this.profileMenu.click();
    }
}

Использование компонент повышает переиспользуемость кода и снижает дублирование.


Практики написания чистых Page Objects

  1. Инкапсуляция селекторов Никогда не использовать селекторы напрямую в тестах. Все селекторы должны быть внутри Page Object.

  2. Минимизация логики в тестах Тесты должны описывать сценарии на высоком уровне: loginPage.login('user', 'pass'), а не управлять каждым полем отдельно.

  3. Согласованное именование методов Использовать глаголы, отражающие действие: click, open, fill, submit. Это улучшает читаемость.

  4. Возвращение Page Objects при навигации Методы, которые ведут на другую страницу, должны возвращать новый экземпляр соответствующего Page Object:

    async goToDashboard() {
        await $('a[href="/dashboard"]').click();
        return new DashboardPage();
    }
  5. Асинхронность Все методы взаимодействия с элементами должны использовать async/await. Это предотвращает проблемы с таймингами и синхронизацией.


Организация проекта с Page Objects

  1. Дерево каталогов
/tests
    /specs
        login.spec.js
        dashboard.spec.js
/pages
    login.page.js
    dashboard.page.js
/components
    header.component.js
    footer.component.js
  1. Переиспользование общих компонентов Общие элементы, такие как хедер или футер, выносятся в отдельные компоненты. Страницы импортируют их для взаимодействия.

  2. Файлы конфигурации и константы 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 Objects

  • Высокий уровень абстракции — тест описывает сценарий, а не детали кликов и ввода.
  • Повторное использование методов — одинаковые действия должны выполняться через Page Object, а не копироваться.
  • Изоляция — каждый тест должен использовать свежий экземпляр страницы или чистое состояние.
  • Ясные ожидания — для проверки состояния использовать методы Page Object, а не прямые селекторы внутри теста.

Page Object Model в WebdriverIO обеспечивает масштабируемость и поддержку тестовой инфраструктуры. Строгое следование принципам инкапсуляции, разделения компонентов и асинхронности позволяет создавать надежные и легко читаемые автотесты.