Одной из ключевых проблем при работе с Protractor является неправильное использование ожиданий и асинхронности. Protractor построен поверх WebDriverJS и использует промисы для управления асинхронными операциями, однако при неправильном подходе тесты становятся нестабильными и хрупкими.
Не использовать browser.sleep() для
синхронизации browser.sleep(ms) останавливает
выполнение на фиксированное время, что замедляет тесты и не гарантирует
стабильность. Вместо этого следует применять explicit
waits:
const EC = protractor.ExpectedConditions;
const button = element(by.id('submit-button'));
browser.wait(EC.elementToBeClickable(button), 5000);
button.click();
Этот подход обеспечивает ожидание события только до его наступления, а не на произвольное время.
Использовать async/await корректно
Protractor с последними версиями NodeJS поддерживает
async/await. Пренебрежение этим приводит к неправильной
последовательности действий:
// Плохо
element(by.id('input')).sendKeys('test');
element(by.id('submit')).click();
// Правильно
await element(by.id('input')).sendKeys('test');
await element(by.id('submit')).click();
Без await операции могут выполняться одновременно,
вызывая ошибки типа element not interactable.
Правильный выбор локаторов напрямую влияет на стабильность тестов.
Использовать CSS и ID вместо XPath при возможности XPath медленнее и более подвержен ломанию при изменении структуры DOM. Пример:
// Предпочтительно
element(by.css('#login-button'));
// Менее надежно
element(by.xpath('//div[@class="login"]/button'));Избегать жёстких цепочек локаторов Слишком
глубокие вложенные локаторы увеличивают риск ошибок при изменении UI.
Вместо этого применять более универсальные селекторы и
by.cssContainingText:
element(by.cssContainingText('.menu-item', 'Settings')).click();Нестабильные тесты часто связаны с зависимостью от состояния предыдущих тестов.
Использовать beforeEach и
afterEach для подготовки и очистки состояния
Например, очищение cookies, локального хранилища или возврат на
начальную страницу:
beforeEach(async () => {
await browser.get('https://example.com');
await browser.manage().deleteAllCookies();
});Избегать зависимости от данных из предыдущих тестов Каждый тест должен быть автономным. Если один тест упал — это не должно ломать остальные.
Protractor изначально создавался для Angular-приложений, что создаёт особые нюансы:
Не отключать waitForAngularEnabled без
причины browser.waitForAngularEnabled(false)
отключает ожидания Angular. Использовать только для не-Angular страниц,
иначе тесты станут нестабильными.
Ожидание появления элементов Angular Angular
может динамически рендерить элементы. Применение
ExpectedConditions.visibilityOf гарантирует, что элемент
доступен для взаимодействия:
const message = element(by.binding('statusMessage'));
await browser.wait(EC.visibilityOf(message), 5000);Ловить ошибки при взаимодействии с элементами Элементы могут исчезнуть или быть недоступны. Применение конструкций типа:
try {
await element(by.id('delete-button')).click();
} catch (error) {
console.warn('Кнопка удаления недоступна', error);
}
позволяет тесту корректно обрабатывать непредвиденные ситуации.
Использовать повторные попытки для нестабильных тестов В Protractor можно реализовать логику повторного выполнения шага при временной недоступности элемента, что улучшает устойчивость тестов.
Следовать паттерну Page Object Разделение логики тестов и работы с элементами повышает читаемость и снижает риск ошибок. Пример структуры:
// login.page.js
class LoginPage {
constructor() {
this.username = element(by.id('username'));
this.password = element(by.id('password'));
this.submitBtn = element(by.id('login-button'));
}
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('./login.page');
it('должен успешно войти', async () => {
await loginPage.login('admin', '1234');
expect(await element(by.id('welcome-message')).isDisplayed()).toBe(true);
});
Такой подход минимизирует дублирование кода и упрощает сопровождение тестов.
Добавление логов при критичных шагах Это позволяет быстро выявлять проблемные места в тестах:
console.log('Кликаем кнопку отправки формы');
await submitButton.click();Использовать скриншоты при падении теста
Protractor поддерживает создание скриншотов через
browser.takeScreenshot(), что помогает анализировать
причины падений.
sleep() вместо ожиданий.Эффективное применение этих практик делает тесты на Protractor стабильными, ускоряет их выполнение и упрощает поддержку большого объема автотестов в реальных проектах.