Page Object — это шаблон проектирования, применяемый для повышения читаемости, поддержки и повторного использования тестов. Основная идея заключается в том, чтобы абстрагировать взаимодействие с элементами страницы в отдельные классы, скрывая детали локаторов и действий от тестов. Каждый Page Object представляет конкретную страницу или её часть и содержит методы для работы с её элементами.
Page Object класс обычно содержит три ключевых компонента:
Локаторы элементов страницы Локаторы описывают
элементы, с которыми предстоит работать. В Protractor используется
объект by для определения стратегий поиска:
by.id, by.css, by.xpath и
др.
Методы действий Методы инкапсулируют операции над элементами: ввод текста, клик, выбор из списка, проверка видимости.
Методы ожидания и проверки состояния Для
стабильности тестов важно использовать ожидания
(ExpectedConditions), чтобы убедиться, что элемент доступен
для взаимодействия или имеет нужное состояние.
Пример структуры:
const { element, by, browser, ExpectedConditions: EC } = require('protractor');
class LoginPage {
constructor() {
this.usernameInput = element(by.id('username'));
this.passwordInput = element(by.id('password'));
this.loginButton = element(by.css('.login-btn'));
this.errorMessage = element(by.css('.error-msg'));
}
async enterUsername(username) {
await browser.wait(EC.visibilityOf(this.usernameInput), 5000);
await this.usernameInput.clear();
await this.usernameInput.sendKeys(username);
}
async enterPassword(password) {
await browser.wait(EC.visibilityOf(this.passwordInput), 5000);
await this.passwordInput.clear();
await this.passwordInput.sendKeys(password);
}
async clickLogin() {
await browser.wait(EC.elementToBeClickable(this.loginButton), 5000);
await this.loginButton.click();
}
async getErrorMessageText() {
await browser.wait(EC.visibilityOf(this.errorMessage), 5000);
return await this.errorMessage.getText();
}
}
module.exports = new LoginPage();
LoginPage, DashboardPage,
SearchResultsPage.enterUsername, clickLogin,
getErrorMessageText.BasePage.Базовый класс упрощает создание новых Page Object и позволяет использовать повторяемые методы, например, ожидание элементов, скролл, навигацию:
class BasePage {
async click(element) {
await browser.wait(EC.elementToBeClickable(element), 5000);
await element.click();
}
async typeText(element, text) {
await browser.wait(EC.visibilityOf(element), 5000);
await element.clear();
await element.sendKeys(text);
}
async getText(element) {
await browser.wait(EC.visibilityOf(element), 5000);
return await element.getText();
}
async waitForElementVisible(element, timeout = 5000) {
await browser.wait(EC.visibilityOf(element), timeout);
}
}
module.exports = BasePage;
Page Object классы наследуют BasePage и используют его
методы:
const BasePage = require('./BasePage');
class LoginPage extends BasePage {
constructor() {
super();
this.usernameInput = element(by.id('username'));
this.passwordInput = element(by.id('password'));
this.loginButton = element(by.css('.login-btn'));
}
async login(username, password) {
await this.typeText(this.usernameInput, username);
await this.typeText(this.passwordInput, password);
await this.click(this.loginButton);
}
}
module.exports = new LoginPage();
Тесты должны использовать только публичные методы Page Object, не обращаясь к локаторам напрямую:
const LoginPage = require('../pages/LoginPage');
describe('Авторизация', () => {
it('должна отображать ошибку при неверных данных', async () => {
await browser.get('https://example.com/login');
await LoginPage.login('wrongUser', 'wrongPass');
const error = await LoginPage.getErrorMessageText();
expect(error).toContain('Неверное имя пользователя или пароль');
});
});
Такой подход повышает читаемость и упрощает поддержку тестов. Любые изменения в верстке затрагивают только Page Object, а тесты остаются неизменными.
Выбор стратегии локатора влияет на стабильность тестов:
by.id и by.css — предпочтительные, быстрые
и устойчивые.by.xpath — использовать при необходимости, если нет
других способов.by.binding, by.model — специфично для
Angular, позволяет работать с привязками.Рекомендуется избегать жёстких абсолютных XPath, использовать относительные и CSS-селекторы с классами и атрибутами.
loginAsAdmin, fillForm) для повторного
использования.Создание Page Object классов обеспечивает устойчивость тестов к изменениям интерфейса и позволяет строить читаемую, поддерживаемую структуру автоматизации в Protractor.