Source: test.js

'use strict';

module.exports = function(gulp, $, config, _) {
    /**
     * Runs the tests once and exits.
     *
     * Possible browsers are Chrome, Firefox and IE and are specified via the karma configuration file.
     *
     * @public
     * @namespace tests
     */
    gulp.task('test', function (done) {
        runKarma(true, done);
    });

    /**
     * Starts the test server without exiting for continuous development.
     *
     * Used internally by {@link watch}.
     *
     * @private
     * @name test:watch
     * @memberof tests
     */
    gulp.task('test:watch', function (done) {
        runKarma(false, done);
    });

    /**
     * Runs the tests on an existing server.
     *
     * Used internally by {@link watch}.
     *
     * @private
     * @name test:run
     * @memberof tests
     */
    gulp.task('test:run', function (done) {
        $.karma.runner.run(undefined, function () {
            done();
        });
    });

    /**
     * Runs the tests once with additional reporting.
     *
     * Skippable with the `-st` switch.
     *
     * JUnit and coverage reporters are used to allow postprocessing by Jenkins and Sonar.
     * The default format of the coverage report is LCOV.
     *
     * HTML files are preprocessed to JavaScript in order to load them once and for all with `beforeEach(module(moduleName.templates));`.
     *
     * Used internally by {@link build}.
     *
     * @private
     * @name test:build
     * @memberof tests
     */
    gulp.task('test:build', function (done) {
        if (config.args.st) {
            $.util.log('Skipping \'test:build\'');
            done();
        } else {
            return runKarma(true, done, true);
        }
    });


    function runKarma(once, done, build) {
        if (!config.karma.deps) {
            $.util.log('No Karma dependencies found, are you sure?');
        }

        // Basic defaults for karma
        var defaults = getDefaults(once, build)
        // Defaults overwritten by manually specified options in the project's karma file.
        var options = _.defaultsDeep(config.karma, defaults);
        // Allow for different browsers in production (CI) vs. development.
        options.browsers = config.isProduction ?
            _.get(config.karma.browsers, 'production', config.consts.karma.browsers.production) :
            _.get(config.karma.browsers, 'development', config.consts.karma.browsers.development);

        if (once) {
            new $.karma.Server(options, done).start();
        } else {
            // Start a new background server and wait for test:run
            background(options);
        }
    }

    function getDefaults(once, build) {
        var defaults = {
            // Files required to run tests successfully, mind the order.
            files: _.union(
                config.karma.deps,
                config.paths.tests,
                config.paths.app.scripts,
                config.paths.app.partials
            ),
            failOnEmptyTestSuite: false,
            singleRun: once,
            frameworks: ['mocha'],
            reporters: ['mocha'],
            // Preprocessing of HTML files to utilize $templateCache in tests.
            preprocessors: {
                '**/*.html': ['ng-html2js']
            },
            mochaReporter: {
                output: 'minimal',
                showDiff: true
            },
            ngHtml2JsPreprocessor: {
                stripPrefix: config.paths.base,
                // The partials are available as Angular module with the name of moduleName.consts.templateSuffix.
                moduleName: config.moduleName + config.consts.templateSuffix
            }
        };

        if (build) {
            // JUnit reporter for postprocessing by Jenkins to fail build if tests fail.
            defaults.reporters.push('junit');
            // Coverage reporter for postprocessing by Sonar.
            defaults.reporters.push('coverage');

            defaults.junitReporter = {
                outputFile: config.paths.build.reports.tests,
                useBrowserName: false
            };
            defaults.coverageReporter = {
                type: 'lcov',
                dir: $.path.join(config.paths.build.reports.coverage),
                subdir: '.'
            };

            defaults.preprocessors[config.paths.app.scripts] = ['coverage'];
        }
        return defaults;
    }

    function background (options) {
        var backgroundProcess = $.spawn('node', [
            $.path.join(__dirname, 'util', 'karma.js'),
            JSON.stringify(options)
        ]);
        process.on('exit', function () {
            backgroundProcess.kill();
        });
    }
};