Protractor — это инструмент для end-to-end (E2E) тестирования веб-приложений на Angular и других SPA. Его ключевое преимущество — интеграция с Angular, возможность работы с асинхронными операциями и синхронизация с Angular-зоной, что облегчает управление ожиданиями элементов. Для написания поддерживаемых тестов важно соблюдать структурированные подходы и использовать возможности Protractor эффективно.
Файл конфигурации protractor.conf.js определяет
поведение тестового фреймворка. Основные параметры:
exports.config = {
framework: 'jasmine',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['specs/**/*.spec.js'],
capabilities: {
browserName: 'chrome'
},
baseUrl: 'http://localhost:4200',
onPrepare: () => {
browser.waitForAngularEnabled(true);
},
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
}
};
baseUrl повышает гибкость тестов.Тесты в Protractor организуются в виде describe и it блоков:
describe('Авторизация пользователя', () => {
beforeEach(() => {
browser.get('/login');
});
it('должна отображать форму логина', () => {
const loginForm = element(by.css('form.login-form'));
expect(loginForm.isPresent()).toBe(true);
});
it('должна успешно авторизовывать пользователя', () => {
element(by.name('username')).sendKeys('testuser');
element(by.name('password')).sendKeys('password');
element(by.buttonText('Войти')).click();
expect(browser.getCurrentUrl()).toContain('/dashboard');
});
});
Ключевые моменты:
describe — логическая группа тестов.beforeEach — код, выполняющийся перед каждым тестом.
Позволяет минимизировать дублирование.it — отдельный тест. Названия тестов должны быть
понятными и отражать поведение приложения.Protractor предоставляет несколько способов поиска элементов:
const usernameField = element(by.model('user.username'));
const submitButton = element(by.buttonText('Submit'));
Для коллекций элементов используется element.all:
const items = element.all(by.repeater('item in items'));
expect(items.count()).toBe(5);
Использование коллекций упрощает проверки списков и таблиц.
Protractor управляет асинхронными операциями через
Promises, но начиная с версии 5 рекомендуется
использовать async/await:
it('должен ждать появления сообщения', async () => {
const message = element(by.css('.success-msg'));
await browser.wait(protractor.ExpectedConditions.visibilityOf(message), 5000);
expect(await message.getText()).toContain('Успешно');
});
Основные моменты:
browser.wait с ExpectedConditions
позволяет контролировать динамические изменения DOM.await для получения значений
элементов.sleep, чтобы тесты оставались
быстрыми и надежными.Для поддерживаемых тестов рекомендуется применять Page Object — паттерн, отделяющий логику взаимодействия с UI от тестов:
class LoginPage {
constructor() {
this.username = element(by.name('username'));
this.password = element(by.name('password'));
this.loginButton = element(by.buttonText('Войти'));
}
async login(user, pass) {
await this.username.sendKeys(user);
await this.password.sendKeys(pass);
await this.loginButton.click();
}
}
module.exports = new LoginPage();
Использование в тесте:
const loginPage = require('../pages/login.page');
it('должен авторизовать пользователя', async () => {
await loginPage.login('testuser', 'password');
expect(await browser.getCurrentUrl()).toContain('/dashboard');
});
Преимущества:
nth-child, лучше
использовать id, data-test атрибуты.onPrepare, чтобы не дублировать их в каждом тесте.afterEach(async () => {
const png = await browser.takeScreenshot();
// сохранить png в лог
});
Protractor хорошо интегрируется с Jenkins, GitHub Actions, GitLab CI.
Рекомендуется запускать E2E тесты параллельно с unit-тестами, используя
multiCapabilities для тестирования в разных браузерах:
multiCapabilities: [
{ browserName: 'chrome' },
{ browserName: 'firefox' }
]
Параллельное выполнение ускоряет тестирование и повышает стабильность при кросс-браузерной проверке.
Эта структура и методы обеспечивают написание поддерживаемых, читаемых и надежных тестов в Protractor, которые легко масштабируются и адаптируются к изменениям веб-приложения.