Фильтрация данных таблицы

Фильтрация данных таблицы — одна из ключевых задач автоматизированного тестирования веб-приложений, где необходимо проверять корректность отображения информации при различных условиях поиска и сортировки. В Protractor для работы с таблицами используется сочетание CSS-селекторов, XPath и встроенных методов WebDriver, что позволяет гибко управлять элементами и проверять их содержимое.


Поиск таблицы и строк

Для начала необходимо идентифицировать таблицу на странице:

let table = element(by.css('table#users'));

Для выборки всех строк таблицы используется element.all:

let rows = table.all(by.css('tbody tr'));

Каждая строка представлена как отдельный элемент, с которым можно работать аналогично обычному WebElement:

rows.get(0).element(by.css('td:nth-child(1)')).getText().then(text => {
    console.log(text);
});

Ключевой момент: element.all возвращает ElementArrayFinder, который поддерживает методы фильтрации, поиска и итерации по элементам.


Фильтрация с использованием filter

Метод filter позволяет отобрать элементы на основании заданного условия. Для фильтрации строк таблицы по содержимому ячейки:

let filteredRows = rows.filter(async (row) => {
    let name = await row.element(by.css('td.name')).getText();
    return name.includes('Иванов');
});

Здесь filter принимает асинхронную функцию, которая должна возвращать true для элементов, которые удовлетворяют условию.

Для проверки количества найденных строк можно использовать:

filteredRows.count().then(count => {
    console.log(`Найдено ${count} строк с именем Иванов`);
});

Использование map для извлечения данных

Для работы с содержимым таблицы часто нужно получить массив значений из определённого столбца:

let names = rows.map(async (row) => {
    return await row.element(by.css('td.name')).getText();
});

names.then(arr => console.log(arr));

Метод map возвращает Promise массива текстовых значений, что удобно для последующих проверок или фильтраций средствами Jav * aScript:

names.then(arr => {
    let filtered = arr.filter(name => name.startsWith('А'));
    console.log(filtered);
});

Комбинированная фильтрация по нескольким столбцам

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

let activeUsers = rows.filter(async (row) => {
    let name = await row.element(by.css('td.name')).getText();
    let status = await row.element(by.css('td.status')).getText();
    return name.startsWith('А') && status === 'Активен';
});

Совет: Всегда использовать await внутри асинхронных функций для корректного получения текста ячеек. Без этого фильтрация может работать некорректно.


Проверка наличия элементов

Для проверки, что отфильтрованные строки существуют на странице, применяется метод isPresent или count:

activeUsers.count().then(count => {
    if (count > 0) {
        console.log('Активные пользователи найдены');
    } else {
        console.log('Совпадений не найдено');
    }
});

Динамическая фильтрация с поисковыми полями

Многие таблицы имеют встроенный поиск. Для тестирования динамической фильтрации можно вводить текст в поле поиска и ожидать обновления таблицы:

let searchInput = element(by.css('input#search'));
searchInput.sendKeys('Иванов');

let filtered = rows.filter(async (row) => {
    let name = await row.element(by.css('td.name')).getText();
    return name.includes('Иванов');
});

Для корректной работы с динамическими таблицами рекомендуется использовать ожидания:

let EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(filtered.first()), 5000);

Сортировка и фильтрация одновременно

Если таблица поддерживает сортировку по заголовкам, фильтрацию можно комбинировать с сортировкой для проверки последовательности данных:

let header = table.element(by.css('th.name'));
header.click(); // сортировка по имени

let sortedNames = rows.map(async (row) => {
    return await row.element(by.css('td.name')).getText();
});

sortedNames.then(arr => console.log(arr));

После этого можно применять фильтры к отсортированному массиву для проверки логики отображения данных.


Работа с асинхронными итерациями

Важно помнить, что все методы filter, map и getText возвращают промисы. Для удобства часто используется async/await:

(async () => {
    let rowsArray = await rows;
    for (let row of rowsArray) {
        let status = await row.element(by.css('td.status')).getText();
        if (status === 'Активен') {
            let name = await row.element(by.css('td.name')).getText();
            console.log(name);
        }
    }
})();

Такой подход обеспечивает последовательное выполнение операций и предотвращает ошибки из-за неполных данных.


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

  • Использовать четкие CSS-классы или идентификаторы, чтобы минимизировать ошибки при выборе элементов.
  • Применять filter вместо ручной итерации по массиву, это упрощает код и делает его читабельным.
  • Всегда проверять асинхронные операции, особенно при работе с динамическими таблицами.
  • Для больших таблиц можно комбинировать фильтры и slice, чтобы обрабатывать только видимые элементы, повышая скорость тестов.
  • Использовать ExpectedConditions для синхронизации при работе с изменяемым контентом.

Фильтрация данных таблицы в Protractor сочетает в себе мощь селекторов и гибкость асинхронного программирования. Правильное применение методов filter, map, count и ExpectedConditions позволяет надежно проверять сложные сценарии отображения и поиска данных.