使用 Karma + Jasmine 对 Browserify 项目进行单元测试

Unit Testing Browserify Project with Karma + Jasmine

我正在尝试为基于 AngularJS 的 JavaScript 插件设置单元测试。该插件通过 Gulp 与 Browserify 捆绑在一起。它依赖于从 bower_components 文件夹中注入 wiredepgulp-inject 的外部库。这一切在生成的包中工作得很好,但是如果我尝试通过 gulp 运行 Karma 单元测试,我会收到以下错误:

Uncaught TypeError: angular.module is not a function at /tmp/94dbea5947f4758ab1ee6935e2f4b3f1.browserify:365 <- app/js/services/index.js:9:0

在这个文件中,angular加载了var angular = require('angular');console.log(angular)给出了一个空对象。

我的karma.conf.js:

'use strict';

const istanbul = require('browserify-istanbul');
const isparta = require('isparta');
const mainBowerFiles = require('main-bower-files');

const karmaBaseConfig = {

    basePath: '../',

    frameworks: ['jasmine', 'browserify'],

    preprocessors: {
        'app/js/**/*.js': ['browserify', 'coverage'],
        '**/*.html': ['ng-html2js']
    },

    browserify: {
        debug: true,
        extensions: ['.js'],
        transform: [
            [["babelify", {"ignore": "/\/bower_components\//"}]],
            'browserify-ngannotate',
            'bulkify',
            'debowerify',
            'brfs',
            istanbul({
                instrumenter: isparta,
                ignore: ['**/bower_components/**', '**/node_modules/**', '**/test/**']
            })
        ]
    },

    ngHtml2JsPreprocessor: {
        stripPrefix: 'app/',
        moduleName: 'templates'
    },

    plugins: [
        'karma-jasmine',
        'karma-coverage',
        'karma-browserify',
        'karma-ng-html2js-preprocessor',
        'karma-chrome-launcher'
    ],

    files: mainBowerFiles({
        filter: '**/*.js',
        paths: {
            bowerDirectory: 'bower_components',
            bowerrc: '.bowerrc',
            bowerJson: 'bower.json'
        }
    }).concat([
        // app-specific code
        'app/js/main.js',

        // 3rd-party resources
        'node_modules/angular-mocks/angular-mocks.js',

        // test files
        'test/unit/**/*.js'
    ]),

    exclude: [],

    reporters: ['progress', 'coverage'],

    port: 9876,

    colors: true,

    autoWatch: false,

    browsers: ['Chrome'],

    singleRun: true
};

const customLaunchers = {
    chrome: {
        base: 'SauceLabs',
        browserName: 'chrome'
    }
};

const ciAdditions = {
    sauceLabs: {
        testName: 'Karma Unit Tests',
        startConnect: false,
        build: process.env.TRAVIS_BUILD_NUMBER,
        tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
    },
    browsers: Object.keys(customLaunchers),
    customLaunchers: customLaunchers,
    reporters: ['progress', 'coverage', 'saucelabs']
};

module.exports = function (config) {
    const isCI = process.env.CI;
    config.set(isCI ? Object.assign(karmaBaseConfig, ciAdditions) : karmaBaseConfig);
};

所有主要应用程序文件位于 app/、bower 文件位于 bower_components/、节点模块位于 node_modules/ 和测试规范位于 test/unit/

它基于此样板文件:https://github.com/jakemmarsh/angularjs-gulp-browserify-boilerplate

错误发生在 Karma 刚启动 Chrome 之后,但在执行任何单元测试之前(我在单元测试中检查了 console.log)。

如有任何帮助,我们将不胜感激。

终于解决了

unit.js(gulp单元任务):

'use strict';

import config   from '../config';
import path     from 'path';
import gulp     from 'gulp';
import {Server} from 'karma';

gulp.task('unit', ['copy-bower-components',
    'styles',
    'images',
    'fonts',
    'api',
    'views',
    'browserify',
    'inject'
], function (done) {

    new Server({
        configFile: path.resolve(__dirname, '../..', config.test.karma),
        singleRun: true
    }, function (exitCode) {
        console.log('Karma has exited with ' + exitCode);
        done();
    }).start();

});

此处的关键是 运行 在开始单元测试之前进行浏览器验证。 karma.conf.js:

// Karma configuration
// Generated on Sat Jan 23 2016 16:43:48 GMT+0100 (CET)

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', 'browserify'],


        // list of files / patterns to load in the browser
        files: [
            "bower_components/tether/dist/js/tether.js",
            "bower_components/jquery/jquery.js",
            "bower_components/bootstrap/dist/js/bootstrap.js",
            "bower_components/jquery-ui/jquery-ui.js",
            "bower_components/rangy/rangy-core.js",
            "bower_components/rangy/rangy-classapplier.js",
            "bower_components/rangy/rangy-highlighter.js",
            "bower_components/rangy/rangy-selectionsaverestore.js",
            "bower_components/rangy/rangy-serializer.js",
            "bower_components/rangy/rangy-textrange.js",
            "bower_components/angular/angular.js",
            "bower_components/textAngular/dist/textAngular.js",
            "bower_components/textAngular/dist/textAngular-sanitize.js",
            "bower_components/textAngular/dist/textAngularSetup.js",
            "bower_components/KaTeX/dist/katex.min.js",
            "bower_components/angular-bootstrap/ui-bootstrap-tpls.js",
            "bower_components/angular-translate/angular-translate.js",
            "bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js",
            "bower_components/angular-cookies/angular-cookies.js",
            "bower_components/angular-translate-storage-cookie/angular-translate-storage-cookie.js",
            "bower_components/angular-translate-storage-local/angular-translate-storage-local.js",
            "bower_components/angular-translate-handler-log/angular-translate-handler-log.js",
            "bower_components/angular-dynamic-locale/src/tmhDynamicLocale.js",
            "bower_components/angular-tour/dist/angular-tour-tpls.min.js",
            "bower_components/ng-sortable/dist/ng-sortable.js",
            "bower_components/moment/moment.js",
            "bower_components/angular-moment/angular-moment.js",
            "bower_components/KaTeX/dist/contrib/auto-render.min.js",
            'dist/js/main.js',
            'node_modules/angular-mocks/angular-mocks.js',
            'test/unit/**/*.spec.js'
        ],

        browserify: {
            debug: true,
            transform: [
                'babelify',
                'brfs',
                'bulkify'
            ]
        },

        // list of files to exclude
        exclude: ['karma.conf.js'],


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


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


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

        urlRoot: '/__karma__/'
    })
};