Protractor предоставляет встроенные механизмы синхронизации с
Angular-приложениями, но стандартные ожидания (как
browser.wait с простым условием
ExpectedConditions) часто недостаточны для сложных
сценариев. Кастомные условия ожидания позволяют создавать гибкие
проверки состояния элементов, страниц или данных, которые нельзя
реализовать стандартными средствами.
Кастомное ожидание в Protractor — это функция, которая возвращает
Promise, резолвящийся в true или
false. Пример базового синтаксиса:
const customCondition = () => {
return element(by.css('.my-element')).isDisplayed().then(isVisible => {
return isVisible;
});
};
browser.wait(customCondition, 5000, 'Элемент не появился за 5 секунд');
Ключевые моменты:
async/await.Promise<boolean>.browser.wait, а сообщение ошибки
помогает в диагностике.С ростом сложности тестов часто требуется проверять состояния,
которые зависят от нескольких элементов или внешних данных. В таких
случаях удобнее использовать async/await:
const allItemsLoaded = async () => {
const items = await element.all(by.css('.item'));
const statuses = await Promise.all(items.map(async (item) => {
return await item.getText() !== '';
}));
return statuses.every(status => status === true);
};
await browser.wait(allItemsLoaded, 10000, 'Не все элементы загрузились за 10 секунд');
Пояснение:
Promise.all для параллельного получения
данных.true только если все элементы
удовлетворяют условию.Для сложных сценариев часто необходимо объединять несколько условий. Например, нужно дождаться, когда элемент видим и текст в нём изменился:
const elementVisibleAndHasText = async (locator, expectedText) => {
const el = element(locator);
const isVisible = await el.isDisplayed();
const text = await el.getText();
return isVisible && text.includes(expectedText);
};
await browser.wait(() => elementVisibleAndHasText(by.id('status'), 'Готово'), 7000);
Такой подход позволяет создавать многоступенчатые
проверки, которые не покрываются стандартными
ExpectedConditions.
Для повышения читаемости и поддержки тестов рекомендуется выносить кастомные условия в отдельные функции или утилиты:
class CustomConditions {
static elementHasClass(locator, className) {
return async () => {
const el = element(locator);
const classes = await el.getAttribute('class');
return classes.split(' ').includes(className);
};
}
static elementCountMoreThan(locator, count) {
return async () => {
const elements = await element.all(locator);
return elements.length > count;
};
}
}
// Использование
await browser.wait(CustomConditions.elementHasClass(by.css('.btn'), 'active'), 5000);
await browser.wait(CustomConditions.elementCountMoreThan(by.css('.list-item'), 3), 5000);
Преимущества:
ExpectedConditionsProtractor позволяет интегрировать кастомные условия с существующими
ExpectedConditions:
const EC = protractor.ExpectedConditions;
const customCondition = async () => {
const el = element(by.css('.notification'));
const text = await el.getText();
return text.includes('Успешно');
};
await browser.wait(EC.and(EC.visibilityOf(element(by.css('.notification'))), customCondition), 5000);
Таким образом можно комбинировать стандартные и кастомные проверки, что делает ожидания более гибкими и точными.
При сложных условиях важно добавлять логирование для понимания причин срабатывания таймаута:
const waitForText = async (locator, expectedText) => {
const el = element(locator);
return await browser.wait(async () => {
const text = await el.getText();
console.log(`Текущий текст: ${text}`);
return text.includes(expectedText);
}, 5000, `Текст элемента ${locator} не соответствует ожидаемому`);
};
Это позволяет:
element(locator) внутри
цикла; лучше сохранять ссылку на элемент.Promise.all для параллельных проверок
нескольких элементов.Кастомные условия ожидания в Protractor дают полный контроль над синхронизацией тестов. Они позволяют обрабатывать сложные сценарии, комбинировать условия и делать проверки более точными и читаемыми, что особенно важно в больших Angular-проектах.