QA на практике
Реальные баг-репорты, интерактивный запуск тестов и понятные QA-артефакты, которые показывают, как мы снижаем риск релиза до выхода в продакшн.
Реальные примеры QA
Эта страница работает как короткий proof-pack: вместо абстрактных обещаний вы сразу видите формат баг-репортов, уровень детализации и качество QA-артефактов, с которыми будет работать ваша команда.
Как мы оформляем находки
Проблема
Фиксируем проблему, контекст, окружение и шаги воспроизведения без двусмысленности.
Влияние
Показываем, что именно ломается для пользователя, бизнеса или релиза.
Рекомендация
Даём более безопасное направление исправления и что проверить после изменений.
Повторная проверка
После фикса повторно проходим сценарий и подтверждаем фактический статус.
Примеры баг-репортов
Таймаут платёжного шлюза
Оплата не проходит, когда ответ провайдера занимает более 15 секунд. Пользователи теряют заказы и деньги.
- Добавить товар в корзину
- Перейти к оформлению
- Ввести данные карты
- Нажать "Оплатить" на медленном соединении
- Увеличить таймаут до 30 секунд
- Добавить механизм повторов (3 попытки)
- Показывать индикатор прогресса
Processing продолжает поиск транзакций после отклонения Travel Rule
Сервис processing-service продолжает поиск и обработку транзакций даже после того, как сервис Travel Rule возвращает статус отклонения (DECLINED).
- Создать инвойс или транзакцию
- Дождаться запуска проверки Travel Rule
- Вернуть ответ DECLINED от сервиса Travel Rule
- Проверить логи processing-service и активность очередей
- Убедиться, что поиск транзакции продолжается после отклонения
- Немедленно завершать transaction-search после статуса DECLINED
- Добавить early-stop механизм для processing pipeline
- Блокировать создание новых processing jobs после отказа Travel Rule
- Добавить guard-check перед каждым этапом обработки транзакции
- Логировать причину остановки processing flow
- Покрыть сценарий integration и e2e тестами
Polygon RPC provider возвращает некорректные block data
Polygon RPC провайдеры (Infura, Alchemy, GetBlock) периодически возвращают
некорректные block payloads, которые не проходят десериализацию из-за
DeserError: BlockTransactions во время обработки блоков.
- Подключиться к Polygon RPC через Infura или Alchemy
- Запросить block data через
eth_getBlockByNumber - Попытаться десериализовать
BlockTransactions - Проверить появление периодических
DeserError
DeserError, из-за чего RPC backend пропускает затронутые блоки.
- Обновить логику десериализации транзакций для поддержки EIP-4844
- Добавить fallback parsing для неизвестных transaction variants
- Реализовать retry и provider failover для некорректных RPC-ответов
- Логировать номера проблемных блоков и ответы провайдеров
- Валидировать RPC payload schema перед обработкой транзакций
- Покрыть blob transaction сценарии regression и integration тестами
Crypto invoice ожидает полный timeout без обнаруженного депозита
Crypto invoices остаются в состоянии AwaitingCryptoDeposit
до полного expires_at timeout (5-10+ часов), даже если
blockchain transaction так и не была обнаружена, что создает плохой UX
в payment widget.
- Создать crypto invoice и открыть payment widget
- Проверить состояние
AwaitingCryptoDeposit - Не отправлять crypto transaction
- Дождаться окончания deposit detection window
- Убедиться, что invoice продолжает ожидание до
expires_at
"Transaction still not found", в то время как widget
продолжает показывать "awaiting payment".
expires_at timeout должен применяться только после
обнаружения транзакции.
- Реализовать two-tier timeout логику для crypto invoices
- Добавить early expiry для invoices без обнаруженных транзакций
- Сохранять возможность cancel во время deposit detection window
- Не завершать invoice, если oracle-pool уже обнаружил in-flight transaction
- Отписывать oracle-pool listeners при любом expiry state
- Вынести invoice timeout values в configurable environment variables
GetInvoice возвращает 500 после oracle-pool callback
После получения oracle-pool callback endpoint
GetInvoice возвращает
500 Internal Server Error вместо корректного invoice object.
- Создать invoice через
PaymentInvoicesService.CreateInvoice - Убедиться, что invoice имеет статус
pending.awaiting_crypto_deposit - Вызвать
GetInvoiceи проверить, что endpoint работает до callback - Отправить
POST /v1/callbacks/oracle-poolсоstatus=1иconfirmations=1 - Повторно вызвать
GetInvoiceдля того жеinvoice_id
GetInvoice возвращает
500 Internal Server Error после обработки oracle-pool callback.
GetInvoice должен возвращать корректный invoice object
с обновленным статусом:
pending.awaiting_checks,
pending.awaiting_exchange
или expired.
- Проверить invoice state transitions после oracle-pool callback
- Добавить null и schema validation перед invoice serialization
- Логировать callback payloads и invoice state mutations для debugging
- Не допускать некорректные invoice states в GetInvoice response mapping
- Добавить fallback error handling для malformed callback data
- Покрыть callback-to-GetInvoice flow integration и regression тестами
Токен сессии в URL
Токен аутентификации виден в адресной строке браузера, что позволяет перехват через историю браузера или логи прокси.
- Нажать "Войти через Google"
- Завершить OAuth-авторизацию
- Проверить URL после редиректа
site.com/home?token=abc123
- Убрать токен из URL-параметров
- Використовувати secure cookie з SameSite=Strict
- Проверить логи доступа на наличие токенов
Накладання меню на iPhone SE
Пункты меню навигации накладываются друг на друга на экранах меньше 375px.
- Открыть сайт на iPhone SE
- Натиснути на меню-бургер
- Посмотреть расположение пунктов меню
- Добавить media query для экранов <375px
- Уменьшить размер шрифта или отступы
- Тестувати на реальному iPhone SE
Потеря черновика после обновления страницы
Последние изменения в длинной форме исчезают, если пользователь обновляет страницу во время задержки автосохранения.
- Открыть длинную форму с автосохранением
- Вводить данные 20-30 секунд
- Обновить страницу во время синхронизации
- Хранить несинхронизированное состояние локально
- Добавить индикатор состояния синхронизации
- Предупреждать перед перезагрузкой при наличии несохранённых изменений
Эскалация прав через кеш ролей
После отзыва админ-прав пользователь ещё некоторое время может выполнять защищённые действия.
- Снять роль администратора с существующего пользователя
- Не завершать текущую сессию
- Попробовать выполнить админ-действия
- Инвалидировать кеш ролей после обновления прав
- Проверять роли на сервере для чувствительных действий
- Логировать попытки доступа после отзыва прав
Событие покупки не попадает в аналитику
Успешный заказ создаётся, но событие покупки не отправляется после оформления в один клик.
- Запустить оформление в один клик с сохранённой картой
- Успешно завершить оплату
- Проверить сетевые запросы и дашборд аналитики
- Запускать аналитику только после подтверждённого backend-успеха
- Добавить оповещения о просадке событий покупки
- Покрыть checkout-сценарии отдельным regression-набором
Сброс фильтров после пагинации каталога
После перехода на вторую страницу каталога активные фильтры исчезают, а список товаров меняется без предупреждения.
- Открыть каталог товаров
- Применить 2-3 фильтра и сортировку
- Перейти на вторую страницу результатов
- Добавить фильтры в URL-параметры
- Использовать History API для навигации
- Хранить состояние фильтров в sessionStorage
PDF-счёт доступен после выхода из аккаунта
Ссылка на инвойс продолжает открывать документ даже после завершения пользовательской сессии.
- Войти в аккаунт и открыть историю счетов
- Скопировать прямую ссылку на PDF
- Выйти из аккаунта и открыть ссылку в новой вкладке
- Проверять авторизацию на уровне файлового эндпоинта
- Использовать короткоживущие подписанные URL
- Добавить аудит доступа к чувствительным документам
SQL-инъекция в поисковом поле
Поле поиска не экранирует спецсимволы, позволяя выполнять произвольные SQL-запросы.
- Открыть каталог товаров
- Ввести в пошук:
'; DROP TABLE orders; -- - Натиснути Enter
- Использовать параметризованные запросы (prepared statements)
- Добавить валидацию ввода на уровне API
- Включить WAF-правила для SQL-инъекций
XSS через поле отзыва
Отзывы пользователей отображаются без экранирования HTML, позволяя выполнять скрипты.
- Открыть любой товар
- Добавить отзыв с текстом:
<script>alert('XSS')</script> - Сохранить отзыв
- Использовать textContent вместо innerHTML
- Добавить CSP-заголовки
- Провести аудит всех мест вывода пользовательских данных
Отсутствие ограничения частоты запросов на API
API-эндпоинт для смены пароля не имеет ограничений на количество запросов.
- Отправить запрос на смену пароля
- Повторить запрос 100+ раз за минуту
- Проверить ответы сервера
- Добавить rate limiting (5 запросов в минуту)
- Внедрить exponential backoff
- Логировать подозрительную активность
Загрузка исполняемых файлов
Форма загрузки аватара принимает любые типы файлов, включая .exe и .php.
- Открыть настройки профиля
- Выбрать файл shell.php вместо изображения
- Загрузить файл
- Валидировать MIME-тип и расширение файла
- Проверять magic bytes файла
- Хранить файлы вне web-root с переименованием
Повторное списание после повторной оплаты
Если пользователь повторно нажимает оплату после долгого ответа провайдера, создаются два успешных списания для одного заказа.
- Оформить заказ с банковской картой
- Дождаться задержки ответа платёжного провайдера
- Повторно нажать кнопку "Оплатить"
- Добавить idempotency key для каждого платёжного запроса
- Блокировать кнопку после первого клика до ответа провайдера
- Отдельно логировать дублирующиеся webhooks и reconciliation case
Некорректное округление суммы при частичной оплате
При частичной оплате бонусами итоговая сумма в checkout отличается от суммы, которая передаётся в платёжный провайдер.
- Добавить товар с копейками в корзину
- Применить бонусный баланс на часть суммы
- Перейти к подтверждению оплаты картой
- Унифицировать правила округления между клиентской и серверной частями
- Работать с минимальными денежными единицами вместо чисел с плавающей точкой
- Добавить автотесты для бонусных и смешанных оплат
Событие возврата не попадает в аналитику
После успешного refund в админ-панели событие возврата не попадает ни в GA4, ни во внутренний финансовый дашборд.
- Открыть оплаченный заказ в админ-панели
- Выполнить частичный или полный возврат
- Проверить аналитические события и BI-дашборд
- Отправлять отдельную refund event после подтверждения backend-статуса
- Добавить мониторинг разрыва между orders и refunds в аналитике
- Покрыть refund flow отдельным regression-сценарием
Потеря UTM-меток после входа в аккаунт
После логина пользователя атрибуция кампании сбрасывается, и заказы попадают в отчётность как direct / none.
- Открыть лендинг с UTM-метками
- Перейти к товару и войти в аккаунт
- Завершить checkout и проверить source / medium
- Сохранять attribution state в sessionStorage или server session
- Не перезаписывать source после auth redirect
- Добавить проверки для login-to-checkout funnel
Демо запуска автотестов
Посмотрите, как выглядит запуск демо-набора автотестов: со статусами, сигналами риска, итогом и переходом к примеру реального QA-отчёта.
Что это показывает: типичный сценарий проверки оформления заказа со статусами прохождения, предупреждениями и сигналами, которые помогают не выпустить рискованный релиз.
Нажмите кнопку, чтобы увидеть не только итог, но и пример конкретных находок в отчёте
Примеры тест-кейсов
- Открыть страницу входа
- Ввести валидный email
- Ввести валидный пароль
- Нажать кнопку "Войти"
- Открыть страницу товара
- Выбрать размер/цвет при необходимости
- Нажать "Добавить в корзину"
- Проверить обновление значка корзины
- Ввести несуществующий email
- Нажать "Отправить ссылку"
- Наблюдать ответ системы
- Открыть оформление в один клик
- Успешно завершить оплату
- Проверить сетевые запросы и события аналитики
- Снять роль администратора с пользователя в другой сессии
- Вернуться в текущую админ-сессию
- Попробовать изменить биллинг или роли других пользователей
- Внести изменения в несколько полей формы
- Не ждать завершения автосохранения
- Попробовать обновить страницу или перейти в другой раздел
Что вы получаете в реальной работе
Эти примеры упрощены, но сама структура в реальных проектах такая же: воспроизводимые доказательства, понятные приоритеты, бизнес-влияние и рекомендации, которые команда может брать в работу сразу.
Приоритезированные находки
Каждый баг группируется по критичности и влиянию, чтобы команда сразу видела, что блокирует релиз, а что можно планировать отдельно.
Чёткие шаги воспроизведения
Окружение, шаги, ожидаемый и фактический результат убирают неоднозначность и экономят время разработки.
Практические рекомендации
Мы не останавливаемся на фразе “сломано”, а подсказываем зоны риска, более безопасный путь исправления и что проверить после изменений.
Быстрый первый сигнал
В фокусе всегда критические сценарии, поэтому уже первый отчёт помогает продукту и разработке принимать решения.
Нужен такой же формат QA-артефактов для вашего продукта?
Покажем, как может выглядеть QA-поддержка именно для вашей команды: с баг-репортами, ретестами, релизными рисками и понятной структурой отчёта.