Возврат в главное содержимое

Protractor — это инструмент для end-to-end тестирования Angular и не-Angular приложений на JavaScript. Он основан на Selenium WebDriver и предоставляет расширенные возможности для работы с асинхронными операциями, характерными для современных веб-приложений.

Для начала работы необходимо установить Protractor через npm:

npm install -g protractor

После установки доступна команда protractor --version для проверки корректности установки. Также требуется запуск Selenium Server:

webdriver-manager update
webdriver-manager start

Конфигурация тестов осуществляется через файл protractor.conf.js, где указываются браузеры, пути к тестам, тайм-ауты и другие настройки:

exports.config = {
    directConnect: true,
    framework: 'jasmine',
    specs: ['specs/**/*.spec.js'],
    capabilities: {
        browserName: 'chrome'
    },
    jasmineNodeOpts: {
        defaultTimeoutInterval: 30000
    }
};

Ключевой момент: использование directConnect: true позволяет обойти запуск отдельного Selenium Server и напрямую управлять браузером.


Основные элементы синтаксиса Protractor

Элементы и локаторы

Protractor использует WebDriverJS, поэтому элементы страницы выбираются с помощью локаторов:

let usernameInput = element(by.id('username'));
let loginButton = element(by.css('.login-button'));
let items = element.all(by.repeater('item in items'));
  • element(by.id('...')) — выбор одного элемента по ID.
  • element(by.css('...')) — выбор элемента по CSS-селектору.
  • element.all(by.repeater('...')) — выбор группы элементов в Angular repeater.

Особенность: element.all возвращает массив объектов ElementArrayFinder, с которыми можно работать через методы get(index), first(), last() и count().

Асинхронность

Protractor поддерживает работу с промисами через async/await. Это особенно важно при взаимодействии с элементами страницы:

it('должен вводить логин и нажимать кнопку', async () => {
    await usernameInput.sendKeys('admin');
    await loginButton.click();
});

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


Навигация и ожидания

Переход между страницами

Метод browser.get(url) открывает указанный URL:

await browser.get('https://example.com/login');

Для возврата на предыдущую страницу используется:

await browser.navigate().back();

Прямая навигация и возврат позволяют создавать сценарии с проверкой истории браузера.

Ожидания элементов

Для стабильных тестов крайне важно использовать ожидания:

let EC = protractor.ExpectedConditions;
await browser.wait(EC.visibilityOf(loginButton), 5000, 'Кнопка не появилась');
  • visibilityOf — ожидает появления элемента.
  • elementToBeClickable — ожидает, пока элемент станет кликабельным.
  • Тайм-аут указывается в миллисекундах.

Рекомендация: не использовать жесткие задержки browser.sleep(), они увеличивают время выполнения и делают тесты нестабильными.


Работа с формами и вводом данных

Protractor позволяет эффективно работать с формами:

await element(by.model('user.name')).sendKeys('Иван');
await element(by.model('user.password')).sendKeys('123456');
await element(by.buttonText('Войти')).click();
  • by.model используется для Angular-привязки данных.
  • by.buttonText и by.partialButtonText позволяют выбрать кнопку по тексту.

Важно: использование Angular локаторов (by.model, by.binding) делает тесты более устойчивыми к изменению DOM.


Проверка состояния элементов

Protractor интегрируется с Jasmine, предоставляя средства для проверок:

let successMessage = element(by.css('.success'));
expect(await successMessage.getText()).toEqual('Вход выполнен успешно');
expect(await loginButton.isEnabled()).toBe(true);
  • getText() возвращает текст элемента.
  • isDisplayed() проверяет видимость.
  • isEnabled() проверяет доступность элемента для взаимодействия.

Для работы с массивами элементов:

let items = element.all(by.repeater('item in items'));
expect(await items.count()).toBe(5);
expect(await items.get(0).getText()).toContain('Первый элемент');

Взаимодействие с всплывающими окнами и alert

Protractor позволяет управлять alert и confirm:

await browser.switchTo().alert().accept();
await browser.switchTo().alert().dismiss();
let alertText = await browser.switchTo().alert().getText();

Подсказка: при работе с модальными окнами нужно всегда переключаться через browser.switchTo().alert() перед взаимодействием.


Структура больших тестовых наборов

Для крупных проектов рекомендуется организовать тесты в папки:

/specs
    login.spec.js
    dashboard.spec.js
/pages
    login.page.js
    dashboard.page.js

Стратегия Page Object Model (POM):

  • Каждый файл в /pages содержит методы для взаимодействия с элементами страницы.
  • Тестовые файлы (spec.js) используют эти методы, повышая читаемость и переиспользуемость.

Пример Page Object:

class LoginPage {
    constructor() {
        this.usernameInput = element(by.id('username'));
        this.passwordInput = element(by.id('password'));
        this.loginButton = element(by.buttonText('Войти'));
    }

    async login(user, pass) {
        await this.usernameInput.sendKeys(user);
        await this.passwordInput.sendKeys(pass);
        await this.loginButton.click();
    }
}

module.exports = new LoginPage();

Логирование и отладка

Protractor поддерживает вывод логов:

browser.manage().logs().get('browser').then(function(logs) {
    logs.forEach(function(log) {
        console.log(log.message);
    });
});

Для детальной отладки можно включить SELENIUM_PROMISE_MANAGER: false в конфигурации и использовать async/await для пошагового контроля выполнения тестов.


Применение Protractor для возврата в главное содержимое

Особенность многих Angular-приложений — динамическое обновление контента и всплывающие окна. Для возврата к главному содержимому используется комбинация навигации и ожиданий:

await browser.navigate().back();
let mainContent = element(by.id('main-content'));
await browser.wait(protractor.ExpectedConditions.visibilityOf(mainContent), 5000);

Такой подход гарантирует, что после перехода пользователь окажется именно на основной странице, а тест не продолжится, пока контент полностью не загрузится.

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