Охота за 100% покрытием: как собрать все метрики воедино в монорепозитории Nx
- четверг, 17 апреля 2025 г. в 00:00:04
 
Монорепозитории становятся всё более популярными и инструмент Nx уже давно зарекомендовал себя как мощное решение для их поддержки. Он упрощает управление зависимостями, автоматизирует задачи генерации кода, обеспечивает кэширование сборок и, конечно же, помогает запускать тесты и оценивать покрытие кода. Однако стандартный подход Nx при запуске тестов через Jest имеет одну особенность: для каждого проекта создаётся свой собственный отчёт.

Когда запускается тестирование, например, командой:
nx test my-app --codeCoverage
в каждом проекте создаётся своя директория с отчётом, например, coverage/apps/my-app или coverage/libs/my-shared-lib. В каждой из этих папок находится файл coverage-final.json с данными о покрытии конкретного проекта. Такой подход удобен для локального анализа, но когда речь идёт о монорепозитории, где важно видеть целостную картину, наличие множества отдельных отчётов становится проблемой.
Встроенные возможности Nx не предусматривают агрегирование данных покрытия из нескольких проектов в один сводный отчёт. Но это не так сложно — можно написать свой скрипт, который соберёт все coverage-final.json файлы, или воспользоваться готовым инструментом. Одним из таких решений является CLI-инструмент nyc-merge.
Интеграция с Nx: Инструмент автоматически находит файлы отчетов в стандартных каталогах (coverage/apps/*, coverage/libs/* и т.д.).
Гибкость поиска: Использование glob-шаблонов (с помощью библиотеки fast-glob) позволяет легко учесть любую структуру директорий.
Корректное объединение: Благодаря использованию istanbul-lib-coverage (ядро утилиты nyc) отчёты объединяются с учётом всех тонкостей.
Параллельная обработка: Быстрая обработка файлов даже на многоядерных машинах.
Простой интерфейс: Минимум настроек, позволяющих интегрировать инструмент в любые CI/CD-процессы.
Установите инструмент как зависимость для разработки в корне вашего Nx-воркспейса:
npm install --save-dev nyc-merge
# или
yarn add --dev nyc-merge
# или
pnpm add --save-dev nyc-merge
Запустите тесты для всех проектов, либо укажите конкретные приложения и библиотеки:
nx run-many --target=test --all --codeCoverage
# или для конкретных проектов:
# nx run-many --target=test --projects=app1,lib1,lib2 --codeCoverage
После выполнения тестов мы получим отдельные отчёты, расположенные, например, в coverage/apps и coverage/libs.
Для объединения файлов воспользуйтесь nyc-merge. Пример команды:
npx nyc-merge \
  -o coverage/coverage-final.json \
  'coverage/**/coverage-final.json'
Если структура ваших директорий иная, можно использовать свои пути, например:
npx nyc-merge \
  -o coverage/coverage-final.json \
  'coverage/apps/*/coverage-final.json' \
  'coverage/libs/*/coverage-final.json'
Объединив данные в один файл, создайте наглядный HTML-отчёт:
npx nyc report --reporter=html --report-dir=coverage --temp-dir=coverage
Таким образом, вы получаете единое представление покрытия для всего монорепозитория, что упрощает анализ и улучшает контроль качества кода.
Удобства ради можно добавить соответствующие скрипты в корневой файл package.json вашего проекта:
{
  "scripts": {
    "coverage:test:all": "nx run-many --target=test --all --codeCoverage",
    "coverage:merge": "npx nyc-merge -o coverage/coverage-final.json coverage/**/coverage-final.json",
    "coverage:html": "npx nyc report --reporter=html --report-dir=coverage --temp-dir=coverage",
    "coverage": "npm run coverage:test:all && npm run coverage:merge && npm run coverage:html"
  }
}
Теперь, выполнив команду:
npm run coverage
вы получите полный цикл: запуск тестов, объединение отчётов и генерацию итогового HTML-отчёта.
Немаловажным аспектом является конфигурация Jest, которая отвечает за сбор покрытия кода. Ниже приведён пример файла jest.preset.js с оптимальными настройками:
module.exports = {
  ...nxPreset,
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageReporters: ['json'],
  coverageThreshold: {
    global: {
      statements: 80,
      branches: 80,
      functions: 80,
      lines: 80,
    },
  },
};
Объяснения ключевых опций:
collectCoverage: true
 Включает сбор информации о покрытии, позволяя фиксировать, какие участки кода были выполнены во время тестов.
coverageDirectory: 'coverage'
 Указывает директорию для сохранения отчётов о покрытии.
coverageReporters: ['json']
 Выбирает формат сохранения отчёта, в данном случае json, что необходимо для последующего объединения с помощью nyc-merge.
coverageThreshold
 Определяет минимальные требования к покрытию кода. Если пороги не достигаются, тесты завершаются с ошибкой. В примере лимиты установлены на уровне 80% по основным категориям (инструкции, ветвление кода, функции и строки).

Для получения краткой сводки по покрытию можно добавить ещё один скрипт:
{
  "scripts": {
    "coverage:summary": "npx nyc report --reporter=text-summary --report-dir=coverage --temp-dir=coverage",
    "coverage:report": "npm run coverage:test:all && npm run coverage:merge && npm run coverage:summary"
  }
}
Можно повесить на хуки гита или встроить в CI/CD.
Если вы работаете с Nx и хотите видеть реальное покрытие кода по всему монорепозиторию, попробуйте nyc-merge. Это простой, быстрый и надежный способ получить единый отчет, который также легко интегрируется в любой CI/CD и cэкономит ваше время.
Репозиторий проекта: https://github.com/BaryshevRS/nyc-merge