如何让 Browserfied AngularJS 应用程序与 Karma 一起工作?

How do I get a Browserfied AngularJS application working with Karma?

我在使用 Karma 和 Jasmine 进行浏览器化 AngularJS 应用程序 运行 测试时遇到问题。我使用 Gulp 构建应用程序,但它目前未参与测试(应该是吗?)。

我收到这个错误,我想使用 PhantomJS

Chrome 44.0.2403 (Linux 0.0.0) LOG: 'WARNING: Tried to load angular more than once.'

Chrome 44.0.2403 (Linux 0.0.0) ERROR
Uncaught ReferenceError: require is not defined
   at /home/xenoterracide/IdeaProjects/mmp-player/app/js/app.js:3

这是我的gulpfile.js,或多或少有效

'use strict';
var gulp = require( 'gulp' ),
    sourcemaps = require( 'gulp-sourcemaps' ),
    concat = require( 'gulp-concat' ),
    browserSync = require( 'browser-sync' ),
    CacheBuster = require( 'gulp-cachebust' )
    ;

var reload = browserSync.reload;
var cachebust = new CacheBuster();

gulp.task( 'build', [ 'build-css', 'build-js' ], function() {
    return gulp.src( 'app/index.html' )
        .pipe( cachebust.references() )
        .pipe( gulp.dest( 'dist' ) )
        .pipe( reload( { stream: true } ) );
} );

gulp.task( 'serve', [ 'build' ], function() {
    browserSync( {
        server: {
            baseDir: 'dist'
        }
    } );

    gulp.watch( [ '**/*.html', 'css/**/*.*css', 'js/**/*.js' ], { cwd: 'app' }, [ 'build' ] );
} );

gulp.task( 'default', function() {
    // place code for your default task here
} );

gulp.task( 'build-config', function() {
    var nconf = require( 'nconf' ),
        rename = require( 'gulp-rename' ),
        ngConstant = require( 'gulp-ng-constant' );

    nconf.use( 'memory' ).argv()
        .env( {
            separator: '_',
            match: /^MMP/
        } )
        .defaults( {
            musicDbSocketUri: 'http://localhost:8080/socket'
        } );

    ngConstant( {
        name: 'mmpPlayer.config',
        constants: nconf.get(),
        stream: true
    } ).pipe( rename( "config.js" ) )
        .pipe( gulp.dest( 'app/generated' ) );
} );

gulp.task( 'build-css', [ 'clean' ], function() {
    var sass = require( 'gulp-sass' );

    return gulp.src(
        [
            'node_modules/angular-material/angular-material.css',
            'app/css/*.*css'
        ] )
        .pipe( sourcemaps.init() )
        .pipe( sass() )
        .pipe( sourcemaps.write( './' ) )
        .pipe( concat( 'app.css' ) )
        .pipe( cachebust.resources() )
        .pipe( gulp.dest( 'dist/css' ) );
} );

gulp.task( 'build-js', [ 'clean', 'build-config', 'build-template-cache' ], function() {
    var browserify = require( 'browserify' ),
        ngAnnotate = require( 'browserify-ngannotate' ),
        gutil = require( 'gulp-util' ),
        source = require( 'vinyl-source-stream' ),
        buffer = require( 'vinyl-buffer' );

    var b = browserify( {
        basedir: 'app/js',
        entries: 'app.js',
        debug: true,
        paths: [ '../generated', 'config', 'controller', 'service', 'factory' ],
        transform: [ ngAnnotate ]
    } );

    return b.bundle()
        .on( 'error', gutil.log )
        .pipe( source( 'js/app.js' ) )
        .pipe( buffer() )
        .pipe( cachebust.resources() )
        .pipe( sourcemaps.init( { loadMaps: true } ) )
        .pipe( sourcemaps.write( './' ) )
        .pipe( gulp.dest( 'dist' ) );
} );

gulp.task( 'build-template-cache', function() {

    var ngHtml2Js = require( 'gulp-ng-html2js' );

    return gulp.src( 'app/partials/*.html' )
        .pipe( ngHtml2Js( {
            moduleName: 'mmpPlayer',
            prefix: 'partials/'
        } ) )
        .pipe( concat( 'partials.js' ) )
        .pipe( gulp.dest( 'app/generated' ) );
} );

gulp.task( 'clean', function( cb ) {
    var del = require( 'del' );

    del( [ 'dist' ], cb )
} );

这是我的 karma.conf.js

'use strict';
module.exports = function( config ) {
    config.set( {

        basePath: './',
        logLevel: 'LOG_DEBUG',

        browserify: {
            basedir: 'app/js',
            entries: 'app.js',
            debug: true,
            paths: [ '../generated', 'config', 'controller', 'service', 'factory' ]
        },

        files: [
            'node_modules/angular/angular.js',
            'node_modules/angular-mocks/angular-mocks.js',
            'app/js/**/*.js',
            'test/**/*.js'
        ],

        autoWatch: true,

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

        browsers: [],

        plugins: [
            'karma-jasmine',
            'karma-browserify'
        ],

        phantomjsLauncher: {
            // Have phantomjs exit if a ResourceError is encountered (useful if karma exits without killing phantom)
            exitOnResourceError: true
        }
    } );
};

我写了这个虚拟服务

'use strict';
require( 'angular' ).module( 'mmpPlayer' ).factory( 'testF', function( ) {
    return "hello";
});

和相应的测试

describe('testF', function () {

var testF;
beforeEach(module('mmpPlayer'));
beforeEach(inject(function (_testF_) {
  testF = _testF_;
}));

describe('Constructor', function () {

  it('assigns a name', function () {
    expect(testF).toBe('hello');
  });

});

});

关于所有这些工具,我仍在学习很多,但我并不觉得我真的了解它们是如何工作的(尽管我非常熟悉 Java 和 Perl 的类似工具) .

我希望使用 PhantomJs 通过此测试和更多测试(对于 运行 CI),我需要进行哪些更改才能实现?

不得不更新我的 karma 配置,很大程度上删除了相对路径并让它从存储库根目录中查看内容。

'use strict';
module.exports = function( config ) {
    config.set( {

        basePath: '',
        logLevel: 'LOG_DEBUG',

        preprocessors: {
            'app/js/app.js': [ 'browserify' ],
            'app/js/**/*.js': [ 'browserify' ]
        },

        browserify: {
            basedir: '',
            debug: true,
            paths: [ 'app/generated', 'app/js/config', 'app/js/controller', 'app/js/service', 'app/js/factory' ]
        },

        files: [
            'app/js/app.js',
            'node_modules/angular-mocks/angular-mocks.js',
            'test/**/*.js'
        ],

        autoWatch: true,

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

        browsers: [ 'Chrome' ],

        plugins: [
            'karma-jasmine',
            'karma-browserify',
            'karma-chrome-launcher'
        ],

        reporters: [ 'dots' ],

        phantomjsLauncher: {
            // Have phantomjs exit if a ResourceError is encountered (useful if karma exits without killing phantom)
            exitOnResourceError: true
        }
    } );
};