End-to-End тестирование: основные принципы

Protractor является инструментом для End-to-End (E2E) тестирования веб-приложений на базе Angular и AngularJS, но также поддерживает тестирование любых веб-приложений, взаимодействующих с браузером через WebDriver. Его главная цель — проверять работу приложения в условиях, максимально приближенных к реальным сценариям использования.

Архитектура Protractor

Protractor построен поверх Selenium WebDriver, обеспечивая управление браузерами и взаимодействие с DOM. Отличительной особенностью является встроенная поддержка Angular, что позволяет:

  • Отслеживать завершение асинхронных операций Angular, таких как $http и $timeout.
  • Использовать специальные селекторы Angular (by.model, by.binding, by.repeater) для более удобного поиска элементов.

Компоненты архитектуры:

  1. WebDriver Manager — утилита для установки и запуска драйверов браузеров (ChromeDriver, GeckoDriver и др.).
  2. Конфигурационный файл (protractor.conf.js) — задаёт параметры тестирования: браузеры, пути к тестам, фреймворк (Jasmine, Mocha или Cucumber), таймауты.
  3. Тестовые скрипты — файлы с шагами сценариев, написанные на JavaScript или TypeScript.
  4. Фреймворк ожиданий (Expectations) — позволяет проверять состояния элементов, значения, наличие текста и другие условия.

Настройка и запуск Protractor

Установка выполняется через npm:

npm install -g protractor

После установки необходимо обновить WebDriver:

webdriver-manager update

Запуск локального сервера Selenium:

webdriver-manager start

Конфигурационный файл может выглядеть следующим образом:

exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['tests/**/*.spec.js'],
  capabilities: {
    browserName: 'chrome'
  },
  framework: 'jasmine',
  jasmineNodeOpts: {
    defaultTimeoutInterval: 30000
  },
  onPrepare: function() {
    browser.waitForAngularEnabled(true);
  }
};

Ключевые моменты конфигурации:

  • seleniumAddress — адрес работающего Selenium сервера.
  • specs — путь к файлам тестов.
  • capabilities — параметры браузера.
  • framework — используемый фреймворк тестирования.
  • onPrepare — функция, выполняющаяся перед запуском тестов, например, включение ожиданий Angular.

Синтаксис и структура тестов

Protractor обычно используют с Jasmine или Mocha. Типичный тест выглядит так:

describe('Тестирование формы входа', function() {
  it('Должен открыть страницу и проверить заголовок', async function() {
    await browser.get('https://example.com/login');
    const title = await browser.getTitle();
    expect(title).toEqual('Login Page');
  });

  it('Должен ввести данные и отправить форму', async function() {
    const username = element(by.id('username'));
    const password = element(by.id('password'));
    const submitBtn = element(by.buttonText('Войти'));

    await username.sendKeys('testuser');
    await password.sendKeys('password123');
    await submitBtn.click();

    const successMessage = element(by.css('.success'));
    expect(await successMessage.getText()).toContain('Успешный вход');
  });
});

Особенности синтаксиса:

  • element(by.selector) — поиск одного элемента.
  • element.all(by.selector) — поиск коллекции элементов.
  • await используется для асинхронных операций (в Protractor версии 6+ рекомендуется явное ожидание).
  • expect() — проверки состояния.

Ожидания и синхронизация

Protractor обеспечивает автоматическую синхронизацию с Angular, но для элементов вне Angular или динамически загружаемых данных необходимо использовать Explicit Wait:

const EC = protractor.ExpectedConditions;
const button = element(by.id('loadButton'));

await browser.wait(EC.elementToBeClickable(button), 5000);
await button.click();

Типичные ожидания:

  • elementToBeClickable — элемент кликабелен.
  • visibilityOf — элемент видим.
  • presenceOf — элемент присутствует в DOM.

Работа с не-Angular приложениями

Для не-Angular приложений требуется отключить ожидание Angular:

browser.waitForAngularEnabled(false);

Это необходимо, чтобы Protractor не ждал Angular событий, которых нет.

Организация тестов и Page Object Pattern

Для поддержки масштабируемости тестов рекомендуется использовать Page Object Pattern. Пример:

// loginPage.js
class LoginPage {
  constructor() {
    this.username = element(by.id('username'));
    this.password = element(by.id('password'));
    this.submitBtn = element(by.buttonText('Войти'));
  }

  async login(user, pass) {
    await this.username.sendKeys(user);
    await this.password.sendKeys(pass);
    await this.submitBtn.click();
  }
}

module.exports = new LoginPage();
// login.spec.js
const loginPage = require('./loginPage');

describe('Тест формы входа', function() {
  it('Успешный вход', async function() {
    await browser.get('https://example.com/login');
    await loginPage.login('testuser', 'password123');
    const successMessage = element(by.css('.success'));
    expect(await successMessage.getText()).toContain('Успешный вход');
  });
});

Преимущества Page Object Pattern:

  • Разделение логики теста и взаимодействия с элементами.
  • Легкость поддержки при изменении интерфейса.
  • Повышение читаемости тестов.

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

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

  • browser.sleep(ms) — временная пауза (не рекомендуется использовать часто).
  • browser.takeScreenshot() — создание скриншотов для отчётности.
  • console.log() внутри тестов для проверки данных.

Для сложных сценариев полезно комбинировать с внешними библиотеками отчётности, например, Allure, Protractor Reporter.

Параллельное выполнение тестов

Protractor поддерживает параллельное выполнение через параметры multiCapabilities:

multiCapabilities: [
  { browserName: 'chrome' },
  { browserName: 'firefox' }
]

Это позволяет ускорять прогон тестов и проверять совместимость с разными браузерами.

Типичные ошибки и рекомендации

  • Неявные ожидания: использование element(...).click() без проверки видимости может привести к флейку.
  • Смешивание Angular и не-Angular страниц: необходимо явно включать или отключать ожидание Angular.
  • Отсутствие Page Object: усложняет поддержку при росте проекта.
  • Долгие таймауты без необходимости: увеличивают время тестирования.

Интеграция с CI/CD

Protractor легко интегрируется с системами CI/CD, такими как Jenkins, GitLab CI, GitHub Actions. Важно:

  • Настроить WebDriver на CI сервере.
  • Использовать headless режим браузеров (chromeOptions: { args: ['--headless'] }) для экономии ресурсов.
  • Сохранять скриншоты и логи тестов для анализа ошибок.

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