Try-catch блоки

В среде Protractor обработка ошибок играет ключевую роль, поскольку тесты работают с асинхронным браузерным контекстом, сетевыми задержками и нестабильным DOM. Блоки try-catch используются для перехвата исключений времени выполнения, которые возникают при выполнении синхронного или асинхронного кода, и позволяют управлять поведением теста при сбоях.

В JavaScript конструкция имеет вид:

try {
    // код, потенциально выбрасывающий ошибку
} catch (error) {
    // обработка ошибки
}

В контексте Protractor эта конструкция применяется поверх действий с элементами страницы, ожиданий (ExpectedConditions), пользовательских функций и вспомогательных утилит.


Особенности ошибок в Protractor

Protractor построен поверх WebDriverJS и использует асинхронную модель выполнения. Основные источники ошибок:

  • элемент не найден (NoSuchElementError);
  • таймаут ожидания (TimeoutError);
  • ошибки взаимодействия с DOM (элемент перекрыт, не кликабелен);
  • логические ошибки в тестовом коде.

Большинство таких ошибок выбрасываются в виде исключений JavaScript, которые можно перехватить с помощью try-catch.


try-catch и асинхронный код

Классическая особенность JavaScript заключается в том, что try-catch не перехватывает ошибки внутри Promise, если они не обрабатываются с помощью await.

❌ Некорректный пример:

try {
    element(by.id('save')).click();
} catch (e) {
    // не сработает
}

Метод click() возвращает Promise, и ошибка произойдёт асинхронно.

✅ Корректный пример с async/await:

try {
    await element(by.id('save')).click();
} catch (e) {
    // ошибка будет перехвачена
}

Ключевое правило: try-catch в Protractor работает корректно только при использовании async/await.


Обработка ошибок поиска элементов

Частый сценарий — элемент может отсутствовать, но это допустимо с точки зрения бизнес-логики теста.

async function isElementPresent(locator) {
    try {
        await element(locator).getText();
        return true;
    } catch (e) {
        return false;
    }
}

В этом случае исключение используется как управляющий механизм, а не как фатальная ошибка.


try-catch и ExpectedConditions

Ожидания часто завершаются таймаутом. По умолчанию это приводит к падению теста, но поведение можно изменить.

const EC = protractor.ExpectedConditions;

try {
    await browser.wait(
        EC.visibilityOf(element(by.css('.popup'))),
        5000
    );
} catch (e) {
    // альтернативная логика, если попап не появился
}

Такой подход позволяет:

  • выполнять запасные сценарии;
  • логировать нестандартное поведение;
  • продолжать тест при некритичных сбоях.

Использование try-catch для диагностики

В Protractor важно сохранять контекст ошибки: текущий URL, состояние страницы, значения переменных.

try {
    await element(by.buttonText('Submit')).click();
} catch (e) {
    const url = await browser.getCurrentUrl();
    console.error('Ошибка на странице:', url);
    console.error(e.message);
    throw e;
}

Здесь ошибка перехватывается, дополняется информацией и пробрасывается дальше, что сохраняет корректное падение теста.


Локальная и глобальная обработка ошибок

Локальная обработка

Используется внутри отдельных шагов или функций:

async function safeClick(el) {
    try {
        await el.click();
    } catch (e) {
        await browser.executeScript('arguments[0].click();', el.getWebElement());
    }
}

Подходит для нестабильных элементов интерфейса.

Глобальная обработка

На уровне всего теста:

it('пример теста', async () => {
    try {
        await login();
        await createEntity();
        await validateEntity();
    } catch (e) {
        await browser.takeScreenshot();
        throw e;
    }
});

Позволяет централизованно управлять падением сценария.


Связка try-catch и finally

Блок finally выполняется всегда, независимо от наличия ошибки. В тестах Protractor он полезен для очистки состояния.

try {
    await runScenario();
} catch (e) {
    throw e;
} finally {
    await logout();
}

Типичные задачи finally:

  • возврат в исходное состояние;
  • закрытие модальных окон;
  • очистка данных.

Ошибки, которые не следует подавлять

Некоторые исключения нельзя «глушить», так как они указывают на критическую проблему:

  • ошибки инициализации браузера;
  • некорректные локаторы;
  • ошибки конфигурации Protractor.

Пример неправильного использования:

try {
    await element(by.id('wrong-id')).click();
} catch (e) {
    // пусто
}

Такой код создаёт ложноположительные тесты, которые формально проходят, но не выполняют проверку.


Рекомендации по использованию

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

Типовые шаблоны

Безопасное ожидание элемента:

async function waitOptional(el, timeout = 3000) {
    try {
        await browser.wait(protractor.ExpectedConditions.presenceOf(el), timeout);
        return true;
    } catch {
        return false;
    }
}

Условное выполнение шага:

try {
    await openAdvancedSettings();
    await configureSettings();
} catch {
    // настройки отсутствуют в данной конфигурации
}

Блоки try-catch в Protractor — это инструмент точечного контроля ошибок, а не универсальное средство подавления проблем. Грамотное применение повышает устойчивость тестов, улучшает диагностику и позволяет моделировать сложные ветвления пользовательских сценариев без потери надёжности.