Цепочки Promise

Protractor построен на основе Selenium WebDriver и использует концепцию Promise для управления асинхронными операциями в JavaScript. Важнейшей особенностью является то, что все действия с браузером — будь то поиск элемента, клик, ввод текста или проверка состояния — возвращают объект Promise. Это позволяет создавать последовательные цепочки действий, обеспечивая корректный порядок выполнения тестов.


Основы работы с Promise

Каждый метод Protractor, например element(by.css('.btn')).click(), возвращает Promise, который представляет собой будущий результат асинхронной операции. Promise может находиться в трёх состояниях:

  • pending (ожидание) — операция выполняется;
  • fulfilled (выполнено) — операция завершена успешно, результат доступен;
  • rejected (отклонено) — операция завершена с ошибкой.

Для обработки результата Promise используется метод .then(). Пример:

element(by.id('submit')).click().then(function() {
    console.log('Клик выполнен');
});

В данном случае код внутри .then() выполнится только после успешного завершения клика.


Создание цепочек

Цепочки Promise позволяют последовательно выполнять несколько асинхронных операций без явного вложения функций. Структура цепочки выглядит так:

element(by.id('username')).sendKeys('admin')
    .then(() => element(by.id('password')).sendKeys('12345'))
    .then(() => element(by.id('login')).click())
    .then(() => console.log('Авторизация выполнена'));

Преимущества цепочек:

  • последовательность операций сохраняется;
  • избегается “адская пирамида колбэков”;
  • удобная обработка ошибок через .catch().

Возврат значений из цепочек

Любой .then() может возвращать результат, который станет входным параметром для следующего шага цепочки. Например:

element(by.id('message')).getText()
    .then(text => {
        console.log('Сообщение: ' + text);
        return text.length;
    })
    .then(length => {
        console.log('Длина текста: ' + length);
    });

В данном случае значение text.length передаётся в следующую функцию .then().


Обработка ошибок

Для обработки ошибок в цепочках используется .catch(). Он перехватывает любое исключение, возникшее в предыдущих шагах цепочки:

element(by.id('login')).click()
    .then(() => element(by.id('welcome')).getText())
    .then(text => console.log(text))
    .catch(err => console.error('Произошла ошибка:', err));

Также можно использовать finally(), чтобы выполнить действия независимо от успеха или ошибки:

element(by.id('logout')).click()
    .finally(() => console.log('Попытка выхода завершена'));

Цепочки с условиями и ветвлением

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

element(by.id('modal')).isDisplayed()
    .then(isVisible => {
        if (isVisible) {
            return element(by.id('closeModal')).click();
        } else {
            return Promise.resolve();
        }
    })
    .then(() => console.log('Модальное окно обработано'));

Если элемент не виден, возвращается Promise.resolve(), чтобы цепочка продолжилась без ошибок.


Использование async/await с Protractor

Современный стиль работы с Promise в Protractor предполагает использование async/await. Это делает код более читаемым, сохраняя последовательность выполнения:

it('должен авторизоваться', async () => {
    await element(by.id('username')).sendKeys('admin');
    await element(by.id('password')).sendKeys('12345');
    await element(by.id('login')).click();
    const message = await element(by.id('welcome')).getText();
    console.log(message);
});

async/await заменяет длинные цепочки .then(), сохраняя при этом всю функциональность Promise, включая обработку ошибок через try/catch:

try {
    await element(by.id('login')).click();
} catch (err) {
    console.error('Ошибка при клике:', err);
}

Практические рекомендации

  • Минимизировать глубокие вложенные .then(), предпочитая цепочки или async/await.
  • Возвращать Promise внутри .then(), чтобы сохранить корректное последовательное выполнение.
  • Использовать .catch() или try/catch для обработки любых возможных ошибок.
  • Проверять состояние элементов перед действиями, чтобы избежать ошибок выполнения из-за отсутствующих или невидимых элементов.

Цепочки Promise являются фундаментальной концепцией Protractor и обеспечивают надёжное управление асинхронностью, позволяя строить стабильные и читаемые тесты для веб-приложений.