Tunneling решения

Karma — это тестовый раннер для JavaScript, который позволяет запускать тесты в реальных браузерах, обеспечивая интеграцию с различными фреймворками вроде Jasmine, Mocha или QUnit. Для работы требуется Node.js и npm. Установка производится через пакетный менеджер:

npm install --save-dev karma karma-cli

После установки глобально или локально можно инициализировать конфигурационный файл:

npx karma init

Файл karma.conf.js является основой для настройки: он определяет браузеры, фреймворк, файлы для тестирования и репортеры. Ключевые поля:

  • frameworks — указывает тестовый фреймворк (например, ['jasmine']).
  • files — список файлов и шаблонов для тестирования.
  • browsers — браузеры, в которых будут выполняться тесты (Chrome, Firefox, PhantomJS).
  • reporters — формат вывода результатов (dots, progress, coverage).

Пример минимальной конфигурации:

module.exports = function(config) {
  config.set({
    frameworks: ['jasmine'],
    files: [
      'src/**/*.js',
      'test/**/*.spec.js'
    ],
    browsers: ['Chrome'],
    reporters: ['progress']
  });
};

Интеграция с фреймворками

Jasmine — наиболее часто используемый фреймворк для Karma. Тесты строятся на основе блоков describe и it:

describe('Модуль калькулятора', () => {
  it('должен складывать два числа', () => {
    expect(2 + 3).toBe(5);
  });
});

Mocha позволяет более гибко настраивать асинхронные тесты с использованием done или промисов:

describe('Асинхронная операция', () => {
  it('возвращает результат через промис', (done) => {
    asyncFunction().then(result => {
      expect(result).toEqual(42);
      done();
    });
  });
});

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


Репортеры и покрытие кода

Для анализа результатов тестирования используются репортеры. Основные:

  • progress — стандартный прогресс выполнения тестов.
  • dots — краткий вывод точек, каждая точка — один тест.
  • karma-coverage — генерация отчётов покрытия кода.

Пример настройки покрытия кода:

module.exports = function(config) {
  config.set({
    frameworks: ['jasmine'],
    files: [
      'src/**/*.js',
      'test/**/*.spec.js'
    ],
    preprocessors: {
      'src/**/*.js': ['coverage']
    },
    reporters: ['progress', 'coverage'],
    coverageReporter: {
      type: 'html',
      dir: 'coverage/'
    }
  });
};

После запуска тестов в директории coverage появляется детализированный HTML-отчёт, показывающий процент покрытия функций, строк и ветвлений.


Работа с браузерами и Tunneling

Karma может запускать тесты в локальных браузерах и удалённых через Tunneling. Это актуально для CI/CD, когда тесты должны выполняться в облачных сервисах (BrowserStack, Sauce Labs) или на нестандартных конфигурациях браузеров.

Принцип Tunneling: Karma через локальный туннель соединяется с внешним сервисом, позволяя тестам запускаться на удалённых машинах и возвращать результаты в локальный CI.

Пример конфигурации для BrowserStack:

module.exports = function(config) {
  config.set({
    frameworks: ['jasmine'],
    files: [
      'src/**/*.js',
      'test/**/*.spec.js'
    ],
    browsers: ['BS_Chrome'],
    customLaunchers: {
      BS_Chrome: {
        base: 'BrowserStack',
        browser: 'chrome',
        browser_version: 'latest',
        os: 'Windows',
        os_version: '11'
      }
    },
    browserStack: {
      username: process.env.BROWSERSTACK_USERNAME,
      accessKey: process.env.BROWSERSTACK_ACCESS_KEY
    }
  });
};

Ключевые моменты работы туннеля:

  • Настройка customLaunchers позволяет создавать любые комбинации ОС и браузеров.
  • Параметры username и accessKey берутся из переменных окружения, что безопаснее хранения в коде.
  • Тесты, запускаемые через туннель, полностью синхронизируются с локальной системой Karma, включая репортеры и покрытие кода.

Асинхронные тесты и контроль времени

Karma позволяет точно управлять таймингом тестов:

  • browserNoActivityTimeout — время ожидания отклика браузера.
  • captureTimeout — время ожидания подключения браузера к Karma.

Асинхронные тесты можно реализовать через промисы, async/await или через колбэки done:

it('должен ждать асинхронную операцию', async () => {
  const result = await fetchData();
  expect(result).toBeDefined();
});

Эта гибкость критична для интеграционных тестов, особенно при работе через туннель, где сетевые задержки могут быть непредсказуемыми.


Инструменты для расширения возможностей

Karma поддерживает плагины:

  • karma-webpack — сборка тестов через Webpack.
  • karma-rollup-preprocessor — использование Rollup для модульного тестирования.
  • karma-sourcemap-loader — поддержка source map для удобной отладки.

Пример подключения Webpack:

module.exports = function(config) {
  config.set({
    frameworks: ['jasmine'],
    files: ['test/**/*.spec.js'],
    preprocessors: {
      'test/**/*.spec.js': ['webpack', 'sourcemap']
    },
    webpack: {
      mode: 'development',
      devtool: 'inline-source-map'
    }
  });
};

Такой подход позволяет использовать современные стандарты JavaScript, TypeScript и модульную структуру в тестах Karma.


Автоматизация в CI/CD

Karma легко интегрируется с системами CI/CD (Jenkins, GitLab CI, GitHub Actions):

  • Тесты запускаются автоматически при пуше или pull request.
  • Результаты и отчёты покрытия могут публиковаться в виде артефактов.
  • Использование туннеля позволяет тестировать проект на разных версиях браузеров в облаке без локальной установки.

Пример скрипта для GitHub Actions:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm install
      - run: npx karma start karma.conf.js --single-run

Многоуровневая стратегия тестирования

Karma поддерживает комбинированный подход:

  1. Unit-тесты — проверка функций и модулей локально.
  2. Integration-тесты — проверка взаимодействия модулей в браузере через туннель.
  3. End-to-End тесты — с использованием Karma + Selenium или внешних сервисов через туннель.

Такой подход обеспечивает комплексное покрытие и стабильность кода при изменениях и обновлениях.