46

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?

5
  • Where is module myApp defined? And MainCtrl? Commented Nov 21, 2013 at 22:03
  • Sorry - typos when renaming for public consumption, now fixed. Problem is still the same. Commented Nov 21, 2013 at 22:14
  • 4
    Figured it out - I had to load the dependencies explicitly in karma.config.js, in the files section. Commented Nov 21, 2013 at 22:33
  • @Richard excellent, please add it as a solution! Commented Jan 23, 2014 at 9:16
  • Use karma-angular-filesort Commented Feb 17, 2016 at 15:37

6 Answers 6

52

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'
    ],
Sign up to request clarification or add additional context in comments.

1 Comment

the key here is that app/app.js - where the angular module is defined - occurs before all the js files that reference the angular module
34

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.

6 Comments

I have the exact same problem. I'm looking for better solution.
@GordonSun check my update, hopefully it will work for your use case, it might be interesting to see if this actually solves the problem for other people.
i have this same problem. I like #2 though...seems like a good compromise
Thank you. You made my day. Experimentally come to solution #2, but without "first the module definitions...".
The second solution worked for me, thank you! Been at this for over a week!
|
1

I also had the same issue, in my case problem occured because there were several files per module which is a bad practice since we can point to not initialized module. Solved this by including just one file per module.

2 Comments

Had the same problem, solved it by adding scripts in order 'app/scripts/app.js', 'app/scripts/**/*Module.js', 'app/scripts/*.js', 'app/scripts/**/*.js' so that all files that include module declarations are included before all files that may require the modules.
What exactly do you mean by "we had several files per module"?
1

Always load the non minified version of angular into karma. it will display errors and help you better to find out what to change. In your case, it's the order of the files being loaded by karma.

Comments

1

Check your index.html that you don't include something by a script tag like.

 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5angular-resource.js"

All your Javascript file need to be in your karma.config.js

Comments

1

Here's a simple solution that worked for me, based on above Solution #1 by @Nobita, AND @danba's comment.

In karma.conf.js, explicitly load the prerequisite file above the pattern that pulls in the rest:

files: [
    ...
    'app/module.js',
    'app/*.js'
]

Karma does not seem to mind that the pattern also matches 'module.js'.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.