Page Object Model паттерн

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

Структура Page Object

Каждая веб-страница или её компонент представляет собой отдельный объект. Эти объекты инкапсулируют все действия и элементы на странице, предоставляя методы для взаимодействия с ними.

Пример структуры POM:

  1. Page Object — класс, который представляет страницу и инкапсулирует все взаимодействия с её элементами.
  2. Test Class — классы, содержащие тесты, которые используют Page Object для выполнения операций на странице.

В Playwright Page Object Model можно реализовать следующим образом:

// LoginPage.js
class LoginPage {
    constructor(page) {
        this.page = page;
        this.usernameField = page.locator('#username');
        this.passwordField = page.locator('#password');
        this.loginButton = page.locator('#login');
    }

    async login(username, password) {
        await this.usernameField.fill(username);
        await this.passwordField.fill(password);
        await this.loginButton.click();
    }
}

module.exports = LoginPage;

В данном примере LoginPage инкапсулирует все действия, связанные с авторизацией, а именно ввод имени пользователя и пароля, а также клик по кнопке входа.

Преимущества использования POM в Playwright

  1. Повторное использование кода Page Object Model способствует повторному использованию кода. Элементы и действия, которые выполняются на одной странице, можно использовать в различных тестах, что предотвращает дублирование и упрощает поддержку.

  2. Читаемость тестов Поскольку тесты работают с абстракциями, а не с конкретными деталями реализации страницы, их становится проще читать и поддерживать. Методы в объекте страницы имеют имена, которые логично описывают действия, что делает код более осмысленным.

  3. Изоляция изменений Если структура страницы изменится, необходимо обновить только Page Object, а не все тесты. Это уменьшает количество изменений в тестах и улучшает их стабильность.

  4. Упрощение тестов Поскольку взаимодействие с веб-страницей вынесено в отдельные методы, тесты становятся компактными и фокусируются только на логике тестирования.

Реализация POM в Playwright

Структура проекта

Рассмотрим типичную структуру проекта с использованием Playwright и Page Object Model:

/tests
  /login
    login.spec.js
  /pages
    LoginPage.js
  • login.spec.js — файл с тестами.
  • LoginPage.js — объект страницы с методами для работы с элементами на странице авторизации.

Пример использования Page Object в тестах

// login.spec.js
const { test, expect } = require('@playwright/test');
const LoginPage = require('../pages/LoginPage');

test('User can log in with valid credentials', async ({ page }) => {
    const loginPage = new LoginPage(page);
    await loginPage.login('user1', 'password123');
    
    // Проверка, что пользователь успешно вошел
    await expect(page.locator('text=Welcome, user1')).toBeVisible();
});

В этом примере тест выполняет следующие шаги:

  1. Создается объект страницы LoginPage.
  2. Взаимодействие с элементами страницы осуществляется через методы объекта.
  3. В конце выполняется проверка, что пользователь успешно авторизовался.

Важные принципы POM

  1. Единая точка изменения В идеале, каждый элемент страницы (например, кнопки, поля ввода) должен быть представлен как локатор в объекте страницы. Это позволяет централизованно изменять локаторы при изменении структуры страницы.

  2. Методы страницы должны быть абстракциями Методы в Page Object не должны быть привязаны к конкретной реализации теста. Например, метод login() должен просто выполнять вход на страницу, не заботясь о том, что именно тест проверяет.

  3. Минимизация логики в тестах Логика тестов должна быть как можно проще. Тесты не должны содержать детализированную информацию о том, как именно взаимодействовать с элементами страницы — всё это скрыто в Page Object.

Разделение ответственности

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

Пример разделения на компоненты:

// HeaderPage.js
class HeaderPage {
    constructor(page) {
        this.page = page;
        this.profileButton = page.locator('#profile');
        this.logoutButton = page.locator('#logout');
    }

    async logout() {
        await this.logoutButton.click();
    }
}

module.exports = HeaderPage;
// LoginPage.js
class LoginPage {
    constructor(page) {
        this.page = page;
        this.usernameField = page.locator('#username');
        this.passwordField = page.locator('#password');
        this.loginButton = page.locator('#login');
    }

    async login(username, password) {
        await this.usernameField.fill(username);
        await this.passwordField.fill(password);
        await this.loginButton.click();
    }
}

module.exports = LoginPage;
// login.spec.js
const { test, expect } = require('@playwright/test');
const LoginPage = require('../pages/LoginPage');
const HeaderPage = require('../pages/HeaderPage');

test('User can log in and log out', async ({ page }) => {
    const loginPage = new LoginPage(page);
    await loginPage.login('user1', 'password123');
    
    const headerPage = new HeaderPage(page);
    await headerPage.logout();
    
    await expect(page.locator('text=Login')).toBeVisible();
});

Управление локаторами

Локаторы являются важной частью Page Object Model. В Playwright есть несколько способов найти элементы: через CSS-селекторы, текстовые значения, атрибуты и т. д. Рекомендуется использовать наиболее стабильные селекторы, чтобы минимизировать риск того, что тесты будут ломаться при изменениях на веб-странице.

Стратегии поиска элементов:

  1. CSS-селекторы — наиболее универсальный способ поиска элементов. Можно использовать классы, id, атрибуты.
  2. Text-based локаторы — полезны, когда на странице есть уникальные текстовые элементы.
  3. XPath — используется, если элементы трудно локализуются с помощью CSS.
// Пример локатора через CSS-селектор
this.usernameField = page.locator('#username');

// Пример локатора через текст
this.loginButton = page.locator('text=Login');

Взаимодействие с элементами

Для взаимодействия с элементами страницы в Playwright существуют методы, такие как click(), fill(), selectOption(), check(), uncheck(). Каждый метод выполняет действия, соответствующие ожидаемому результату.

class LoginPage {
    async login(username, password) {
        await this.usernameField.fill(username);
        await this.passwordField.fill(password);
        await this.loginButton.click();
    }
}

В этом примере метод fill() заполняет поле ввода, а click() выполняет клик по кнопке.

Тестирование с асинхронностью

Playwright работает в асинхронном режиме, и все взаимодействия с элементами страницы являются асинхронными. Методы, которые изменяют состояние страницы, должны быть асинхронными, и тесты должны ожидать завершения этих действий.

class LoginPage {
    async login(username, password) {
        await this.usernameField.fill(username);
        await this.passwordField.fill(password);
        await this.loginButton.click();
    }
}

Каждый метод, взаимодействующий с элементами, выполняется с await, чтобы гарантировать правильный порядок выполнения.

Обработка ошибок и ожидания

Одной из важных особенностей при работе с Playwright является управление ожиданиями. Иногда действия, такие как клик или ввод данных, могут не выполняться мгновенно из-за загрузки страницы или асинхронных операций. Playwright предоставляет различные методы ожидания, чтобы гарантировать, что элементы готовы к взаимодействию.

// Пример ожидания появления элемента
await this.page.waitForSelector('#dashboard', { state: 'visible' });

Этот код будет ожидать, пока элемент с id dashboard не станет видимым.

Заключение

Использование Page Object Model в тестировании с Playwright значительно упрощает организацию тестов, повышает их поддерживаемость и читаемость. Этот паттерн позволяет изол