Protractor — это инструмент для end-to-end тестирования веб-приложений на базе Angular и AngularJS. Он построен поверх WebDriverJS, что позволяет управлять браузером и выполнять асинхронные операции. Основной особенностью Protractor является глубокая интеграция с Angular, благодаря чему синхронизация с приложением осуществляется автоматически: тест ожидает завершения всех асинхронных операций, таких как HTTP-запросы и таймеры, прежде чем выполнять следующие действия.
Protractor использует promise-based архитектуру, что
позволяет безопасно работать с асинхронными операциями. В современных
версиях рекомендуется использование async/await для
упрощения чтения и поддержки кода.
Для работы с Protractor необходимо установить несколько зависимостей:
npm install --save-dev protractor
npm install --save-dev jasmine
Protractor требует файл конфигурации
(protractor.conf.js), который задаёт:
browser.waitForAngularEnabled.Пример минимальной конфигурации:
exports.config = {
framework: 'jasmine',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['specs/**/*.spec.js'],
capabilities: {
browserName: 'chrome'
},
onPrepare: async () => {
await browser.waitForAngularEnabled(true);
}
};
Для работы с элементами Angular Protractor использует локаторы, расширяющие стандартные селекторы WebDriver:
by.model('modelName') — связывает элемент с
Angular-моделью;by.binding('bindingName') — находит элемент по привязке
данных;by.repeater('repeaterExpression') — используется для
коллекций, созданных с помощью ng-repeat;by.css() и by.id() — стандартные CSS- и
ID-селекторы.Пример поиска элемента по модели:
const usernameInput = element(by.model('user.name'));
await usernameInput.sendKeys('testUser');
Angular-приложения активно используют асинхронные операции. Protractor автоматически ждёт завершения этих операций, однако иногда требуется явное ожидание:
browser.wait с
функцией ожидания, возвращающей true при готовности
элемента;Пример использования ExpectedConditions:
const EC = protractor.ExpectedConditions;
const submitButton = element(by.id('submit'));
await browser.wait(EC.elementToBeClickable(submitButton), 5000);
await submitButton.click();
Protractor совместим с Jasmine, поэтому тесты обычно структурируются
с помощью блоков describe и it:
describe('Форма входа', () => {
it('должна вводить логин и пароль', async () => {
await browser.get('http://localhost:4200/login');
await element(by.model('user.name')).sendKeys('admin');
await element(by.model('user.password')).sendKeys('12345');
await element(by.id('loginButton')).click();
const successMessage = element(by.binding('message'));
expect(await successMessage.getText()).toBe('Добро пожаловать!');
});
});
Блок beforeEach часто используется для настройки
состояния перед каждым тестом, а afterEach — для
очистки.
Angular-компоненты часто имеют сложную структуру, состоящую из дочерних компонентов и шаблонов. Protractor позволяет:
Пример проверки состояния компонента:
const todoList = element.all(by.repeater('todo INTOdos'));
expect(await todoList.count()).toBe(3);
const firstTodoText = await todoList.first().element(by.binding('todo.text')).getText();
expect(firstTodoText).toBe('Купить хлеб');
Protractor позволяет тестировать маршрутизацию Angular-приложений.
Метод browser.get() открывает страницу, а
browser.waitForAngular() обеспечивает синхронизацию. Для
проверки маршрутов можно использовать Angular service
location или считывать
browser.getCurrentUrl():
await browser.get('/dashboard');
expect(await browser.getCurrentUrl()).toContain('/dashboard');
Для упрощения и масштабирования тестов применяется паттерн Page Object Model (POM). В POM создаются отдельные классы для страниц и компонентов, инкапсулирующие локаторы и действия:
class LoginPage {
constructor() {
this.username = element(by.model('user.name'));
this.password = element(by.model('user.password'));
this.loginButton = element(by.id('loginButton'));
}
async login(user, pass) {
await this.username.sendKeys(user);
await this.password.sendKeys(pass);
await this.loginButton.click();
}
}
module.exports = new LoginPage();
Тест с использованием POM становится более чистым:
const loginPage = require('../pages/login.page');
describe('Авторизация', () => {
it('должна успешно входить', async () => {
await browser.get('/login');
await loginPage.login('admin', '12345');
expect(await element(by.binding('message')).getText()).toBe('Добро пожаловать!');
});
});
Для отладки и анализа тестов Protractor поддерживает:
browser.takeScreenshot();browser.manage().logs().get('browser');Пример снятия скриншота при ошибке:
afterEach(async () => {
const png = await browser.takeScreenshot();
require('fs').writeFileSync('screenshot.png', png, {encoding: 'base64'});
});
Protractor легко интегрируется с системами CI/CD. В pipeline можно:
npm install;multiCapabilities;Несмотря на официальное прекращение поддержки Protractor, в существующих проектах важно учитывать:
browser.waitForAngularEnabled(false);async/await упрощает работу с promise и
предотвращает ошибки синхронизации;browser.executeScript.Эти практики обеспечивают стабильное выполнение end-to-end тестов даже в крупных приложениях с динамическим контентом и многочисленными асинхронными процессами.