Search code examples
karma-runnerbrowserifykarma-jasmineangular-mock

browserify/karma/angular.js "TypeError: Cannot read property '$injector' of null" when second test uses "angular.mock.inject", "currentSpec" is null


I have an Angular.js app and am experimenting with using it with Browserify. The app works, but I want to run tests too, I have two jasmine tests that I run with karma. I user browserify to give me access to angular.js and angular-mocks.js and other test fixtures within the tests.

Versions are:-

"angular": "^1.4.0",
"angular-mocks": "^1.4.0",
"browserify": "^10.2.3",
"karma": "^0.12.32",
"karma-browserify": "^4.2.1",
"karma-chrome-launcher": "^0.1.12",
"karma-coffee-preprocessor": "^0.2.1",
"karma-jasmine": "^0.3.5",
"karma-phantomjs-launcher": "^0.1.4",

If I run the tests individually (by commenting one or the other from the karma.conf file) they both work OK. (yey!)

But if I run them both I get this error

    TypeError: Cannot read property '$injector' of null
    at Object.workFn (/tmp/3efdb16f2047e981872d82fd8db9c0a8.browserify:2272:22 <- node_modules/angular-mocks/angular-mocks.js:2271:0)

looking at line 2271 of the angular.mocks.js It reads

if (currentSpec.$injector) {

So clearly currentSpec is somehow now null.

I have isolated the problem to when I call "angular.mock.inject" in the second test.

beforeEach(angular.mock.inject(function (_GridUtilService_) {
  gridUtilService = _GridUtilService_;
}));

If I comment this out it works, but obviously I can't then run a test n my gridUtilService.

Does anyone know how to run two (or more :-) angular-mock jasmine tests with karma and browserify?

below are my tests, karma.conf file. the Angular services work when deployed but for this purpose they can simply be dumb services that do nothing.

karma.conf:-

// Karma configuration

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

    // list of files / patterns to load in the browser
    files: [
      'src/main/assets/js/**/*.js',
//      'src/test/**/*.js'
      'src/test/services/SettingUtil*.js',
      'src/test/services/GridUtil*.js'
    ],


    // list of files to exclude
    exclude: [
        'src/main/assets/js/**/app-config.js'
    ],


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

    browserify: {
        debug: true,
        extensions: ['.js', '.coffee', '.hbs']
    },

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

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

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

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

src/test/services/SettingUtilServiceTest.js:

'use strict';

describe("SettingUtilServiceTest.", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });

  require('angular');

  require('angular-mocks'); 

  // can't do below see error at https://github.com/xdissent/karma-browserify/issues/10
  //beforeEach(module('dpServices'));

  //so need todo this
  beforeEach(angular.mock.module('dpServices'));

  var fixtures = require('./serviceFixtures.js');

  var sus = fixtures.settingUtilServiceTestFixtures;
  var ts1 = sus.tablesetting1;
  var ts2 = sus.tablesetting2;

  var settingUtilService;

  beforeEach(angular.mock.inject(function (_settingUtilService_) {
      settingUtilService = _settingUtilService_;
    }));

    it('should return an object containing mins and maxs from function minMaxes()', function() {
        expect(ts1).toBeDefined();
        expect(ts2).toBeDefined();
        var minMaxs = settingUtilService.minMaxs(ts1);
        var mins = minMaxs.mins;
        expect(mins).toBeDefined();
        var maxs = minMaxs.maxs;
        expect(maxs).toBeDefined();
    });

});

src/test/services/GridUtilServiceTest.js:

'use strict';

describe("GridUtilServiceTest.", function() {
  it("is a set of tests to test GridUtilService.", function() {
    expect(true).toBe(true);
  });

  require('angular');

  require('angular-mocks');

  // can't do below see error at https://github.com/xdissent/karma-browserify/issues/10
//  beforeEach(module('dpServices'));

  //so need todo this
  beforeEach(angular.mock.module('dpServices'));

  var fixtures = require('./gridFixtures.js');

  var gridFix = fixtures.gridUtilServiceTestFixtures;

  var ts1 = gridFix.tablesetting1;
  var ts2 = gridFix.tablesetting2;
  var ts3 = gridFix.tablesetting3;

  var gridUtilService;

  beforeEach(angular.mock.inject(function (_GridUtilService_) {
    gridUtilService = _GridUtilService_;
  }));

  it('should return an object containing mins and maxs from function minMaxes()', function() {
        expect(ts1).toBeDefined();
        expect(ts2).toBeDefined();
        expect(ts3).toBeDefined();
    });

});

If you need access to the angular setup I can provide it (split into multiple files using browserify's require() function and built with gulp... but as I say the app runs ok and the tests only fail when there are two tests, so I think the issue is with karma-jasmine and angular-mocks or overwriting the currentSpec variable.

If anyone knows how to split my angular tests into multiple tests (I don't want a monolithic angular test) without the error message all help is appreciated. thanks.


Solution

  • I had the same issue, the issue for me was because I was requiring angular and angular-mocks exactly as you were inside each describe block. I moved the two lines

    require('angular');
    require('angular-mocks');
    

    above the describe blocks and made sure to only call them once.