Тестирование неочевидного: баги в фильтрах, UX и логике подбора товаров

Фильтрация товаров на сайте кажется простой функцией, но на практике в ней скрыто много нюансов. Небольшие недочеты могут приводить к неочевидным багам – от неправильной работы логики отбора до проблем в интерфейсе. Рассмотрим основные виды фильтров и их особенности на примере матрасов проекта Askona, обсудим UX-принципы при проектировании фильтрации, типичные ошибки реализации, а также методы тестирования логики подбора товаров.

Виды фильтров: фасетные, сквозные, многослойные

Фасетные фильтры. Фасетный (атрибутный) фильтр позволяет отбирать товары сразу по нескольким характеристикам – цвету, размеру, цене, материалу и т.д. Например, матрасы на сайте можно одновременно фильтровать по жесткости, размерам, высоте, типу наполнителя, ценовому диапазону и другим параметрам. В интерфейсе такие фильтры обычно представлены группами чекбоксов, переключателей или слайдеров для каждого свойства. Важно, что фасетная система подбирает значения динамически: после выбора одного фильтра остальные автоматически подстраиваются, убирая варианты, которые больше не подходят под текущую выборку. Благодаря этому фасетный поиск стремится не выдавать пустых результатов – недоступные комбинации просто исключаются из доступных опций. Правильно настроенные фасетные фильтры существенно улучшают поиск товаров и даже повышают конверсию магазина (по некоторым данным – на 25% и более). На практике в Askona фасетные фильтры – это основной способ отбора: пользователь может, к примеру, отметить жесткость «Средняя» и материал «Латекс», и увидеть все матрасы, удовлетворяющие обоим условиям.

Сквозные фильтры. Сквозными называют фильтры, действующие не в пределах одной категории, а по всему каталогу сразу. Классический пример – фильтр по бренду. Если пользователь выбирает бренд (например, Askona или Serta), сайт отберет все товары этого бренда во всех разделах магазина. В проекте Askona брендовый фильтр реализован как отдельная страница: кликнув на название бренда, покупатель увидит матрасы, подушки, кровати и другие товары данной марки на едином списке. Сквозные фильтры также могут включать, например, признак «Акция/Скидка» – при его применении выводятся все уцененные товары по всему сайту. Особенность сквозных фильтров в том, что они действуют глобально: в отличие от фасетных, привязанных к атрибутам внутри текущей категории, сквозной фильтр игнорирует границы разделов и подтягивает любой релевантный товар со всего каталога. Это удобно для пользователей, которые хотят просматривать товары по общему критерию (бренду, распродаже, новинкам и т.п.), не думая о структуре каталога.

Многослойные (иерархические) фильтры. Многослойная фильтрация подразумевает пошаговый отбор: сначала пользователь сужает выбор по одному крупному признаку, затем по другому, более детальному, и так далее. Фактически, это фильтры с иерархией или зависимостями между параметрами. Пример из Askona – подбор матраса по параметрам. Разработчики сгруппировали коллекции матрасов так, что сначала можно отфильтровать матрасы по жесткости, потом по типу конструкции или по материалу наполнителя. То есть на первом “слое” пользователь выбирает, скажем, жесткость «Жесткая», и только после этого ему предлагаются доступные типы матрасов (пружинный, беспружинный и др.) и материалы, которые есть среди жестких моделей. Такой подход упрощает выбор: человек не видит сразу десятки фильтров, а шаг за шагом отвечает на вопросы, сужая список товаров. Многослойные фильтры часто реализуются в формате мастера подбора или пошагового анкетирования. Например, на Askona был интегрирован специальный сервис подбора: он задает пользователю ключевые вопросы (желаемая жесткость, размер, предпочитаемый материал и т.д.) и на основе ответов формирует подборку подходящих матрасов. Важно, что в многослойной модели фильтры могут быть зависимы: выбор значения на первом шаге ограничивает варианты на втором, что похоже на поведение фасетных фильтров, но организовано последовательными этапами.

UX-принципы при проектировании фильтрации

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

  • Понятность и правильные обозначения. Фильтры должны быть названы языком пользователя и однозначно понятны. Названия не должны вызывать вопросов или требовать догадок. Например, лучше использовать простое название «Жесткость матраса», чем технический термин вроде «Индекс упругости». Если фильтр подразумевает единицы измерения (см, кг, ₽), их стоит указывать прямо в названии или в интерфейсе – так пользователь сразу поймет, о чем идет речь. Также важно, чтобы названия помещались целиком и не обрезались в UI. В проекте Askona этому уделялось внимание: фильтры имеют очевидные названия («Цена», «Размер», «Для кого», «Акция» и т.д.), благодаря чему пользователи без труда ориентируются. Если какие-то фильтры специфичны и могут быть неясны (например, параметр матраса «независимый пружинный блок»), желательно сопровождать их подсказками или пояснениями. Простой язык и понятные ярлыки повышают доверие: человек сразу видит, как можно сузить поиск, и не тратит время на разгадку смысла фильтра.
  • Обратная связь и видимость результатов. Хороший интерфейс фильтрации всегда дает пользователю понять, что происходит при выборе опций. Визуальная обратная связь начинается с мелочей: при наведении на интерактивный элемент фильтра он подсвечивается или меняет курсор, давая понять, что по нему можно кликнуть. После применения фильтра пользователь должен заметить изменения: список товаров обновляется, счётчик результатов (если предусмотрен) показывает новое количество, а выбранный фильтр выделяется как активный. Например, если фильтр требует нажать кнопку «Применить», на ней часто отображают количество найденных товаров ("Показать 8 товаров"), чтобы юзер понимал результат ещё до клика. В Askona фильтрация применяется автоматически при выборе опции – страница сразу перегружает список товаров под новые условия. Если комбинация фильтров привела к пустому результату, интерфейс не должен оставить человека в неопределенности. Сайт отображает понятное сообщение, например: «Таких товаров нет. Попробуйте изменить условия фильтра», и сразу дает кнопку сброса. Этот подход реализован в Askona: при отсутствии результатов пользователь видит уведомление и ссылку «Сбросить фильтры», чтобы одним нажатием убрать все критерии и начать заново. Такая обратная связь чрезвычайно важна – она предотвращает ситуацию, когда пользователь думает, что сайт «сломался» или завис, хотя на самом деле просто не нашлось товаров под заданные фильтры. Кроме того, активные фильтры всегда видны: хорошей практикой считается показывать выбранные параметры отдельными метками (т.н. “бабблы”) в верхней части списка. Пользователь на ходу видит, какие фильтры применены, и может быстро их отключить по одному, не прокручивая всю панель. Подобные UX-мелочи, реализованные и в проекте Askona, делают процесс подбора товаров более прозрачным и дружелюбным.
  • Предотвращение ошибок пользователя. Идеальный интерфейс фильтрации спроектирован так, чтобы минимизировать вероятность некорректных действий. Один из способов – не давать выбрать взаимоисключающие или бесполезные комбинации. Как мы упоминали, фасетная логика сама скрывает недоступные значения: например, если в каталоге Askona нет мягких матрасов размером 200x200, то после выбора размера 200x200 вариант «Мягкая» может автоматически исчезнуть или стать неактивным. Пользователю просто не дадут “зайти в тупик” с заведомо пустым результатом. Это ключевое отличие умного фильтра от примитивного. Также предотвращать ошибки помогает валидация ввода: если фильтр требует ручного ввода (скажем, минимальной цены или длины), интерфейс должен ограничивать недопустимые значения. Например, поле цены может не позволять ввести буквы или отрицательные числа, а при выходе за диапазон – подсветить ошибку. В Askona диапазон цен задается слайдером и полями ввода, где заданы мин/макс – это исключает ошибку ввода вне диапазона. Другой аспект – сохранение контекста: если пользователь применил фильтры и открыл товар, а затем вернулся назад, сайт должен по возможности сохранить ранее выбранные фильтры. Иначе человек может запутаться, почему список снова полный – у него создастся ощущение, что произошел сброс. В случае Askona фильтры являются частью URL, поэтому при возврате по браузеру они сохраняются, что предотвращает неожиданное “обнуление” результатов. Ну и конечно, интерфейс должен иметь понятный способ отменить фильтрацию (кнопка «Очистить все фильтры»), и этот элемент не должен быть спрятан. Кнопка сброса, как правило, отображается только когда есть что сбрасывать – это тоже своего рода защита от ошибки: если фильтры не активны, элемент сброса не показывается, чтобы не сбивать с толку. Подводя итог: UX-фильтрация должна быть предсказуемой – пользователь в любой момент понимает, какие критерии стоят, как их убрать, и почему он видит тот или иной набор товаров.

Типовые паттерны и ошибки при реализации фильтров

  • Сброс параметров фильтра. Баги, связанные с очисткой фильтров, встречаются очень часто. Например, кнопка «Сбросить фильтры» может не очищать какой-то один параметр или делать это не полностью. Бывает так когда после сброса фильтров ползунок цен оставался на прежней позиции (хотя товары показываются верно). Визуально у пользователя создается впечатление, что диапазон цены всё ещё применен. Другой вариант проблемы – непреднамеренный сброс: фильтры сбрасываются тогда, когда не должны. Скажем, покупатель отфильтровал матрасы по размеру и перешел на страницу товара, а после возвращения назад список вдруг оказался полным, хотя ожидался отфильтрованный – это раздражает. Причиной может быть неправильно настроенный кэш или обновление страницы без сохранения состояния. Здесь необходимо специально проверять подобные сценарии: возвращать Back из карточки товара, переходить между категориями с активными фильтрами, чтобы убедиться, что параметры не “слетают” сами собой. Ещё один нюанс – частичный сброс при повторном открытии страницы. Если фильтры хранятся в сессии, но не в URL, новый визит пользователя может начаться с неожиданно сохраненных старых критериев. Все эти кейсы нужно продумывать. Решение обычно одно: явно сбрасывать фильтры при смене категорий (если старые не применимы) и хранить состояние фильтрации в адресной строке или в локальном хранилище, чтобы “назад” работало ожидаемо. Тестировщики на проекте обязательно проверяют корректность работы кнопки сброса и отсутствие «фантомных» фильтров – когда интерфейс кажется чистым, а на самом деле запрос к серверу всё ещё содержит ограничение. Подобный баг легко выявить через DevTools, увидев в сети запрос с лишним параметром, и его нужно сразу фиксить.
  • Некорректная логика сочетания фильтров. Фильтрация – это по сути применение нескольких условий отбора, и очень важно, чтобы логические операторы между ними были реализованы верно. Стандартно действует правило: между разными фильтрами – логическое И (AND), между значениями внутри одного фильтра – логическое ИЛИ (OR). То есть, если пользователь выбирает несколько значений в одном фильтре (например, два бренда), товары подходят под любой из них (BrandA OR BrandB). А вот если выбраны фильтры по разным свойствам (например, бренд и жесткость), товар должен удовлетворять обоим критериям одновременно (BrandA AND Medium hardness). На практике ошибки случаются, когда разработчики путают эти связи. Возможен баг, при котором выбор двух значений в одном фильтре работает как AND – тогда система пытается найти товар, имеющий сразу два бренда одновременно, что невозможно, и выдает пустой список. Обратный случай: фильтры по разным свойствам вдруг работают как OR – тогда при выборе «Askona И жесткий» пользователь получит все жесткие матрасы плюс все матрасы Askona, даже мягкие, то есть фактически лишний товар. Подобный сбой я однажды наблюдала при тестировании: комбинация фильтров давала слишком широкий результат, явно включающий лишние позиции. Анализ через DevTools показал, что на бэкенд уходит неверно сформированный запрос (параметры объединены как «или» вместо «и»). Я задокументировала это поведение и привела примеры, после чего логика была исправлена. Выявить такие баги помогает тест-дизайн на разные сочетания: здесь прописываем кейсы как на единичные фильтры, так и на их одновременное применение. Например, в тест-кейсе ожидается, что при выборе фильтра A и B в списке останутся только товары, удовлетворяющие обоим. Если фактически появляется что-то лишнее или список пуст при наличии подходящих товаров – налицо ошибка логики. Особенно важно проверять граничные случаи: когда значения пересекаются. Например, матрас со значением «средней/высокой жесткости» – вдруг он попадет не в ту выборку, если логика не учтет двойные атрибуты. В Askona матрасы имеют четкие градации жесткости, но если бы была комбинация (например, универсальной жесткости), ее фильтрация потребовала бы особого внимания.
  • Рассинхрон фильтров с данными. Еще одна категория неочевидных багов – это расхождение между тем, что показывают фильтры, и реальными данными каталога. Классический пример: фильтр отображает значение, которого уже нет ни у одного товара. Такое бывает, если товарные данные обновились, а кеш фасетных значений – нет. Например, в Askona могли убрать из продажи матрасы высотой 45 см, но фильтр «Высота: 45 см» по-прежнему присутствует и показывает (0) товаров. Пользователь, выбрав его, увидит пустоту (хорошо если с сообщением), хотя сам факт наличия неактуального пункта – баг. Обратная ситуация: в каталоге появились товары с новым свойством, а фильтр его не отображает. Можно сталкиваться с этим, когда добавили новый размер матраса, но он не появился в списке размеров фильтра, пока не обновили индекс. Такие проблемы обычно кроются в механизмах индексации или кэширования: фасетные фильтры часто строятся на предрассчитанных данных (например, в ElasticSearch), которые могут запаздывать относительно обновлений каталога. Чтобы выявить рассинхрон, тестировщики сверяют JSON-данные от бэкенда с фактическим UI. Например, через DevTools можно посмотреть ответ API с перечнем фильтров и количеством товаров. Если в ответе для значения X указано count: 5, мы ожидаем увидеть 5 товаров при выборе X. Если их меньше или больше – повод разобраться. В одном из случаев я обнаружила, что count в JSON не уменьшается при одновременном применении нескольких фильтров – т.е. бэкенд возвращал некорректные числа. Хотя на сам список товаров это не влияло, но сбивало с толку: фильтр показывал “Жесткость: Мягкая (12)”, а при активном другом фильтре товаров могло оказаться меньше. Подобные баги я описывала, прикладывая выгрузку JSON с несоответствием. Ещё рассинхрон проявляется, когда есть внешние ограничения: например, на Askona можно скрывать товары “нет в наличии”, но фильтры изначально считают все товары. В результате в фильтре может быть написано «Размер 160x200 (10 товаров)», а по факту на странице 8 (потому что 2 закончились и скрыты). Такое несоответствие тоже считается багом или, как минимум, задачей на улучшение логики – нужно либо обновлять цифры динамически, либо не учитывать отсутствующие товары изначально. Я в тестировании обращаю внимание на такие детали, потому что для пользователя это выглядит как ошибка (“фильтр обещал 10 товаров, а показал 8”). Решение – более тонкая синхронизация фронтенда с актуальным состоянием склада и каталога. Практический совет: при тестировании сложных фильтров всегда полезно заглядывать “под капот” – смотреть сетевые ответы, API и сырой JSON. Это помогает поймать расхождения, которые не сразу видны глазами, и уверенно указать проблему разработчикам.

Методы тестирования фильтров и логики подбора

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

  • Ручное тестирование UI. Прежде всего здесь нужно исследовать фильтры глазами пользователя: заходим в различные категории (матрасы, подушки, аксессуары) и пробуем все доступные опции. Такой изучающий подход помогает выявить явные проблемы – например, фильтр не реагирует на нажатие, или выпадающий список уходит за пределы экрана (бывает и такое). Далее проверяем, что каждый фильтр действительно влияет на список товаров и отрабатывает без сбоев. На этапе ручного тестирования важно действовать методично: менять параметры по одному и в разных комбинациях, отслеживая, соответствует ли результат ожиданиям. Здесь пригодилась бы экспертиза по самому каталогу Askona – какие товары должны отображаться при тех или иных фильтрах. Например, фильтр «Жесткость: Мягкая» в категории матрасов не должен показывать матрасы серии XX, потому что они все жесткие; если бы один вдруг появился, это явный баг данных. Такой ориентир на ожидания (oracle) позволяет быстро засечь ошибки. Конечно, полностью вручную перебрать десятки комбинаций сложно, поэтому…
  • Тщательный тест-дизайн случаев. Необходимо составить набор тест-кейсов, покрывающих основные сценарии фильтрации. Он включает случаи: 1) одиночный фильтр, 2) несколько фильтров вместе, 3) снятие фильтра, 4) полный сброс, 5) отсутствие результатов, 6) граничные значения. Например, один сценарий проверял выбор одного фильтра из списка – убедиться, что список товаров сузился корректно и при отключении фильтра вернулся к исходному состоянию. Другой сценарий – одновременный выбор нескольких фильтров (например, Бренд A + Акция) и проверка, что остаются только товары бренда A со скидкой. Обязательный пункт – тест «Очистить все фильтры», который должен вернуть список ко всему ассортименту. Также далее планируем кейс на ситуацию No matching data: когда при определенной комбинации товаров нет, приложение должно отобразить сообщение, как в случае с проектом Askona, а не просто пустую страницу. Отдельно уделим внимание динамическому обновлению: проверим, что если фильтры на сайте применяются без кнопки, при каждом клике список обновляется мгновенно и без глюков (никаких “старых” товаров не остается, новые не дублируются и т.п.)
  • Такой структурированный набор случаев позволит охватить максимум ситуаций системно, а не хаотично, что очень важно в работе тестировщика. Также нужно подумать и о неочевидных сочетаниях: например, фильтрация + сортировка (чтобы сортировка правильно работала на урезанном списке) или фильтрация + пагинация (если товаров много и они разбиваются на страницы). В тестах нужно описывать и ожидаемое поведение системы, и UI-реакцию – чтобы эти ожидания потом легли в основу баг-репортов, когда реальность расходилась с планом.
  • Граничные значения и экстремальные кейсы. Как и при любом функциональном тестировании, нужно проверить границы фильтров. Для числовых диапазонов (цена, высота матраса) пробовать минимальные и максимальные значения, вводить предельные цифры. Например, выставляем ползунки цены на самый минимум и максимум, чтобы убедиться, что алгоритм включает товары ровно в заданном диапазоне (важно, граничные товары тоже попадают). Пробовать оставить поле цены пустым или ввести некорректные данные (буквы, лишние знаки) – интерфейс не должен это принять. Для категорийных фильтров нужно искать крайние случаи: фильтр с единственным возможным значением (например, если в категории остались товары только одного бренда – будет ли фильтр «Бренд» активен и корректно ли себя ведет?). Ещё интересный экстремальный случай – выбор всех фильтров сразу. Далее отмечаем галочками вообще все свойства (если интерфейс позволял мультивыбор повсеместно) и смотрим, что получится. В теории выбор всех значений равносилен отсутствию фильтра, но система могла повести себя по-разному. В случае с Askona, например, можно выбрать сразу несколько жесткостей, материалов, размеров – фактически пользователь хочет «все подходящее любого вида, кроме исключенных». Далее проверяем, что при выборе всех опций фильтра выдача равна исходной выдаче (то есть ничего не теряется и не дублируется). Такие проверки помогают поймать потенциальные ошибки объединения условий. Негативные сценарии тоже берем на вооружение: к примеру, вручную подправляем URL с фильтрами, подставляя несуществующие значения (например, id фильтра, которого нет). Сайт должен был адекватно отреагировать – обычно просто показать пустой результат или игнорировать лишний параметр. В Askona это отрабатывало: при неверном параметре фильтрация просто ничего не находит, отображая сообщение для пользователя (то есть система защищена от падения). Также далее эмулируем быстрое беспорядочное переключение фильтров (стресс-тест UI) – интерфейс не должен “ломаться”, например, показывая противоречивые состояния. Граничные и негативные тесты часто выявляют скрытые баги, поэтому я всегда включаю их в проверку.
  • Инструменты: DevTools, Postman и анализ JSON. Тестирование фильтров невозможно без заглядывания в технические детали. Я активно пользуюсь DevTools (вкладка Network) в браузере, чтобы видеть какие запросы отправляются при выборе фильтров и что приходит в ответ. Это очень помогает при расследовании багов. К примеру, когда фильтр работает некорректно, я открываю сеть и вижу, что запрос уходит без нужного параметра – сразу становится ясно, что проблема на фронтенде (JS не добавил фильтр в запрос). В другом случае, как упоминалось, наоборот запрос был неправильный по логике (оператор OR вместо AND), и по ответу сервера было видно лишних товаров. JSON-ответы API я изучаю не только ради отладки багов, но и превентивно. В Askona фильтрация реализована через API: при каждом изменении фильтра фронтенд получает список товаров и актуальные значения фильтров в формате JSON. Вот упрощенный пример фрагмента такого ответа:
Упрощенный пример значений фильтров в формате JSON
Упрощенный пример значений фильтров в формате JSON

В блоке filters приходит актуальный список доступных значений с количеством товаров под каждым (например, у бренда Askona – 15 товаров всего, но с учетом других фильтров может остаться меньше). Блок selected показывает, что выбрано пользователем (Askona + средняя жесткость), а totalProducts сообщает, сколько товаров соответствует всем условиям – в данном случае 5. Сопоставляя эти цифры и фактический список товаров на странице, проверяем консистентность работы фильтра. Если JSON говорит, что должно быть 5 товаров, а на экране 4 или 6 – налицо проблема. Такой анализ особенно выручает, когда ассортимент большой: вручную труднее понять, все ли товары показаны. Через API можно также проверять случаи, которые трудно смоделировать кликами. Например, можно вызвать запрос с фильтрами, которые в интерфейсе взаимоисключающие, и убедиться, что backend возвращает пустой результат (и что фронт это правильно обработает). Для этого я использую Postman – отправляю GET-запросы к API каталога с разными комбинациями параметров. Postman позволяет автоматизировать некоторые проверки: например, прогнать набор запросов для всех вариантов одного фильтра и удостовериться, что totalProducts в сумме равняется общему числу товаров (что ни один товар не потерян и не “лишний”). Такие вещи сложно отследить вручную, зато через API – пожалуйста. Помимо сетевых данных, DevTools помогает ловить и ошибки на уровне консоли – вдруг при выборе фильтра скрипт выдает исключение. Я всегда отслеживаю, чтобы в консоли не сыпались ошибки JavaScript при любых действиях с фильтрами.

  • Оформление найденных багов. В процессе тестирования фильтров я, конечно, находила баги и аккуратно заносила их в трекинговую систему. В описании бага важно указать не только шаги и ожидание, но и детали, помогающие разработчикам понять корень проблемы. Поэтому я часто прикладывала к баг-репорту скриншоты страницы до и после применения фильтра, консоли (если есть ошибки) и, что особенно ценно, фрагменты JSON или URL запроса. Например, баг по некорректному сочетанию фильтров сопровождался таким примечанием: «Запрос к API содержит параметры brand=Askona и hardness=Soft без оператора AND, что приводит к получению всех Askona и всех Soft товаров раздельно». А к багу про незавершенный сброс я приложила бы JSON, где в блоке selected после сброса всё ещё присутствовал фильтр – убедительное доказательство проблемы. Такой уровень детализации поможет команде быстро локализовать и исправить ошибки, ведь вместо гадания «почему фильтр не работает» они увидят конкретно, где разъехались данные или логика.

Практика показывает, что тестирование фильтров – это сочетание внимательности к деталям и умения пользоваться инструментами. Я не только «кликала по галочкам», но и думала о том, как фильтрация реализована внутри. Благодаря этому удалось обнаружить тонкие дефекты, которые обычный пользователь заметил бы не сразу (например, неверные счетчики или устаревшие значения). В итоге, совместная работа QA и разработки над такими неочевидными моментами заметно улучшает качество подбора товаров на сайте. Ведь когда фильтры работают правильно, пользователи быстрее находят нужное – а это и есть главная цель.