🔥

Тред (@kirjs)


Продолжим тему дебага историей из реальной жизни. Это случилось на проекте с Ангуларом, но самого Ангулара вы не увидите, и все техники используемые тут могут быть применены на любом проекте. Можете попробовать воспроизвести тут: github.com/codelab-fun/co…
notion image

При запуске тестов на проекте (на котором тесты не запускались очень давно), выпадала странная ошибка: > npm test feedback :ERROR [config]: File ./libs/feedback/karma.conf.js does not exist! При этом сам файл существовал, например cat выводил его содержимое.
notion image

Тут важно понимать, что (почти) все что, что запускается из npm, это обычный JavaScript, а значит код скорее всего лежит в папке node_modules. Попробуем найти код отвечающий за это сообщение по части сообщения в папке node_modules
notion image

Нам повезло: результаты довольно однозначные, поэтому мы просто добавляем "debugger" перед выведением ошибки. Когда мы запустим наше приложение в дебаг режиме, дебаггер остановится в этом месте и мы сможем разобраться - что именно тут происходит.
notion image

Пришло время взять в руки дебаггер! C node.js это немного посложнее чем с браузером, но ничего невозможного. Чтобы запустить node в дебаг-режиме, нам нужно добраться до .js файла, который запускается под капотом. В package.json мы видим что "npm test" просто запускает "ng test"
notion image

Локальный бинарник ng лежит в папке node_modules/.bin, и это просто javascript файл. Это значит что мы просто можем запустить: node node_modules/.bin/ng test feedback И получить тот же самый результат!
notion image

Добавим --inspect-brk, чтобы запустить nodejs в дебаг режиме: $ node --inspect-brk node_modules/.bin/ng test feedback При запуске nodejs остановится и подождет, пока мы присоединимся к нему дебаггером
notion image

Дебаггеры бывают разные, мы используем Chrome Dev Tools: в Chrome заходим по адресу: chrome://inspect/#devices И видим снизу наш node процесс, нажав на который мы попадем наконец-то в дебаггер!
notion image

На самом деле есть альтернатива (Но еще не очень стабильная) всем этим сложным махинациям, можно использовать npmjs.com/package/ndb npm i -g ndb ndb npm test feedback Так или иначе, мы уже в дебаггере. Теперь разберемся как он поможет нам починить баг.
notion image

На этой драматической ноте я пойду посплю, потому что болею, и у меня по ходу температура 😫 Когда я вернусь расскажу почему карма выдает такое странное сообщение и как это можно починить.

Ок, посмотрим что тут происходит: Мы находимся файла config в karma.js Функция в которой мы сейчас - parseConfig - получает конфиг для тестов Карма пытается получить (require) fileConfigPath. По ходу будет выброшена ошибка, которая будет соответствовать двум критериям:
notion image

Тип ошибки - MODULE_NOT_FOUND В сообщении ошибки - fileConfigPath - путь файла который мы пытаемся получить.
notion image

В образовательных целях давайте попробуем поймать эту ошибку. Для этого нам нужно остановиться ДО require(...). Чтобы это сделать: Поставим точку останова (breakpoint) на строке 351 Перезапустим скрипт из терминала
notion image

Убедимся что все гуд: Мы Остановились на нужной строчке до require() Теперь: 3) Включим остановку при выбрасывании ошибки 4) Поставим галку, чтобы мы остановились даже если ошибка внутри try/catch 5) Поехали!
notion image

Вот наша первая остановка 🔥 Мы где-то внутри cjs (closure js) загрузщика модулей node.js. Глубоко! Ошибка "Cannot find module '../../karma.conf", не совсем то, что мы ожидали Код подходит под ожидание Прежде чем мы посмотрим message, глянем в стэк вызовов:
notion image

Мы пришли сюда из кармы, parseConfig, как и ожидалось. Также мы видим в стеке вызовов karma.conf.js, по ходу это и есть наш "Несуществующий файл" Заглянем туда, нажав на соответствующий вызов
notion image

Вот и наш файл. Во-первых он все-таки есть. Во-вторых он пытается загрузить несуществующий файл. Это вызывает ошибку, вроде все понятно. Но почему же карма выводит неправильное имя 😫? Нажмем продолжить (F8) и вернемся в место дебага все все началось:
notion image

Ок, вернувшись в начала мы: Убедимся что это та же самая ошибка. Вроде код и сообщение совпадают. Единственно что не понятно, как получилось так, что e.message содержит в себе имя файла? Давайте посмотрим на e.message
notion image

Да вот же он, прямо в стеке вызовов. По какой-то причине загрузчик модулей посчитал что добавить стек в сообщение это хорошая идея. Давайте вернемся в тот код и посмотрим как это могло случиться...
notion image

Возвращаемся в код загрузчика и видим что стек добавляется в сообщение вручную.
notion image

резюме: Карма ловит ошибку при загрузке конфига и делает две проверки: code === MODULE_NOT_FOUND ✅ Верна для всех вложенных ненайденых модулей message.includes(configFilePath) ✅Верна для всех вложенных ненайденых модулей, т.к. configFilePath в стеке вызовов
notion image

Что делать дальше? В целом понятно как починить это локально - убрать сломанный require Это 100% баг кармы, надо починить и там, чтобы сэкономить время другим людям. В тот момент я выбрал создать issue а не PR, т.к. не было времени. Вот оно: github.com/karma-runner/k…

Через пару недель кто-то сделал PR (github.com/karma-runner/k…). Вместо добавления новых условий они просто убрали существующие и стали выводить непосредственно ошибку:
notion image

На этом детективная история со счастливым финалом закончена! Спасибо всем кто прочитал до конца 🔥🔥🔥 У меня заняло примерно в 5 раз больше времени написать про этот баг чем починить :)