Karma-rollup-preprocessor

Karma — это тестовый раннер для JavaScript, который позволяет выполнять тесты в реальном браузере или headless-среде. Его гибкость обеспечивается системой препроцессоров, которые трансформируют исходный код перед выполнением. Одним из популярных инструментов для сборки и обработки модулей является Rollup, и для интеграции его с Karma используется karma-rollup-preprocessor.


Назначение karma-rollup-preprocessor

Препроцессор позволяет:

  • Использовать современные стандарты ES6/ESNext в тестах.
  • Транспилировать модули с помощью Rollup, включая поддержку tree-shaking.
  • Применять плагины Rollup для обработки специфичных форматов (например, TypeScript, JSON, CSS-модули).
  • Обеспечивать единообразную сборку кода как для тестов, так и для продакшн-бандлов.

Основная идея: тесты и исходный код проходят через один и тот же pipeline сборки, что исключает расхождения между средами.


Установка и базовая настройка

Установка производится через npm:

npm install --save-dev karma-rollup-preprocessor rollup

Для работы с современным синтаксисом часто требуется Babel:

npm install --save-dev @rollup/plugin-babel @babel/core @babel/preset-env

В karma.conf.js конфигурация препроцессора подключается через объект preprocessors и отдельный блок rollupPreprocessor:

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],
    files: [
      'src/**/*.js',
      'test/**/*.spec.js'
    ],
    preprocessors: {
      'src/**/*.js': ['rollup'],
      'test/**/*.spec.js': ['rollup']
    },
    rollupPreprocessor: {
      plugins: [
        require('@rollup/plugin-babel')({
          babelHelpers: 'bundled',
          presets: ['@babel/preset-env']
        })
      ],
      output: {
        format: 'iife',
        name: 'TestBundle',
        sourcemap: 'inline'
      }
    },
    reporters: ['progress'],
    browsers: ['ChromeHeadless']
  });
};

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

  • plugins — список подключаемых Rollup-плагинов для трансформации кода.
  • output.format — формат бандла. Для браузерных тестов оптимально iife.
  • sourcemap — inline-карта исходников упрощает отладку тестов.

Поддержка ES-модулей и CommonJS

Rollup по умолчанию работает с ES-модулями. Для тестирования проектов, которые используют CommonJS, необходимо подключить плагин @rollup/plugin-commonjs:

const commonjs = require('@rollup/plugin-commonjs');

rollupPreprocessor: {
  plugins: [
    commonjs(),
    require('@rollup/plugin-babel')({
      babelHelpers: 'bundled',
      presets: ['@babel/preset-env']
    })
  ],
  output: {
    format: 'iife',
    name: 'TestBundle',
    sourcemap: 'inline'
  }
}

Это позволяет импортировать пакеты из node_modules, которые используют CommonJS, и использовать их в тестах без дополнительных преобразований.


Интеграция с TypeScript

Для проектов на TypeScript применяется плагин @rollup/plugin-typescript:

const typescript = require('@rollup/plugin-typescript');

rollupPreprocessor: {
  plugins: [
    typescript({ tsconfig: './tsconfig.json' }),
    require('@rollup/plugin-babel')({
      babelHelpers: 'bundled',
      presets: ['@babel/preset-env']
    })
  ],
  output: {
    format: 'iife',
    name: 'TestBundle',
    sourcemap: 'inline'
  }
}

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

  • Rollup компилирует TypeScript до ES5/ES6 в зависимости от конфигурации tsconfig.json.
  • Можно комбинировать с Babel для использования последних возможностей JavaScript.

Использование плагинов Rollup

Препроцессор полностью поддерживает экосистему Rollup:

  • @rollup/plugin-node-resolve — поиск модулей в node_modules.
  • rollup-plugin-terser — минификация кода (для интеграционных тестов может быть не нужна, но полезна для продакшн-бандлов).
  • rollup-plugin-replace — подмена констант или окружения.
  • rollup-plugin-alias — настройка алиасов для модулей.

Пример с плагинами Node Resolve и Replace:

const resolve = require('@rollup/plugin-node-resolve');
const replace = require('@rollup/plugin-replace');

rollupPreprocessor: {
  plugins: [
    resolve(),
    replace({ 'process.env.NODE_ENV': JSON.stringify('test') }),
    require('@rollup/plugin-babel')({
      babelHelpers: 'bundled',
      presets: ['@babel/preset-env']
    })
  ],
  output: {
    format: 'iife',
    name: 'TestBundle',
    sourcemap: 'inline'
  }
}

Советы по производительности

  • Минимизировать число файлов, обрабатываемых Rollup, через точный паттерн в files.
  • Использовать кеширование Rollup (cache), если тесты повторяются в CI.
  • Генерация sourcemap только для разработки (sourcemap: false для CI ускоряет сборку).
  • Подключать плагины только при необходимости, так как каждый плагин увеличивает время препроцессинга.

Проблемы и их решение

  1. Тесты не запускаются после импорта CSS или JSON Решение: использовать соответствующие плагины Rollup: @rollup/plugin-json для JSON, rollup-plugin-postcss для CSS.

  2. Ошибки с Babel и babelHelpers Проверить настройку babelHelpers. Для Karma обычно подходит 'bundled'.

  3. CommonJS пакеты не находятся Подключить @rollup/plugin-node-resolve и @rollup/plugin-commonjs.

  4. Длинное время сборки Разделить тесты на несколько файлов и использовать инкрементальный запуск Karma с autoWatch: true.


Вывод

karma-rollup-preprocessor обеспечивает единый процесс сборки для тестов и приложения. Он позволяет использовать современные возможности JavaScript, управлять зависимостями через плагины Rollup и поддерживает сложные конфигурации TypeScript, Babel и CommonJS. Грамотная настройка препроцессора снижает вероятность расхождений между тестовой и рабочей сборкой, повышает читаемость тестов и ускоряет CI/CD процессы.