Работа с возвращаемыми значениями

Protractor — инструмент для end-to-end тестирования Angular и не-Angular приложений на JavaScript. Одной из ключевых особенностей является работа с возвращаемыми значениями элементов страницы, асинхронными операциями и ожиданиями. Понимание механизма получения данных из элементов и работы с промисами критично для написания корректных и стабильных тестов.


Получение текста и атрибутов элементов

Метод element(locator) возвращает объект ElementFinder, который не содержит напрямую значения элемента. Чтобы получить текст или атрибут, необходимо использовать методы, возвращающие промис:

let username = element(by.id('username'));

// Получение текста элемента
username.getText().then(text => {
    console.log('Текст элемента:', text);
});

// Получение атрибута
username.getAttribute('value').then(value => {
    console.log('Значение атрибута:', value);
});

Ключевой момент: getText() и getAttribute() всегда возвращают промис. В Protractor 5 и старше использовались методы then() для обработки. В современных версиях с поддержкой async/await код становится более читаемым:

let text = await username.getText();
let value = await username.getAttribute('value');

Работа с асинхронными действиями

Любое взаимодействие с элементами на странице, будь то click(), sendKeys() или getText(), является асинхронным. Protractor изначально использовал control flow, который позволял писать код без явного ожидания промисов, но начиная с последних версий рекомендуется использовать async/await для контроля последовательности действий.

Пример асинхронной цепочки:

let loginButton = element(by.css('.login-button'));
let username = element(by.id('username'));
let password = element(by.id('password'));

await username.sendKeys('testuser');
await password.sendKeys('securepassword');
await loginButton.click();

let successMessage = element(by.css('.success')).getText();
console.log(await successMessage);  // вывод текста после клика

Использование ElementArrayFinder

Для работы с множественными элементами применяется element.all(locator), возвращающий объект ElementArrayFinder. Основные методы:

  • get(index) — получение конкретного элемента по индексу.
  • first() / last() — доступ к первому и последнему элементу.
  • count() — количество найденных элементов.
  • map(fn) — преобразование массива элементов в массив значений.

Пример:

let items = element.all(by.css('.item'));

let firstItemText = await items.first().getText();
let lastItemText = await items.last().getText();
let itemCount = await items.count();

console.log(`Всего элементов: ${itemCount}`);
console.log(`Первый элемент: ${firstItemText}`);
console.log(`Последний элемент: ${lastItemText}`);

Метод map() позволяет получить массив данных всех элементов:

let texts = await items.map(async el => await el.getText());
console.log(texts);  // массив текстов всех элементов

Работа с возвращаемыми значениями промисов

Все методы ElementFinder и ElementArrayFinder возвращают promise. Для правильной работы необходимо использовать:

  • await (современный подход)
  • или .then() для старых версий

Неправильное обращение к промису может привести к тому, что переменная будет содержать не значение элемента, а объект промиса:

let textPromise = element(by.id('header')).getText();
console.log(textPromise); // [object Promise], а не текст

Правильно:

let text = await element(by.id('header')).getText();
console.log(text); // корректный вывод текста

Важность ожиданий

При получении значений с элементов важно учитывать, что элемент может быть еще не загружен или не видим. Использование ExpectedConditions помогает гарантировать получение корректных данных:

let EC = protractor.ExpectedConditions;
let message = element(by.css('.message'));

await browser.wait(EC.visibilityOf(message), 5000);
let text = await message.getText();
console.log(text);

Ожидания предотвращают ошибки, связанные с попыткой прочитать текст до того, как элемент появился на странице.


Преобразование значений

Иногда текст или атрибут необходимо преобразовать перед использованием:

let priceText = await element(by.css('.price')).getText();
let priceNumber = parseFloat(priceText.replace('$', ''));
console.log(priceNumber);

Аналогично можно фильтровать массив значений:

let items = element.all(by.css('.item'));
let prices = await items.map(async el => {
    let text = await el.getText();
    return parseFloat(text.replace('$', ''));
});
let expensiveItems = prices.filter(p => p > 50);
console.log(expensiveItems);

Работа с возвращаемыми булевыми значениями

Методы вроде isDisplayed(), isEnabled(), isSelected() возвращают промис, который резолвится в true или false. Пример:

let submitButton = element(by.id('submit'));
let enabled = await submitButton.isEnabled();

if (enabled) {
    await submitButton.click();
}

Эти методы полезны для проверки состояния элементов до взаимодействия.


Советы по обработке данных

  1. Всегда использовать await при работе с возвращаемыми значениями, чтобы избежать неожиданностей.
  2. Проверять наличие элементов с помощью isPresent() или count() перед попыткой прочитать текст.
  3. Использовать map и filter для обработки массивов элементов и получения удобных массивов данных.
  4. Приводить значения к нужному типу перед сравнениями или расчетами (числа, строки, булевы значения).

Эффективная работа с возвращаемыми значениями позволяет писать стабильные, читаемые тесты и полностью контролировать асинхронное поведение веб-страницы. Правильное использование await, ожиданий и методов ElementFinder/ElementArrayFinder делает тесты предсказуемыми и уменьшает вероятность ошибок, связанных с асинхронностью и динамическим контентом.