Source maps и покрытие

Source maps: связывание исходного кода и транспилированного кода

В современных проектах на JavaScript часто используется транспиляция с помощью Babel, TypeScript или Webpack. Транспиляция позволяет писать код с современными возможностями языка или использовать модульную структуру, однако тесты запускаются уже не на исходном коде, а на скомпилированном. Это приводит к проблемам с отладкой: ошибки и стек-трейсы показывают строки в транспилированных файлах, а не в исходных. Решение этой проблемы — использование source maps.

Source map — это файл, который сопоставляет каждую строку и каждый символ исходного кода с соответствующей частью скомпилированного кода. Karma умеет работать с source maps, если правильно настроен плагин karma-sourcemap-loader.

Пример настройки в karma.conf.js:

module.exports = function(config) {
  config.set({
    frameworks: ['jasmine'],
    files: [
      { pattern: 'src/**/*.js', included: true },
    ],
    preprocessors: {
      'src/**/*.js': ['webpack', 'sourcemap']
    },
    webpack: {
      devtool: 'inline-source-map',
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: { presets: ['@babel/preset-env'] }
            }
          }
        ]
      }
    },
    reporters: ['progress', 'coverage'],
    browsers: ['ChromeHeadless'],
  });
};

Ключевые моменты:

  • devtool: 'inline-source-map' указывает Webpack генерировать source map внутри файлов, что удобно для Karma.
  • karma-sourcemap-loader необходим для того, чтобы Karma могла корректно сопоставлять строки ошибок с исходным кодом.
  • Использование source maps облегчает диагностику ошибок и повышает читаемость отчётов о тестах.

Покрытие кода (Code Coverage)

Покрытие кода показывает, какие части исходного кода выполняются тестами. Karma тесно интегрируется с инструментом Istanbul, через плагин karma-coverage или karma-coverage-istanbul-reporter.

Основные показатели покрытия:

  • Statements (операторы) — сколько выражений кода выполнено.
  • Branches (ветвления) — насколько покрыты условные конструкции if, switch.
  • Functions (функции) — какие функции были вызваны.
  • Lines (строки) — сколько строк кода реально выполнено.

Настройка Karma для покрытия:

module.exports = function(config) {
  config.set({
    frameworks: ['jasmine'],
    files: [
      'src/**/*.js'
    ],
    preprocessors: {
      'src/**/*.js': ['webpack', 'sourcemap', 'coverage']
    },
    webpack: {
      devtool: 'inline-source-map',
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: 'babel-loader'
          }
        ]
      }
    },
    reporters: ['progress', 'coverage-istanbul'],
    coverageIstanbulReporter: {
      reports: ['html', 'lcov', 'text-summary'],
      fixWebpackSourcePaths: true,
      dir: 'coverage/',
    },
    browsers: ['ChromeHeadless'],
  });
};

Особенности:

  • preprocessors включают coverage для подсчёта покрытия.
  • coverageIstanbulReporter генерирует отчёты в разных форматах. html позволяет визуально изучить покрытие, lcov используется для CI/CD, а text-summary выводит краткую сводку в консоли.
  • Параметр fixWebpackSourcePaths корректирует пути исходного кода, чтобы отчёты совпадали с оригинальными файлами, а не с бандлом Webpack.

Взаимодействие Source Maps и Coverage

Для корректного покрытия важно, чтобы source maps учитывались. Если их нет или они настроены неправильно, отчёты о покрытии будут показывать строки из транспилированного кода, что делает анализ бесполезным.

Правильная последовательность:

  1. Сначала транспиляция кода с генерацией inline source maps.
  2. Затем обработка файлов через karma-coverage или karma-coverage-istanbul-reporter.
  3. Karma считывает source maps и формирует отчёт по исходным файлам, а не по бандлу.

Это особенно критично при использовании TypeScript или современных возможностей JavaScript, когда один исходный файл может превратиться в несколько скомпилированных строк. Без source maps покрытие будет отображаться некорректно.

Дополнительные советы

  • Использовать ChromeHeadless для CI/CD, так как он быстрее и стабильнее в автоматическом тестировании.
  • Для больших проектов стоит включать exclude для внешних библиотек, чтобы не замусоривать отчёт покрытия.
  • Можно комбинировать source maps с инструментами анализа кода, например, ESLint или SonarQube, чтобы получать полное представление о качестве кода и его тестировании.

Понимание связи source maps и покрытия позволяет не только отлаживать тесты, но и точно измерять качество покрытия, повышая надёжность приложений.