Page Object Pattern (POP) — это архитектурный подход к организации тестов пользовательского интерфейса, который позволяет повысить читаемость, поддерживаемость и повторное использование кода. Идея заключается в том, чтобы представлять страницы или компоненты приложения как объекты с методами и свойствами, отражающими действия и элементы на странице. В контексте тестирования с использованием Enzyme этот паттерн помогает изолировать логику взаимодействия с компонентами React от самих тестов.
1. Абстракция взаимодействия с компонентом Каждый Page Object инкапсулирует детали работы с элементами DOM. Тесты не должны напрямую обращаться к селекторам, а использовать методы Page Object.
Пример:
class LoginPage {
constructor(wrapper) {
this.wrapper = wrapper;
}
setUsername(username) {
this.wrapper.find('input[name="username"]').simulate('change', { target: { value: username } });
}
setPassword(password) {
this.wrapper.find('input[name="password"]').simulate('change', { target: { value: password } });
}
submit() {
this.wrapper.find('form').simulate('submit');
}
getErrorMessage() {
return this.wrapper.find('.error-message').text();
}
}
В этом примере тестовый код не зависит от конкретной реализации формы: любые изменения селекторов или DOM можно исправить только внутри Page Object.
2. Методы должны отражать действия пользователя Методы Page Object описывают именно действия или запросы информации, а не внутренние детали DOM. Это делает тесты понятными и декларативными:
loginPage.setUsername('user1');
loginPage.setPassword('password123');
loginPage.submit();
expect(loginPage.getErrorMessage()).toBe('Invalid credentials');
1. Разделение по страницам и компонентам Каждая страница или крупный компонент имеет отдельный файл Page Object. Например:
/tests/pageObjects/LoginPage.js
/tests/pageObjects/DashboardPage.js
Если компонент содержит вложенные подкомпоненты, можно создавать отдельные объекты для них и использовать композицию:
class DashboardPage {
constructor(wrapper) {
this.wrapper = wrapper;
this.header = new HeaderComponent(wrapper.find('Header'));
this.sidebar = new SidebarComponent(wrapper.find('Sidebar'));
}
getUserGreeting() {
return this.header.getGreeting();
}
navigateTo(section) {
this.sidebar.clickSection(section);
}
}
2. Инициализация Page Object Page Object получает на
вход обертку Enzyme (mount или shallow).
Использование mount предпочтительнее для тестирования
полной интеграции с жизненным циклом компонентов.
import { mount } from 'enzyme';
import LoginPage from './pageObjects/LoginPage';
import App from '../App';
const wrapper = mount(<App />);
const loginPage = new LoginPage(wrapper.find('LoginForm'));
1. Симуляция событий Enzyme предоставляет методы
.simulate() для имитации событий, таких как
click, change, submit. Page
Object инкапсулирует эти вызовы:
submitForm() {
this.wrapper.find('form').simulate('submit');
}
2. Получение данных из компонента Методы для чтения
состояния страницы или сообщений об ошибках используют
.text(), .prop(), .state():
getUsernameFieldValue() {
return this.wrapper.find('input[name="username"]').prop('value');
}
3. Работа с вложенными компонентами Если компонент состоит из нескольких вложенных компонентов, Page Object может создавать объекты для них и вызывать их методы:
this.wrapper.find('Header').simulate('click');
или
this.header.clickLogoutButton();
mount для комплексных компонентов с
жизненным циклом, shallow для юнит-тестов.Page Object Pattern в сочетании с Enzyme позволяет создавать тесты, которые легко читать, поддерживать и масштабировать. Ключ к эффективности — строгая инкапсуляция взаимодействия с компонентами и ясное разделение ответственности между тестами и Page Object.