执行 gulp 任务时无法在 karma 配置文件上加载 "mocha" 框架

Can not load "mocha" framework on karma configuration file while executing gulp task

在执行 gulp test-browser 命令时,我收到以下警告消息

WARN [reporter]: Can not load "mocha", it is not registered!
Perhaps you are missing some plugin?

但如果我执行 karma start 命令,它工作正常,它不会显示任何警告消息。

为什么我会收到此警告消息?
我在这里错过了什么?

package.json

{
'''
 "dependencies": {
    "browser-sync": "^2.9.12",
    "gulp": "^3.9.0",
    "karma": "^0.13.15",   
    "karma-mocha": "^0.2.0",
    "mocha": "^2.3.3"
  },
  "devDependencies": {
    "karma-phantomjs-launcher": "^0.2.1",
    "phantomjs": "^1.9.18"
  }
}

gulpfile.js

gulp.task('test-browser', function () {
var config = {
    configFile: __dirname + '/karma.conf.js',
    singleRun: true,
    reporters: ['mocha']
};
var server = new Server(config);
server.start();
});

karma.conf.js

module.exports = function (config) {
config.set({
    browsers: ['PhantomJS'],        
    frameworks: ['mocha'],
    files: [
        "bower_components/angular/angular.js",
        "bower_components/chai/chai.js",
        "app/**/*.js",
        "test/*.spec.js"
        ]
    });
};

我唯一的不同是我没有 mocha 作为记者,我在 karma.conf.js

的框架中有 chai

gulpfile.js(注意:我的手表是为了代码更改,我在部署之前构建和测试,所以这不会自动运行)。

gulp.task('Tests', function(done) {
    karma.start({
        configFile: __dirname + '/karma.conf.js',
        coverageReporter: {
            type : 'html',
            dir: RootDir.docs + DocumentationPath.CodeCoverage,
        },
        singleRun: true
    }, function() {
        done();
    });

karma.conf.js

module.exports = function(config) {

    var SourceCode = [
        'app/app.js',
        ...
    ];

    var Libraries = [
        'app/bower_components/angular/angular.js',
        ...
    ];

    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: ['mocha', 'chai'],

        // list of files / patterns to load in the browser
        files: Libraries.concat(SourceCode),


        // list of files to exclude
        exclude: [
        ],


        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
            'app/**/*.js': ['coverage']
        },

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

        coverageReporter: {
            type : 'html',
            dir : 'docs/coverage/'
        },

        logLevel: 'LOG_DEBUG',

        // 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,

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

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

我的完整gulpfile.js。这已针对各种项目进行了修改,并没有使用所有内容。它还使用我们遵循的源代码结构。该工具在开发人员机器上监视和准备我们的发布目录,同时作为数据的本地副本。

var gulp = require('gulp');
var AppSync = require('browser-sync').create();
var mainBowerFiles = require('main-bower-files');
var concat = require('gulp-concat');
var del = require('del');
var fs = require('fs');
var GoogleCDN = require('gulp-google-cdn');
var Graph = require('gulp-angular-architecture-graph');
var csslint = require('gulp-csslint');
var header = require('gulp-header');
var hhint = require('gulp-htmlhint');
var hlint = require('gulp-htmllint');
var imagemin = require('gulp-imagemin');
var pngquant = require('imagemin-pngquant');
var istanbul = require('gulp-istanbul');
var jscs = require('gulp-jscs');
var stylish = require('gulp-jscs-stylish');
var jshint = require('gulp-jshint');
var jsonlint = require('gulp-jsonlint');
var karma = require('karma').Server;
var mocha = require('gulp-mocha');
var minifyCss = require("gulp-minify-css");
var minifyHtml = require("gulp-minify-html");
var notify = require("gulp-notify");
var plumber = require('gulp-plumber');
var run = require('gulp-run');
var size = require('gulp-size');
var sourcemaps = require('gulp-sourcemaps');
var stripdebug = require('gulp-strip-debug');
var uglify = require('gulp-uglify');
var util = require('gulp-util');
var watch = require('gulp-watch');

// Get Information using NodeJs file system from files for the Application
var getApplicationName  = function()    { return ReadLocalFile( RootDir.config + 'Application', __dirname); };
var getBuildGraphic     = function()    { return ReadLocalFile( RootDir.config + 'BuildGraphic', ''); };
var getCopyright        = function()    { return ReadLocalFile( RootDir.config + 'Copyright', 'Copyright (c) 2015 - Steven Scott'); };
var getVersion          = function()    { return ReadLocalFile( RootDir.config + 'Version', '0.0.1'); };

var getAppInfo = function() {
    var Text = [
        "/**",
        " * " + getApplicationName(),
        " * Version: " + getVersion(),
        " * " + getCopyright(),
        " */",
        ""
    ];
    return Text.join('\n');
};

var getBuildInfo = function() {
    var Text = [
        '',
        util.colors.yellow.bold(getBuildGraphic()),
        getApplicationName(),
        getCopyright(),
        'Build (' + util.colors.green(getVersion()) + ')',
        '',
    ];
    return Text.join('\n');
}

var NoOp = function() { };
var OnErrorHandler = function(err) {
    util.log(util.colors.white.bold(err + '!'));
    this.emit('end');
};

var Paths = {
    CDN: 'CDN',
    Images: 'images/',
    JavaScript: 'js/',
    JSON: 'data/',
    Libraries: 'ExternalLibraries/',
    Modules: 'Modules/',
    Styles: 'css/'
};  

var RootDir = { config: './', dist: 'dist/', docs: 'docs/', home: 'app/' };
var DocumentationPath = { API: 'API.v' + getVersion() + '/', CodeCoverage: 'Coverage/', Graphs: 'Diagrams.v' + getVersion() + '/' };

var SourcePath = {
    BowerComponents: ['bower_components/**'],
    ExtraFiles: ['favicon.ico'],
    ExtraStyleFiles: ['ExternalLibraries/ui.Grid/*.woff','ExternalLibraries/ui.Grid/*.ttf', 'ExternalLibraries/ui.Grid/*.svg'],
    HTML: ['*.html'],
    HTMLPages: ['Modules/**/*.html'],
    Images: ['graphics/**/*.gif','graphics/**/*.jpg','graphics/**/*.png',
        'Modules/**/*.gif', 'Modules/**/*.jpg', 'Modules/**/*.png'
    ],
    JSON: ['Modules/**/*.json'],

    Libraries: ['bower_components/angular-order-object-by/src/ng-order-object-by.js'],
    LibStyles: [],

    SourceCode: ['Modules/**/*.js'],
    Styles: ['Modules/**/*.css'],
    TestFiles: ['UnitTests/**/*.test.js'],
};

var ApplicationName = getApplicationName();
var BuildLogo = getBuildInfo();
var SourceCopyright = getAppInfo();

// ================ Gulp Tasks ================
// Package Bower Files into 1 Library
gulp.task('BowerFiles', function() {
    del([ RootDir.home + Paths.CDN + "*.js", RootDir.dist + Paths.CDN + "*.js" ]);
    // mainBowerFiles is used as a src for the task, usually you pipe stuff through a task
    return gulp.src(mainBowerFiles(), {cwd: RootDir.home})
        // Then pipe it to wanted directory
        .pipe(gulp.dest(RootDir.home + Paths.CDN))
        .pipe(gulp.dest(RootDir.dist + Paths.CDN))
});

// Convert Bower local files to CDN
gulp.task('BowerToCDN', ['BowerFiles'], function() {
    var CDNOptions = {
    };
    return gulp.src('index.html', {cwd: RootDir.home})
        .pipe(GoogleCDN(require(RootDir.config + 'bower.json'), CDNOptions))
        .pipe(gulp.dest(RootDir.dist));
});

// Remove Temporary files (bak, log, etc...)
gulp.task('DeleteBackupFiles', function(callback) {
    return del([ 
            RootDir.config + '**/*.bak',
            RootDir.config + 'lcov.info',
            RootDir.config + '*.log'
        ], callback)
    ;
});

// Document the API
gulp.task('Document-API', function() {
    var reportOptions = {
        err:    true,   // default = true, false means don't write err 
        stderr: true,   // default = true, false means don't write stderr 
        stdout: true    // default = true, false means don't write stdout 
    };

    del([ RootDir.docs + DocumentationPath.JavaScript ]);

    return run('node_modules\.bin\jsdoc' + 
                ' -c node_modules/angular-jsdoc/common/jsdoc.conf.json ' +   // config file
                ' -t node_modules/angular-jsdoc/default ' +    // template file
                ' -d ' + RootDir.docs + DocumentationPath.API +
                ' ./README.md ' +
                ' -r ' + RootDir.home + Paths.Modules
        ).exec();

});

// -=-=-=- Documentation - Do not wait to complete -=-=-=-
gulp.task('Documentation',['Document-API'], function() {
    del([ RootDir.docs + DocumentationPath.Graphs ]);

    return gulp.src(SourcePath.SourceCode, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(Graph({dest: RootDir.docs + DocumentationPath.Graphs})
    );
});

// -=-=-=- HTML Pages -=-=-=-   
gulp.task('HTMLPages', ['BowerToCDN'], function() {
    del([ RootDir.dist + "*.html" ]);
    gulp.src(SourcePath.HTML, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(hlint())
        //.pipe(hhint('htmlhint.json'))
            .pipe(hhint.reporter())         // FailReporter to fail build step
        .pipe(minifyHtml())
        .pipe(gulp.dest(RootDir.dist))
    ;

    del([ RootDir.dist + Paths.Modules + "**/*.html" ]);
    return gulp.src(SourcePath.HTMLPages, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(hlint())
        .pipe(hhint('htmlhint.json'))
            .pipe(hhint.reporter())         // FailReporter to fail build step
        .pipe(minifyHtml())
        .pipe(gulp.dest(RootDir.dist + Paths.Modules))
    ;
});

gulp.task('Images', function () {
    del([ RootDir.home + Paths.Images + "*.png" ]);
    del([ RootDir.dist + Paths.Images + "*.png" ]);
    return gulp.src(SourcePath.Images, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(imagemin( {
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngquant()]
        }))
        .pipe(gulp.dest(RootDir.home + Paths.Images))
        .pipe(gulp.dest(RootDir.dist + Paths.Images))
    ;
});

// -=-=-=- JSON Data -=-=-=-    
gulp.task('JSONChanges', function(callback) {
    del([ RootDir.dist + Paths.JSON]);
    return gulp.src(SourcePath.JSON, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(jsonlint())
        .pipe(jsonlint.reporter())
        .pipe(gulp.dest(RootDir.dist + Paths.JSON))
    ;
});

// -=-=-=- External Libraries -=-=-=-   
gulp.task('Libraries-CSS', function() {
    del([ RootDir.home + Paths.Libraries + 'ExternalLibraries.min.css' ]);
    return gulp.src(SourcePath.LibStyles, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
//      .pipe(minifyCss())
        .pipe(concat('ExternalLibraries.min.css'))
        .pipe(gulp.dest(RootDir.home + Paths.Libraries))
        .pipe(gulp.dest(RootDir.dist + Paths.Styles))
    ;
});

gulp.task('Libraries', ['Libraries-CSS', 'BowerToCDN'], function() {
    del([ RootDir.dist + Paths.JavaScript + 'ExternalLibraries.min.js' ]);
    return gulp.src(SourcePath.Libraries, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(concat('ExternalLibraries' + '.min.js'))
        .pipe(header(SourceCopyright))
        .pipe(size( { showFiles: false, gzip: true, title: 'Min ExternalLbraries' } ))
        .pipe(gulp.dest(RootDir.home + Paths.JavaScript))
        .pipe(gulp.dest(RootDir.dist + Paths.JavaScript))
    ;
});

// -=-=-=- Misc. File Moves -=-=-=-
gulp.task('OtherFileChanges', function() {
    gulp.src(SourcePath.ExtraFiles, {cwd: RootDir.home} )
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(gulp.dest(RootDir.dist))
    ;
    return gulp.src(SourcePath.ExtraStyleFiles, {cwd: RootDir.home} )
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(gulp.dest(RootDir.dist))
    ;
});

// -=-=-=- Source Code Processing -=-=-=-
gulp.task('SourceCode-CSS', function() {
    del([ RootDir.home + Paths.Styles + ApplicationName + ".min.css" ]);
    del([ RootDir.dist + Paths.Styles + ApplicationName + ".min.css" ]);

    return gulp.src(SourcePath.Styles, {cwd: RootDir.home})
        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(csslint('csslint.json'))
            .pipe(csslint.reporter())
        .pipe(concat(ApplicationName + '.min.css'))
        .pipe(gulp.dest(RootDir.home + Paths.Styles))
        .pipe(minifyCss())
        .pipe(gulp.dest(RootDir.dist + Paths.Styles));
    ;
});

// -=-=-=- Source Code Changed -=-=-=-
gulp.task('SourceCode', ['Documentation', 'JSONChanges', 'OtherFileChanges', 'SourceCodeTests'], function() {
    util.log(BuildLogo);

    del([ RootDir.home + Paths.JavaScript + ApplicationName + ".min.js" ]);
    del([ RootDir.dist + Paths.JavaScript + ApplicationName + ".min.js" ]);

    return gulp.src(SourcePath.SourceCode, {cwd: RootDir.home})
        .pipe(jshint())
            .pipe(jscs( 'jscs.json'))
            .on('error', NoOp)                              // Don't Stop on Errors
                .pipe(stylish.combineWithHintResults())     // combine with jshint results
                .pipe(jshint.reporter('jshint-stylish'))

        .pipe(plumber( { errorHandler: OnErrorHandler  } ))
        .pipe(concat(ApplicationName + '.min.js'))
        .pipe(header(SourceCopyright))
        .pipe(size({ showFiles: false, gzip: true, title: ApplicationName } ))
        .pipe(gulp.dest(RootDir.home + Paths.JavaScript) )

        .pipe(sourcemaps.init())
            .pipe(stripdebug())
            .pipe(uglify())

            .pipe(size({ showFiles: false, gzip: true, title: 'Min ' + ApplicationName } ))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest(RootDir.dist + Paths.JavaScript) )
    ;
});

gulp.task('SourceCodeTests', function(done) {
    karma.start({
        configFile: __dirname + '/karma.conf.js',
        coverageReporter: {
            type : 'html',
            dir: RootDir.docs + DocumentationPath.CodeCoverage,
        },
        singleRun: true
    }, function() {
        done();
    });
});

// -=-=-=- Job Tasks -=-=-=-
// Browser Sync - Auto Reload/Refresh
gulp.task('BrowserSyncStartup', ['SourceCode', 'SourceCode-CSS', 'Libraries', 'HTMLPages'], function() {
    return AppSync.init({
        server: {
            baseDir: [RootDir.config], 
            index: 'index.html',
            directory: false,           // Set to True for Browsing Files, not launching index
            routes: {
                '/API': RootDir.docs + DocumentationPath.API,
                '/app': RootDir.home,
                '/Coverage': RootDir.docs + DocumentationPath.CodeCoverage + 'PhantomJS 1.9.8 (Windows 7 0.0.0)/'
            }
        },
        port: 3000,
        startPath: '/app'
    });
});

/* Watch Tasks */
gulp.task('WatchBowerFiles', ['BowerToCDN'], function() { });
gulp.task('WatchHTMLPages', ['HTMLPages'], function() { AppSync.reload(); });
gulp.task('WatchGraphics', ['Images'], function() { AppSync.reload(); });
gulp.task('WatchLibraries', ['Libraries'], function() { AppSync.reload(); });
gulp.task('WatchSourceCodeCSS', ['SourceCode-CSS'], function() { AppSync.reload(); });
gulp.task('WatchSourceCode', ['SourceCode', 'Documentation'], function() { AppSync.reload(); });
gulp.task('WatchSourceCodeTests', ['SourceCodeTests'], function() { AppSync.reload(); });

// A development task to run anytime a file changes
gulp.task('WatchSource', ['BrowserSyncStartup'], function() {
    gulp.watch([RootDir.home + SourcePath.HTML, RootDir.home + SourcePath.HTMLPages], ['WatchHTMLPages']);
    gulp.watch(RootDir.home + SourcePath.Images, ['WatchGraphics']);
    gulp.watch(RootDir.home + SourcePath.Libraries, ['WatchLibraries']);
    gulp.watch(RootDir.home + SourcePath.SourceCode, ['WatchSourceCode']);
    gulp.watch(RootDir.home + SourcePath.Styles, ['WatchSourceCodeCSS']);
    gulp.watch(RootDir.home + SourcePath.TestFiles, ['WatchSourceCodeTests']);
});

// The default task (called when you run `gulp` from cli) runs a sequence of the above tasks
gulp.task('default',['SourceCodeTests', 'WatchSource', 'DeleteBackupFiles']);

// Write a step of the build on the console
function ShowStepOnConsole(MsgText) {
    if(MsgText.length > 0)
    {
        var ConsoleMessage = [
            'Process',
            util.colors.magenta.bold(MsgText),
        ].join(' ');
        util.log(ConsoleMessage);
    }
}

// Return with a Syncronys Call the contents of a file
function ReadLocalFile( FileName, DefaultWhenNotFound)
{
    if ( fs.existsSync(FileName) )  {
            return fs.readFileSync(FileName);
    }
    else {
        return DefaultWhenNotFound;
    }
}

这里的问题是您没有在 karma.conf.js 插件中安装或添加 karma-mocha-reporter

如果你没有安装它。

npm install karma-mocha-reporter --save-dev

并将其添加到您的 karma.conf.js 插件中。

module.exports = function(config){
config.set({
    plugins:['karma-mocha','karma-phantomjs-launcher','karma-mocha-reporter'],
    browsers:['PhantomJS'],
    frameworks:['mocha'],
    files:[
        "bower_components/angular/angular.js",
        "bower_components/angular-mocks/angular-mocks.js",
        "bower_components/chai/chai.js",

        "app/**/*.js",

        "test/*.js"
    ],
    colors: true,
})
}

它应该解决警告并使其正常工作。