Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Include dependencies in Karma test file for Angular app?

I am trying to get started with Karma tests, adding them to an existing Angular app.

This is my main app definition file:

angular
  .module('myApp', [
    'ngRoute',
    'moduleAdherence'
  ]);

This is my controller file:

   angular
    .module('moduleAdherence', [])
    .controller('AdherenceCtrl', ['$scope', function ($scope) {
      $scope.awesomeThings = [1,2,3,4];
    }]);

This is my first stab at a file:

describe('Controller: AdherenceCtrl', function () {
  beforeEach(module('myApp'));
  var MainCtrl,
    scope;
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    MainCtrl = $controller('AdherenceCtrl', {
      $scope: scope
    });
  }));
  it('should attach a list of awesomeThings to the scope', function () {
    expect(scope.awesomeThings.length).toBe(4);
  });
});

When I try to run this with grunt test, it fails with the following error:

Uncaught Error: [$injector:nomod] Module 'd3' is not available! 
You either misspelled the module name or forgot to load it. 
If registering a module ensure that you specify the dependencies 
as the second argument.
http://errors.angularjs.org/1.2.0/$injector/nomod?p0=d3
at /Users/me/Dropbox/projects/myapp/app/bower_components/angular/angular.js:1498

I don't understand this, because this controller does not Use D3. I do use D3 elsewhere in the app, in a directive, but I'm not registering it with the module (I use the external D3 file).

Why is Karma noticing D3? Shouldn't it be able to test this controller without D3?

like image 913
Richard Avatar asked Nov 21 '13 21:11

Richard


2 Answers

In karma configuration file (karma.conf.js) you need to define all libraries.

etc.

    // list of files / patterns to load in the browser
    files: [
        'app/lib/angular/angular.js',
        'app/lib/angular-route/angular-route.js',
        'test/lib/angular-mocks.js',
        'app/app.js',
        'app/controllers/*.js',
        'app/services/*.js',
        'app/*',
        'test/spec/**/*.js'
    ],
like image 77
Branislav Djuric Avatar answered Oct 23 '22 07:10

Branislav Djuric


Had a similar problem and my solution (inspired someway by @danba comment) was to load the scripts in the files in the exact same order as they were loaded in the index.html. In my case globbing patterns like app/scripts/**/*.js were causing trouble to karma which constantly threw errors.

Maybe not the most elegant solution to copy all the scripts definitions but worked in the end so my test could finally get back running. Hope it helps.

EDIT: Editing this because today I probably (and hopefully) got the hang of what was going wrong here. So it seems that Karma does not like globbing patterns when the same module is defined in one file and used in many different files. Let's say that your folder structure is like this:

risky folder structure

Suppose that in AuthService.js you have your module definition for all your services in that folder, so that that file starts with:

angular.module('myApp.services', [
  'myApp.urls',
  'ngCookies'
])

Then in all the other files you're just attaching other services to that same module. In the picture tokenService.js would start with:

angular.module('myApp.services');

If everything stays this way everything will probably work. But if by any chance I define the module the other way round, so the module definition is not anymore in the first file of that folder but on another that Karma reads after AuthService then it will throw an error and refuse to complete the tests.

Solution 1

A solution might be to put the module definition in its own file, starting with an underscore. Finally, let all the siblings files depend on that one(s). So the above folder structure should be:

safer folder structure

Solution 2

Another - probably better - solution is to mark the files where the modules are defined with a common suffix/extension for example service.module.js while the files that depend on it could be named normally like authService.js, tokenService.js. The Karma configuration at that point will become something like:

// list of files / patterns to load in the browser
files: [
    'app/lib/angular/angular.js',
    'test/lib/angular-mocks.js',
    'app/app.js',
    'app/**/*.module.js', // <-- first the module definitions...
    'app/**/*.js', // <-- ..then all the other files
    'test/spec/**/*.js'
],

This way karma will load the modules definitions first and then those file that depend on them.

like image 34
Aurelio Avatar answered Oct 23 '22 07:10

Aurelio