DevTools и логи: где искать причину

«У меня не работает» — худший баг-репорт на свете. DevTools превращает его в «фронтенд шлёт quantity строкой, сервер отвечает 422» — и баг чинят за час.

DevTools (инструменты разработчика, открываются по F12 или Cmd+Option+I) — встроенная в браузер панель, которая показывает, что происходит внутри страницы: какие запросы уходят на сервер, что он отвечает и какие ошибки возникают в коде.

Зачем это тестировщику

Есть навык, который на собеседовании отличает junior от «junior, которого берут»: умение сказать, на чьей стороне баг. Разработчиков в команде обычно двое-трое, и они разные: один пишет интерфейс, другой — сервер. Баг-репорт «корзина пустая» отправится в общий котёл и пролежит там неделю. Баг-репорт «на GET /api/cart сервер вернул 200 и три товара, но фронтенд отрисовал пустой список — вот HAR» уйдёт напрямую к фронтендеру и будет починен сегодня.

Разница между этими двумя формулировками — пять минут в DevTools.

Вкладка Console: что сломалось в коде страницы

Console показывает сообщения от JavaScript, работающего на странице. Читать их нужно по цветам и уровням:

УровеньЧто значитРеакция
Error (красный)Код упал с исключениемПочти всегда баг фронтенда. Копируем текст и stack trace в задачу
Warning (жёлтый)Предупреждение: устаревший метод, лишний ключОбычно не баг. Не тащите жёлтое в баг-репорт «на всякий случай»
Info / LogОтладочные сообщения разработчикаКонтекст, иногда очень полезный

Типичная ошибка выглядит так:

Uncaught TypeError: Cannot read properties of undefined (reading 'name')
    at renderUser (profile.js:42:18)
    at ProfilePage (profile.js:15:5)

Даже не зная JavaScript, вы читаете отсюда главное: код пытался взять поле name у чего-то, чего не существует. Скорее всего, сервер не прислал ожидаемый объект — а фронтенд не проверил и упал. То есть баг, вероятно, двойной: сервер отдал не то, фронтенд не защитился. И то и другое стоит написать в задаче.

Обязательно включите галочку Preserve log: без неё консоль очищается при каждом переходе на новую страницу, и ошибка, случившаяся перед редиректом, исчезнет у вас на глазах.

Вкладка Network: что ушло на сервер и что вернулось

Это главная вкладка тестировщика. Она записывает все сетевые запросы страницы. Включите фильтр Fetch/XHR — останутся только обращения к API, без картинок и шрифтов.

По каждому запросу смотрим четыре вещи:

ПодвкладкаЧто тамЗачем тестировщику
HeadersМетод, URL, статус, заголовкиПроверить код ответа, наличие Authorization, Content-Type
Payload (Request)Что отправил фронтендСравнить с тем, что вы ввели в форму. Здесь ловится половина багов фронта
Response / PreviewЧто вернул серверСравнить с тем, что нарисовано на экране
TimingСколько чего длилосьПонять, тормозит сервер или отрисовка

Пример. В форму заказа ввели количество 2, а во вкладке Payload видим:

{
  "product_id": "42",
  "quantity": "2"
}

А сервер отвечает:

{
  "error": "validation_failed",
  "details": [
    { "field": "quantity", "message": "expected integer, got string" }
  ]
}

Вердикт очевиден и доказан: фронтенд отправляет число строкой, сервер честно ругается 422. Это баг фронтенда, и в баг-репорт идут оба JSON — спорить не о чем.

Полезные кнопки на панели Network, о которых новички не знают:

  • Disable cache — заставляет браузер каждый раз ходить на сервер. Без неё вы можете полдня тестировать старую версию скрипта.
  • Preserve log — сохраняет запросы при переходах и редиректах (иначе запрос логина исчезнет сразу после успешного входа).
  • Throttling — эмуляция медленной сети (Slow 3G). Половина багов «двойного клика» и «бесконечного спиннера» ловится только здесь.
  • Copy → Copy as cURL — правый клик по запросу даёт готовую команду, которую можно вставить в терминал или импортировать в Postman.
  • Export HAR — выгрузка всех запросов в файл. Прикладывайте HAR к багу вместо скриншота консоли: разработчик увидит ровно то же, что и вы.

Как отличить баг фронта от бага бэкенда

Это не интуиция, а алгоритм из четырёх вопросов. Задавайте их по порядку — на каком шаге сломалось, тот и виноват.

  1. Запрос вообще ушёл? Нажимаем кнопку, смотрим Network. Если новой строки не появилось — сервер тут ни при чём: фронтенд не отправил запрос (не сработал обработчик, форма не прошла свою валидацию).
  2. Что ушло? Открываем Payload. Если фронтенд отправил не то, что вы ввели, — баг фронтенда, до сервера дело не дошло.
  3. Что вернулось? Смотрим статус и Response. 5xx или неверные данные в теле — баг бэкенда.
  4. Что нарисовано? Если запрос корректный и ответ корректный, а на экране ерунда — виноват фронтенд: данные пришли, но он их неправильно отобразил.

Сводная таблица-шпаргалка:

СимптомЧто видно в DevToolsВердикт
Кнопка «мертва»В Network пусто, в Console — красная ошибкаФронтенд
Ошибка валидации на верных данныхPayload содержит не то, что вводилиФронтенд
«Что-то пошло не так»500 в ответеБэкенд (и это баг всегда)
Список пуст, хотя данные есть200, в Response три объектаФронтенд: получил, но не отрисовал
Список пуст200, в Response []Бэкенд или тестовые данные
Выкидывает на логин401Токен протух / не отправляется — смотрим заголовок Authorization
Ничего не грузится, в консоли CORSCORS policy: No 'Access-Control-Allow-Origin' headerКонфигурация бэкенда, не фронт
Долго крутится спиннерTiming: запрос идёт 12 секундБэкенд (производительность)
Долго крутится спиннерОтвет пришёл за 100 мс, но спиннер виситФронтенд

Отдельно про 404: он двусмысленный. 404 на /api/ordres (опечатка в URL) — баг фронтенда. 404 на корректный /api/orders/17, когда заказ 17 существует, — баг бэкенда или проблема тестовых данных. Всегда смотрите на сам URL, а не только на цифру.

Как это работает

DevTools подключён напрямую к движку браузера, поэтому видит и сеть, и исполнение скриптов. Пара следствий, которые полезно понимать.

Во-первых, Network показывает только те запросы, которые сделала страница. Всё, что происходит между сервером приложения и, например, платёжным шлюзом, вы здесь не увидите — это уже серверная история, и туда путь лежит через логи.

Во-вторых, статусы вроде (from disk cache) или 304 Not Modified означают, что реального похода на сервер не было. Отсюда классическая иллюзия «баг не воспроизводится у разработчика»: у него сборка свежая, у вас — закешированная. Правило: воспроизводим баг с включённым Disable cache и в режиме инкогнито.

В-третьих, есть вкладка Application (в Firefox — Storage): там лежат cookie, localStorage и токены. Если пользователя внезапно разлогинивает, ответ почти всегда там — токен не сохранился или перезаписался.

Когда DevTools уже не хватает: логи бэкенда

Если сервер вернул 500, браузер покажет только сам факт. Почему он упал, написано в логах сервера — их обычно смотрят в Kibana, Grafana Loki, Sentry или просто в консоли контейнера. Чтобы найти нужную запись среди тысяч, ищите по идентификатору запроса: многие бэкенды возвращают заголовок вроде X-Request-Id или trace-id.

Response Headers:
  X-Request-Id: 8f3a1c2e-7b40-4d19-9a12-6c0f5b2d1e77

Поиск в Kibana:
  request_id: "8f3a1c2e-7b40-4d19-9a12-6c0f5b2d1e77"

Скопировать этот id в баг-репорт — приём, за который разработчики будут вас любить: он экономит им полчаса поиска по логам.

Частые ошибки

  • Скриншот вместо HAR. На картинке не видно ни заголовков, ни тела запроса. Прикладывайте HAR-файл и текст ответа.
  • Открывать DevTools после того, как баг случился. Панель не записывает то, что было до её открытия. Правило: сначала F12, потом воспроизводим.
  • Выключенный Preserve log. Баг на логине или при редиректе исчезает вместе с логом, и вы час ищете «пропавший запрос».
  • Тащить в баг жёлтые warning'и. Они шумят и обесценивают репорт. Ищите красное — и только то, что появляется в момент воспроизведения.
  • Обвинять бэкенд по факту 500, не приложив тело ответа и request id. Формально вы правы, но задача вернётся с вопросом «а где именно?».
  • Не проверить кеш. «Работает у меня, не работает у него» в 9 случаях из 10 — старый JS в кеше. Disable cache и инкогнито до того, как заводить баг.
  • Считать CORS-ошибку багом фронтенда. Текст ошибки появляется в браузере, но заголовки настраивает сервер. Это почти всегда конфигурация бэкенда.

Итоги

  • Console отвечает на вопрос «упал ли код страницы», Network — «что ушло на сервер и что вернулось».
  • Алгоритм локализации бага: запрос ушёл? → что отправили? → что вернулось? → что нарисовали? Первый сломанный шаг и есть виновник.
  • 5xx — всегда баг сервера. Неверный Payload при верном вводе — всегда баг фронта. 200 с корректным телом и пустым экраном — тоже фронт.
  • Disable cache, Preserve log и Throttling — три галочки, которые превращают DevTools из просмотрщика в инструмент.
  • HAR-файл, тело ответа и X-Request-Id в баг-репорте экономят команде часы и делают вас тем тестировщиком, которого хотят держать в проекте.
Проверьте себя
1. В списке заказов пусто. В Network видно: GET /api/orders вернул 200, в Response — три объекта заказа. Чей это баг?
AБэкенда: данные пришли неправильные
BФронтенда: данные получены, но не отрисованы
CЭто не баг, а особенность кеширования
DОпределить невозможно без логов сервера
2. Зачем перед воспроизведением бага включать в Network галочки Disable cache и Preserve log?
AЧтобы страница грузилась быстрее
BЧтобы браузер не подсунул старую версию скриптов, а запросы не стирались при редиректе
CЧтобы автоматически сохранить HAR-файл
DЧтобы скрыть из списка картинки и шрифты