Page Object Model (POM) представляет собой шаблон проектирования тестов, направленный на разделение логики тестов и структуры страниц приложения. Основная цель — сделать тесты более поддерживаемыми, читаемыми и масштабируемыми. В контексте Cypress использование POM позволяет централизованно управлять селекторами и действиями на страницах, снижая дублирование кода и упрощая изменения при обновлении интерфейса.
В POM каждая веб-страница или крупный компонент приложения представляется отдельным классом или объектом, содержащим:
Пример базовой структуры директории для POM в проекте на Cypress:
cypress/
├─ e2e/
│ ├─ login.spec.js
│ └─ dashboard.spec.js
└─ support/
└─ pageObjects/
├─ LoginPage.js
└─ DashboardPage.js
Каждый файл внутри pageObjects представляет отдельную
страницу приложения.
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', 'Неверный логин или пароль');
});
});
Если на странице присутствует сложная последовательность действий, её можно оформить отдельным методом. Например, оформление заказа в интернет-магазине:
completeOrder(product, address) {
this.selectProduct(product);
this.addToCart();
this.proceedToCheckout();
this.enterShippingAddress(address);
this.confirmOrder();
}
Данные для тестов можно хранить в cypress/fixtures и
передавать их в методы POM:
cy.fixture('users.json').then(user => {
loginPage.login(user.valid.username, user.valid.password);
});
Для общих элементов (например, шапка сайта, футер) можно создать
базовый класс 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();
}
}
Методы можно реализовать так, чтобы возвращался объект страницы, позволяя строить удобные цепочки:
enterUsername(username) {
this.usernameInput().type(username);
return this;
}
enterPassword(password) {
this.passwordInput().type(password);
return this;
}
// Использование
loginPage.enterUsername('user1')
.enterPassword('password123')
.submitLogin();
Для повторяющихся действий можно также создавать кастомные команды Cypress, интегрируя их с POM:
Cypress.Commands.add('loginAs', (username, password) => {
const loginPage = new LoginPage();
loginPage.login(username, password);
});
Это позволяет в тестах писать:
cy.visit('/login');
cy.loginAs('user1', 'password123');
data-* атрибутами.POM в сочетании с Cypress обеспечивает высокую стабильность и масштабируемость автотестов, особенно для крупных веб-приложений с множеством страниц и сложной логикой пользовательских сценариев.