KarmaJS, Jasmine, RequireJS и т. д.: как использовать Require для тестирования модулей

Запуск тестов Karma + Jasmine с помощью RequireJS — начало работы

Помощь! . . . _ _ _ . . . СОС!

В настоящее время у меня есть проект упражнений, чтобы освоиться с KarmaJS и модульным тестированием в целом. Общая проблема заключается в том, что у меня действительно нет четкого представления о том, что Karma делает за кулисами, и я не могу найти адекватную документацию в соответствующих областях. Без дальнейшего промедления...

Вот моя структура папок:

root
    |-/lib
        |-/[dependencies] (/angular, /angular-mocks, /bootstrap, /etc)  # from bower
    |-/src                                                              
        |-/[unreferenced directories] (/js, /css, /views)               # not referenced anywhere
        |-app.js                                                        # sets up angular.module('app', ...)
        |-globals.js                                                    # may be referenced in RequireJS main file; not used.
        |-index.html                                                    # loads bootstrap.css and RequireJS main file
        |-main.js                                                       # .config + require(['app', 'etc'])
        |-routeMap.js                                                   # sets up a single route
        |-test-file.js                                                  # *** simple define(function(){ return {...}; })
    |-/test
        |-/spec
            |-test-test-file.js                                         # *** require || define(['test-file'])
    |-.bowerrc                                                          # { "directory": "lib" }
    |-bower.json                                                        # standard format
    |-karma.conf.js                                                     # *** HELP!
    |-test-main.js                                                      # *** Save Our Souls!!!

karma.conf.js

// Karma configuration
// Generated on Wed Nov 19 2014 15:16:56 GMT-0700 (Mountain Standard Time)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine', 'requirejs'],


    // list of files / patterns to load in the browser
    files: [
      //'test/spec/test-test-file.js',
      //'lib/**/*.js',
      //'src/**/*.js',
      //'test/spec/**/*.js',
      'test-main.js',
      {pattern: 'lib/**/*.js', included: false},
      {pattern: 'src/**/*.js', included: false},
      {pattern: 'test/spec/*.js', included: true}
    ],


    // list of files to exclude
    exclude: [
        'lib/**/!(angular|angular-mocks|angular-resource|angular-route|require|text).js',
        'lib/**/**/!(jquery|bootstrap).js',
        'src/app.js'
    ],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false
  });
};

test-main.js

var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;

var pathToModule = function(path) {
    return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};

Object.keys(window.__karma__.files).forEach(function(file) {
    if (TEST_REGEXP.test(file)) {
        // Normalize paths to RequireJS module names.
        allTestFiles.push(pathToModule(file));
    }
});

require.config({
    // Karma serves files under /base, which is the basePath from your config file
    baseUrl: '/base/src',
    
    paths: {
        
        angular: '../lib/angular/angular',
        ngRoute: '../lib/angular-route/angular-route',
        jquery: '../lib/jQuery/dist/jquery',
        bootstrap: '../lib/bootstrap/dist/js/bootstrap',
        models: 'models',
        controllers: 'controllers',
        globals: 'globals',
        routeMap: 'routeMap'
    },
    shim: {
        angular: {
            exports: 'angular'
        },
        ngRoute: {
            deps: ['angular']
        },
        jquery: {
            exports: '$'
        },
        bootstrap: {
            deps: ['jquery']
        }
    },

    // dynamically load all test files
    deps: allTestFiles,

    // we have to kickoff jasmine, as it is asynchronous
    callback: window.__karma__.start
});

test-test-file.js

console.log('....................');

define(function(){
    //console.log('testing test-file', testFile);
    
    describe('Testing testing', function(){
        it('should work', function(){
            expect(true).toEqual(true);
        });
    });

});

test-file.js

define('testFile', [], function(){
    
    return function init(sandbox){
        var app, application = app = sandbox.app
          , globals = sandbox.globals;
        
        return {
            some: 'module'
        };
    };
    
});

Вопросы и описания

Ключевые моменты, на которые я хотел бы услышать ответы:

  • что делает { pattern: '...', include: true|false }?
  • лучший способ исключить все лишнее внутри каталогов беседки.
  • какие файлы мне нужно включить в файл test-main.js?
  • какие файлы мне нужно включить в файл karma.conf.js?
  • что на самом деле делает test-main.js; Для чего это?

Я получаю сообщения об ошибках и проблемах, как только я оборачиваю свою спецификацию в вызов define(...) -- событие, когда я даю модулю идентификатор -- define('someId', function(){ ... }) -- нужно ли мне что-то вернуть из этого модуля, так как он это вызов define?

В других случаях я получаю сообщение 'ol ERROR: 'Нет временной метки для /base/src/app.js!'. Временная метка, конечно! Как глупо с моей стороны... -- что, черт возьми, это значит?! Иногда я получаю печально известную ошибку Executed 0 of 0 ERROR. Я также мог бы внести некоторую ясность, пожалуйста. На самом деле, я получаю много ошибок ERROR: '...no timestamp...' -- и даже 404s, когда кажется, что я должен использовать эту библиотеку вместе с karma.conf.js files конфиг...???

Кажется даже, что обычно, когда я явно говорю карме исключить src/app.js, я все равно получаю 404 и ошибки.

тл;др

Очевидно, я немного сбит с толку новичком в карме и *DD в целом...

Я могу запустить test-test-file.js нормально, когда мой массив files karma.conf.js выглядит как [ 'test-main.js', 'test/spec/test-test-file.js' ], но, тем не менее, если я завершу свой тест вызовом определения RequireJS, я получаю упомянутую ошибку Mismatching anonymous define() над.

Кажется, что когда я добавляю { pattern: '...', include: false, карма просто не добавляет ни один из моих файлов для данного шаблона ( ???).

Если кто-то может просто указать мне, как использовать RequireJS с Karma, а именно, чтобы я мог просто обернуть свои тесты вызовом define/require и вытащить модуль, который хочу протестировать... Это было бы очень признательно.

Поскольку несколько сложно задавать такие вопросы кратко и при этом предоставлять адекватную информацию, я надеюсь, что не сделал их слишком длинными.


РЕДАКТИРОВАТЬ

Прочитав ответ от glepretre и немного повозившись самостоятельно, я перенастроил свой проект следующим образом:

  • Перемещено test-main.js в test/test-main.js,
  • переименовал test-test-file.js в testFileSpec.js — переместил его с test/spec на test/,

karma.conf.js:

...
// list of files / patterns to load in the browser
files: [
    {pattern: 'lib/**/*.js', included: false},
    {pattern: 'src/**/*.js', included: false},
    {pattern: 'test/**/*Spec.js', included: false},
    
    'test/test-main.js'
  
],
....

тест/test-main.js:

/* **************** HOW COME THE DEFAULT (Karma-generated) CONFIGURATION DOES ***NOT WORK???
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;

var pathToModule = function(path) {
    return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};

Object.keys(window.__karma__.files).forEach(function(file) {
    if (TEST_REGEXP.test(file)) {
        // Normalize paths to RequireJS module names.
        allTestFiles.push(pathToModule(file));
    }
});
*/

var tests = [];
for (var file in window.__karma__.files) {
    if (/Spec\.js$/.test(file)) {
        tests.push(file);
    }
}

require.config({
    // Karma serves files under /base, which is the basePath from your config file
    baseUrl: '/base/src',
    
    paths: {},
    shim: {},

    // dynamically load all test files
    //deps: allTestFiles,
    //
    deps: tests,

    // we have to kickoff jasmine, as it is asynchronous
    callback: window.__karma__.start
});

Теперь я успешно запускаю модульные тесты! Особая благодарность glepretre и всем другим участникам.


Спасибо за любое понимание вообще :)


person Cody    schedule 20.11.2014    source источник


Ответы (1)


Хорошо, я постараюсь ответить на каждый вопрос по очереди:

Вопрос 1

  • что делает { pattern: '...', included: true|false }?

Поведение Karma по умолчанию:

  • найти все файлы, соответствующие pattern (обязательное свойство)
  • следите за ними на наличие изменений (опция watched), чтобы перезапустить ваши модульные тесты, чтобы дать вам живой результат, когда вы редактируете свой код (работает, только если вы оставите значение по умолчанию autoWatch по умолчанию равным true).
  • обслуживать их с помощью собственного веб-сервера (вариант served)
  • включить их в браузер с помощью <script> (опция included)

Итак, в массиве files конфига кармы можно использовать поведение по умолчанию, добавляя только строковые шаблоны:

files: [
  // this will match all your JS files 
  // in the src/ directory and subdirectories
  'src/**/*.js'
]

Или используйте полный синтаксис объекта для настройки каждой опции:

files: [
  {pattern: 'src/**/*.js', watched: true, served: true, included: false}
]

Используя requireJS, вы НЕ хотите, чтобы они были включены, потому что это будет конфликтовать с поведением requireJS!

Включено. Описание: Должны ли файлы включаться в браузер с помощью тега <script>? Используйте false, если вы хотите загрузить их вручную, например. с помощью Require.js.

из karma/config/files docs

Примечание. Обратите внимание на порядок добавления файлов/шаблонов в массив. Это важно! Для большего понимания установите logLevel: config.LOG_DEBUG в конфигурации кармы.

Вопрос 2

  • какие файлы мне нужно включить в файл karma.conf.js?

По крайней мере, все необходимые файлы для правильного функционирования ваших компонентов для модульного тестирования.

По сути, все файлы, перечисленные в блоках define([]) и require().

Вопрос 3

  • лучший способ исключить все лишнее внутри каталогов беседки.

Что именно вы пытаетесь сделать?

Основываясь на том, что я писал ранее, вы можете видеть, что вы можете выборочно добавлять файлы, которые вам понадобятся в ваших тестах.

Я добавляю шаблон '/bower_components/**/*.js' и даже '/bower_components/**/*.html', когда мои пакеты Bower используют шаблоны. Я никогда не замечал серьезных проблем с производительностью, если вас это беспокоит... Вам решать, какие шаблоны файлов вам понадобятся.

Вопрос 4 и 5

  • что на самом деле делает test-main.js; Для чего это?

  • какие файлы мне нужно включить в файл test-main.js?

Цель файла test-main.js — найти и загрузить ваши тестовые файлы перед запуском Karma. Он соединяет точки между Karma и requireJS

Вы должны выбрать соглашение для именования ваших тестовых файлов, а затем определить TEST_REGEXP для соответствия всем им.

В официальном руководстве по стилю angular и рекомендациях для структуры приложения рекомендуется использовать суффикс *_test.js.

РЕДАКТИРОВАТЬ: Ваше регулярное выражение не работает, потому что оно определено так, чтобы ловить "spec.js" || "test.js" в конце, или имя вашего файла спецификации заканчивается на "file.js" ;) См. http://regex101.com/r/bE9tV9/1

Еще кое-что

Надеюсь, я был достаточно ясен. Вы можете ознакомиться со структурой начального приложения для наших проектов, использующих Angular + Require: angular-requirejs-ready . Он уже настроен и протестирован как с Karma, так и с Protractor.

person glepretre    schedule 24.11.2014
comment
glepretre, большое спасибо за ваш подробный и очень полезный ответ - это мне очень помогло. Единственное — и я отмечу ваш ответ как «Принятый» — теперь, когда я успешно запускаю тесты, я хотел бы узнать больше о настройках конфигурации в test-main.js. Я переключился с созданных Karma allTestFiles & var TEST_REGEXP = /(spec|test)\.js$/i; на те, которые доступны онлайн, var tests = []; и if (/Spec\.js$/.test(file)) {...} (см. мое редактирование выше). Не могли бы вы уточнить это для нас, кодировщиков, не использующих RegExp? Просто хочу понять, ПОЧЕМУ это не удалось для меня - спасибо - person Cody; 25.11.2014
comment
вы мне очень помогли! Огромное спасибо (тонн). Отличный ответ (ы) - я отмечу это как принятый ответ - Ура - person Cody; 25.11.2014