I am trying to setup unit testing for a JavaScript plugin that is based on AngularJS. The plugin is bundled with Browserify via Gulp. It depends on external libraries that are injected with wiredep
and gulp-inject
from the bower_components
folder. This is all working beautifully in the generated bundle, but if I try to run a Karma unit test via gulp, I get the following error:
Uncaught TypeError: angular.module is not a function at /tmp/94dbea5947f4758ab1ee6935e2f4b3f1.browserify:365 <- app/js/services/index.js:9:0
In this file, angular
is loaded with var angular = require('angular');
, and a console.log(angular)
gives an empty object.
My 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);
};
All main application files are located under app/
, bower files in bower_components/
, node modules in node_modules/
and test specs in test/unit/
.
It is based on this boilerplate: https://github.com/jakemmarsh/angularjs-gulp-browserify-boilerplate.
The error occurs just after Karma has launched Chrome, but before any unit test are executed (I checked with console.log
in the unit test).
Any help would be greatly appreciated.
Finally solved it.
unit.js
(gulp unit task):
'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();
});
The key here was to run browserify before the unit tests are started. 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__/'
})
};