Получение ворчащей кармы для запуска unit test

Мне было интересно, есть ли у кого-то хрюкая карма, чтобы запустить только одну спецификацию, которая меняется на часы. Это моя конфигурация ниже. Проблема в том, что строка grunt.config('karma.unit.options.files', filepath); похоже, ничего не делает, поскольку все спецификации все еще запущены, но foo действительно получает выход перед кармой: unit: run запущен.

grunt.initConfig({
    karma: {
        unit: {
            configFile: 'karma.conf.js',
            background: true,
            singleRun: false,
            options: {
                files: allFilesArray
            }
        }
    },
    watch: {
        options: {
            spawn: false,
            livereload: true
        },
        karma: {
            files: ['js/spec/**/*.spec.js', 'js/src/**/*.js'],
            tasks: ['karma:unit:run']
        }
    }
})

grunt.event.on('watch', function (action, filepath){
    console.log('foo');
    grunt.config('karma.unit.options.files', filepath);
});

Есть ли кто-нибудь из тех, кто добился выполнения одной спецификации в терминале при смене файла? У нас тысячи тестов, поэтому он начинает замедляться.

Спасибо, Alex

Ответ 1

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

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

grunt.initConfig({
  // ...
  karma: {
    all: {
      configFile: 'karma.conf.js',
      browsers: ['PhantomJS'],
      singleRun: true,
      options: {
        files: [
          'bower_components/jquery/dist/jquery.js', // dependencies
          'src/js/**/*.js', // js source files
          'src/js/**/*.spec.js' // unit test files
        ]
      }
    },
    one: {
      configFile: 'karma.conf.js',
      browsers: ['PhantomJS'],
      singleRun: true,
      files: [
        {src: 'bower_components/jquery/dist/jquery.js'}, // dependencies
        {src: ['src/js/**/*.js','!src/js/**/*.spec.js']} // source files
        // (exclude the unit test files)
        // watchEventListener will add the unit test file to run
      ]
    }
  },
  // ...
});

Затем, затем в моем файле grunt, я добавляю слушатель для просмотра событий. Этот слушатель обновляет карму: одна задача и добавляет файл unit test. Мы сохраняем копию исходного массива файлов, иначе наши дополнения будут сохраняться и накапливаться в течение всей жизни задачи просмотра.

// when a unit test changes, execute only it
var original_karmaOne_files = grunt.config.get('karma.one.files'); // keep the original files array
grunt.event.on('watch', function watchEventListener(action, filepath, target){

  // this handler handles ALL watch changes. Try to filter out ones from other watch tasks
  if (target == 'js_spec') handleJSHintSpec();

  // ---------------------
  function handleJSHintSpec() {
    if (action == 'deleted') return; // we don't need to run any tests when a file is deleted
    // this will probably fail if a watch task is triggered with multiple files at once
    // dynamically change the config
    grunt.config.set('karma.one.files', [].concat(original_karmaOne_files, [{src: filepath}]));
  }
});

И вот моя задача для просмотра gruntfile:

watch: {
  // ...
  // when js spec files change,
  // lint them
  // run unit tests
  js_spec: {
    options: {
      interrupt: true
    },
    files: 'src/js/**/*.spec.js',
    tasks: ['jshint:js_spec', 'karma:one']
  },
  // ...
}

Мой файл karma.conf.js довольно по умолчанию, но его массив файлов пуст. Собственно, я прокомментировал это, поэтому свойство undefined.

// list of files / patterns to load in the browser
//files: [], // specified in the gruntfile

Ответ 2

TL; DR: Используйте карму: единица везде, а не карма: unit: запустите и используйте grunt.event.on('watch', function() {}); для редактирования конфигурации кармы, чтобы включать только те файлы тестов, которые вы хотите запустить.

У меня это работает, но это может быть не то, что вы хотите. Я запускаю сервер снова каждый раз, когда я сохраняю файл. Дальнейшее объяснение ниже. Вот некоторые из конфигураций:

    watch: {
        tests: {
            files: 'tests/**/*.js',
            tasks: ['karma:unit']
        },
        tsChanged: {
            files: config.tsFiles,
            tasks: [
                'ts',
                'karma:unit'
            ]
        }
    }

    grunt.event.on('watch', function(action, filepath){
        grunt.config(['karma', 'unit', 'files'], [{
            src: [
                path/to/your/source/files,
                path/to/your/test/file,
            ]
        }]);
    });

Мне кажется, что карма загружает все файлы приложений и тестовые файлы в браузер при каждом запуске сервера. В вашем случае это будет когда вы вводите "grunt karma: unit: start watch" в командную строку. Итак, здесь я использовал "ворчащие часы" и просто добавил "карму: единица" в процесс. Затем я поймал событие сохранения и обновил конфигурацию кармы до того, как он запустил сервер.

Надеюсь, что это поможет.

Ответ 3

Используя комбинацию yargs и некоторой магии времени выполнения, я делаю это:

var argv = require('yargs')
    .default('t', '*.js')
    .alias('t', 'tests')
    .describe('t', 'A file or file pattern of the test files to run, relative to the test/unit dir')
    .help('?')
    .alias('?', 'help')
    .argv;

var filesToLoad = ['src/**/*.js', 'test/unit/helpers/*.js'];
filesToLoad.push(path.join('test/unit/**', argv.t));

gulp.task('tdd', function (done) {
    karma.start({
        configFile: __dirname + '/../../karma.conf.js',
        jspm: {
            loadFiles: filesToLoad,
        }
    }, function(e) {
        done();
    });
});

Что берет тестовый файл/шаблон пути в качестве аргумента для gulp и загружает это предпочтение ко всем файлам.

Ответ 4

Основываясь на ответе Маттиаса и комментариях, мой Grundfile.js:

module.exports = function (grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        karma: {
            all: {
                configFile: 'karma.conf.js',               
                background: true,
                files: [
                    { src: './Leen.Managementsystem/bower_components/jquery/dist/jquery.js' },
                    { src: './Leen.Managementsystem/bower_components/globalize/lib/globalize.js' },
                    { src: './Leen.Managementsystem/bower_components/**/*.js', included: false },
                    { src: './Leen.Managementsystem.Tests/App/test/mockFactory.js', included: false },
                    { src: './Leen.Managementsystem/App/**/*.js', included: false },
                    { src: './Leen.Managementsystem.Tests/App/test/*.js', included: false },
                    { src: './Leen.Managementsystem.Tests/App/**/*.spec.js', included: false },   
                    { src: './Leen.Managementsystem.Tests/App/test-main.js' }
                ]
            },
            one: {
                configFile: 'karma.conf.js',               
                files: [
                    { src: './Leen.Managementsystem/bower_components/jquery/dist/jquery.js' },
                    { src: './Leen.Managementsystem/bower_components/globalize/lib/globalize.js' },
                    { src: './Leen.Managementsystem/bower_components/**/*.js', included: false },
                    { src: './Leen.Managementsystem.Tests/App/test/mockFactory.js', included: false },
                    { src: './Leen.Managementsystem/App/**/*.js', included: false },
                    { src: './Leen.Managementsystem.Tests/App/test/*.js', included: false },          
                    // (do not inlcude the *.spec.js files here! The watch event listener will add the single spec file to run)
                    { src: './Leen.Managementsystem.Tests/App/test-main.js' }   
                ]
            }
        },
        watch: {           
            spec_js: {
                options: {
                    interrupt: true,
                    spawn: false
                },
                files: 'Leen.Managementsystem.Tests/App/**/*.spec.js',
                tasks: ['karma:one:start']               
            }
        }
    });

    var originalKarmaOneFiles = grunt.config.get('karma.one.files'); // keep the original files array

    grunt.event.on('watch', function watchEventListener(action, filepath, target) {

        if (target === 'spec_js') {
            handleChangedSpecFile();
        }

        function handleChangedSpecFile() {
            if (action === 'deleted') {
                return;
            }           

            var testFilePath = "./" + filepath.replace(/\\/g, "/");

            grunt.log.writeln(['Running single karma test for: ' + testFilePath]);
            var updatedFiles = originalKarmaOneFiles.concat([{ src: testFilePath, included: false }]);

            grunt.config.set('karma.one.files', updatedFiles);
        }
    });


    grunt.loadNpmTasks('grunt-karma');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.registerTask('default', ['karma:all','watch']);

};

karma.conf.js:

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

      // base path, that will be used to resolve files and exclude
      basePath: '', //the solution root path, e.g. D:\Energienetzwerke\trunk


      // frameworks to use
      frameworks: ['jasmine', 'requirejs'],

      // list of files / patterns to load in the browser
      files: [
        './Leen.Managementsystem/bower_components/jquery/dist/jquery.js',
        './Leen.Managementsystem/bower_components/globalize/lib/globalize.js',
        { pattern: './Leen.Managementsystem/bower_components/**/*.js', included: false },
        { pattern: './Leen.Managementsystem.Tests/App/test/mockFactory.js', included: false },
        { pattern: './Leen.Managementsystem/App/**/*.js', included: false },
        { pattern: './Leen.Managementsystem.Tests/App/test/*.js', included: false},
        { pattern: './Leen.Managementsystem.Tests/App/**/*.spec.js', included: false},
        './Leen.Managementsystem.Tests/App/test-main.js'
      ],


      // list of files to exclude
      exclude: [
        './Leen.Managementsystem/App/main.js'
      ],


      // test results reporter to use
      // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
      reporters: ['progress', 'coverage', 'notify', 'htmlDetailed', 'xml'],



      coverageReporter: {
        dir: './Leen.Managementsystem.Tests/testCoverage',
        reporters: [
          { type: 'html',subdir: 'html'},
          { type: 'cobertura',subdir: 'xml', file: 'coverage.xml' },
          { type: 'lcov', subdir: 'lcov' },
          { type: 'text-summary' }
          ]
      },


      notifyReporter: {
        reportEachFailure: true, // Default: false, Will notify on every failed spec
        reportSuccess: false // Default: true, Will notify when a suite was successful
      },

      htmlDetailed: {
        autoReload: true,
        dir: './Leen.Managementsystem.Tests/testResults'

      },
    preprocessors: {
      // source files, that you wanna generate coverage for
      // do not include tests or libraries
      // (these files will be instrumented by Istanbul)
      './Leen.Managementsystem/App/**/*.js': ['coverage']
    },


    // 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: false, //watching is done by Gruntfile.js to only execute changed tests
    usePolling: true,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: ['Chrome_With_Saved_DevTools_Settings'],

    customLaunchers: {
        Chrome_With_Saved_DevTools_Settings: {
            base: 'Chrome',
            chromeDataDir: './.chrome'            
        }
    },


    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,


    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: true
  });
};

package.json:

{
  "name": "solution",
  "version": "1.0.0",
  "description": "contains packages that are needed for running karma",
  "main": "./Leen.Managementsystem.Tests/App/test-main.js",
  "dependencies": {
    "grunt": "1.0.1",
    "grunt-cli": "1.2.0",
    "grunt-contrib-watch": "1.0.0",
    "grunt-karma": "2.0.0",
    "jasmine-core": "2.6.4",
    "karma": "1.7.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "1.0.1",
    "karma-coverage": "1.1.1",
    "karma-firefox-launcher": "1.0.1",
    "karma-html-detailed-reporter": "1.1.20",
    "karma-ie-launcher": "1.0.0",
    "karma-jasmine": "1.1.0",
    "karma-notify-reporter": "1.0.1",
    "karma-phantomjs-launcher": "1.0.4",
    "karma-requirejs": "1.1.0",
    "karma-xml-reporter": "0.1.4",
    "requirejs": "2.3.4"
  },
  "devDependencies": {},
  "scripts": {
    "test": "karma run"
  },
  "author": "LEEN",
  "license": "private"
}