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

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


Структура POM в Cypress

В POM каждая веб-страница или крупный компонент приложения представляется отдельным классом или объектом, содержащим:

  1. Селекторы элементов страницы — локаторы для кнопок, полей ввода, таблиц и других элементов.
  2. Методы действий — функции, выполняющие клики, ввод текста, навигацию и проверки состояния элементов.
  3. Методы проверки состояния страницы — функции для валидации текущего состояния страницы или отображения элементов.

Пример базовой структуры директории для POM в проекте на Cypress:

cypress/
├─ e2e/
│  ├─ login.spec.js
│  └─ dashboard.spec.js
└─ support/
   └─ pageObjects/
       ├─ LoginPage.js
       └─ DashboardPage.js

Каждый файл внутри pageObjects представляет отдельную страницу приложения.


Пример реализации POM для страницы логина

class LoginPage {
    // Селекторы
    usernameInput() {
        return cy.get('#username');
    }

    passwordInput() {
        return cy.get('#password');
    }

    loginButton() {
        return cy.get('button[type="submit"]');
    }

    errorMessage() {
        return cy.get('.error-message');
    }

    // Действия
    enterUsername(username) {
        this.usernameInput().clear().type(username);
    }

    enterPassword(password) {
        this.passwordInput().clear().type(password);
    }

    submitLogin() {
        this.loginButton().click();
    }

    // Комбинированное действие
    login(username, password) {
        this.enterUsername(username);
        this.enterPassword(password);
        this.submitLogin();
    }
}

export default LoginPage;

Использование в тесте:

import LoginPage from '../support/pageObjects/LoginPage';

describe('Login Tests', () => {
    const loginPage = new LoginPage();

    it('Успешный логин', () => {
        cy.visit('/login');
        loginPage.login('user1', 'password123');
        cy.url().should('include', '/dashboard');
    });

    it('Неправильный пароль', () => {
        cy.visit('/login');
        loginPage.login('user1', 'wrongPassword');
        loginPage.errorMessage().should('be.visible')
            .and('contain.text', 'Неверный логин или пароль');
    });
});

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

  • Централизация селекторов и методов — изменения в DOM требуют правки только в одном месте.
  • Повторное использование кода — методы страниц можно использовать в нескольких тестах.
  • Упрощение чтения тестов — тесты становятся похожими на сценарии действий пользователя, без излишней детализации работы с элементами.
  • Масштабируемость — добавление новых страниц или компонентов не требует изменения существующих тестов.

Продвинутые подходы к POM в Cypress

  1. Использование вспомогательных методов для сложных действий

Если на странице присутствует сложная последовательность действий, её можно оформить отдельным методом. Например, оформление заказа в интернет-магазине:

completeOrder(product, address) {
    this.selectProduct(product);
    this.addToCart();
    this.proceedToCheckout();
    this.enterShippingAddress(address);
    this.confirmOrder();
}
  1. Интеграция с фикстурами

Данные для тестов можно хранить в cypress/fixtures и передавать их в методы POM:

cy.fixture('users.json').then(user => {
    loginPage.login(user.valid.username, user.valid.password);
});
  1. Наследование и базовые классы страниц

Для общих элементов (например, шапка сайта, футер) можно создать базовый класс BasePage с методами навигации и проверок. Остальные страницы будут наследоваться от него:

class BasePage {
    header() {
        return cy.get('header');
    }

    footer() {
        return cy.get('footer');
    }

    navigateTo(url) {
        cy.visit(url);
    }
}

class DashboardPage extends BasePage {
    userProfileButton() {
        return cy.get('.profile-btn');
    }

    openUserProfile() {
        this.userProfileButton().click();
    }
}
  1. Использование цепочек методов (Method Chaining)

Методы можно реализовать так, чтобы возвращался объект страницы, позволяя строить удобные цепочки:

enterUsername(username) {
    this.usernameInput().type(username);
    return this;
}

enterPassword(password) {
    this.passwordInput().type(password);
    return this;
}

// Использование
loginPage.enterUsername('user1')
         .enterPassword('password123')
         .submitLogin();

Взаимодействие POM с Cypress Commands

Для повторяющихся действий можно также создавать кастомные команды Cypress, интегрируя их с POM:

Cypress.Commands.add('loginAs', (username, password) => {
    const loginPage = new LoginPage();
    loginPage.login(username, password);
});

Это позволяет в тестах писать:

cy.visit('/login');
cy.loginAs('user1', 'password123');

Рекомендации по поддержке POM

  • Использовать читаемые и уникальные селекторы, предпочтительно с data-* атрибутами.
  • Разделять действия и проверки — методы POM должны выполнять действия или возвращать элементы для проверки, но не выполнять assert напрямую, чтобы тесты оставались гибкими.
  • Минимизировать вложенность методов — каждый метод должен выполнять одно логическое действие.
  • Регулярно обновлять селекторы после изменений интерфейса, чтобы избежать сломанных тестов.

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