Обработка модулей

Karma — это инструмент для запуска тестов JavaScript в реальных браузерах. Ключевой аспект работы Karma — корректная обработка модулей, чтобы тестируемый код и зависимости могли быть правильно подключены и выполнены. В современном JavaScript используются разные системы модулей: CommonJS, ES Modules (ESM) и AMD. Karma предоставляет гибкие механизмы для их интеграции, что позволяет использовать как Node.js-модули, так и фронтенд-библиотеки.


Конфигурация файлов и модулей

В файле karma.conf.js определяются файлы и шаблоны, которые Karma будет загружать. Основные опции:

module.exports = function(config) {
  config.set({
    files: [
      'src/**/*.js',        // исходный код
      'test/**/*.spec.js'   // тесты
    ],
    frameworks: ['mocha', 'chai'], // фреймворки тестирования
    preprocessors: {
      'src/**/*.js': ['babel'],
      'test/**/*.spec.js': ['babel']
    }
  });
};

Ключевой момент: порядок загрузки файлов имеет значение. Если тест зависит от определённого модуля, сначала нужно подключать исходный код, затем тесты.


Поддержка CommonJS и Node.js-модулей

Для модулей CommonJS Karma не предоставляет встроенного загрузчика. Обычно используется Browserify или Webpack:

preprocessors: {
  'src/**/*.js': ['browserify'],
  'test/**/*.spec.js': ['browserify']
},
browserify: {
  debug: true,
  transform: ['babelify'] // позволяет использовать ES6+ синтаксис
}

Особенности работы:

  • require() становится доступен в браузере.
  • Все зависимости упаковываются в единый бандл.
  • Можно подключать сторонние npm-пакеты без изменений.

Поддержка ES Modules (ESM)

Современные браузеры поддерживают ESM, и Karma может использовать это напрямую:

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],
    files: [
      { pattern: 'src/**/*.js', type: 'module' },
      { pattern: 'test/**/*.spec.js', type: 'module' }
    ]
  });
};

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

  • Используется синтаксис import и export.
  • Модули загружаются асинхронно.
  • Порядок загрузки определяется зависимостями import.
  • Karma автоматически подключает <script type="module"> в тестовой среде.

Работа с AMD (Asynchronous Module Definition)

AMD распространён в старых проектах, часто вместе с RequireJS. Karma поддерживает его через соответствующий фреймворк:

frameworks: ['mocha', 'requirejs'],
files: [
  'src/**/*.js',
  'test/**/*.spec.js',
  { pattern: 'test/test-main.js', included: true }
]

В файле test-main.js описывается загрузка модулей:

require.config({
  baseUrl: 'src',
  paths: {
    utils: 'utils'
  }
});

require(['utils/math'], function(math) {
  window.math = math; // доступ для тестов
});

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


Препроцессоры и трансформации

Для работы с современным JavaScript часто используют Babel, TypeScript, Webpack или Rollup как препроцессоры. Karma предоставляет интерфейс для их подключения:

preprocessors: {
  'src/**/*.js': ['webpack'],
  'test/**/*.spec.js': ['webpack']
},
webpack: {
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      }
    ]
  }
}

Преимущества:

  • Поддержка современных стандартов JavaScript.
  • Возможность использовать JSX, TypeScript и другие расширения.
  • Сборка модулей в единый бандл, готовый для браузера.

Изоляция модулей

Karma запускает каждый тестовый файл в отдельной сессии браузера, что позволяет изолировать состояния модулей. Однако глобальные переменные остаются доступными. Рекомендации:

  • Использовать import/require вместо глобальных переменных.
  • Для моков и заглушек использовать sinon или встроенные возможности фреймворков.
  • Проверять, что каждый модуль корректно очищается между тестами, особенно если используются синглтоны или статические объекты.

Динамическая загрузка модулей

В некоторых случаях тесты требуют динамической подгрузки модулей во время выполнения. Karma позволяет это через асинхронные функции:

it('должен динамически загрузить модуль', async function() {
  const module = await import('../src/utils/math.js');
  assert.equal(module.add(2, 3), 5);
});

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

  • Поддерживается только в ESM-сценариях или при использовании Webpack с динамическим import().
  • Позволяет тестировать lazy-loaded функции и модули.

Организация большого проекта

При масштабных проектах рекомендуется:

  1. Разделять тесты по каталогам, соответствующим структуре исходного кода.
  2. Использовать pattern и included: false для модульной загрузки.
  3. Применять препроцессоры для поддержки всех современных возможностей языка.
  4. Настраивать Karma совместно с Webpack/Browserify для единообразной сборки.

Эти подходы обеспечивают корректную обработку модулей, минимизируют проблемы с зависимостями и упрощают масштабирование тестовой инфраструктуры.