128
votes

I am trying to run the default service unit test in my project (Taken from the Angular Seed project on GitHub), but I keep getting the error "module is not defined".

I have read that it could be something to do with the order of the referenced JavaScript files, but I can't seem to get it to work, so hopefully one of you might be able to help.

My configuration for the test looks like this:

basePath = '../';

files = [
'public/javascripts/lib/jquery-1.8.2.js',
'public/javascripts/lib/angular.js',
'public/javascripts/lib/angular-.js',
'public/app.js',
'public/controllers/
.js',
'public/directives.js',
'public/filters.js',
'public/services.js',
JASMINE,
JASMINE_ADAPTER,
'public/javascripts/lib/angular-mocks.js',
'test/unit/*.js' ];

autoWatch = true;

browsers = ['Chrome'];

junitReporter = { outputFile: 'test_out/unit.xml', suite: 'unit' };

The service looks like the following:

angular.module('myApp.services', []).
  value('version', '0.1');

The test looks like this:

'use strict';

describe('service', function() {
  beforeEach(module('myApp.services'));


  describe('version', function() {
    it('should return current version', inject(function(version) {
      expect(version).toEqual('0.1');
    }));
  });
});

And the error when running the test through testacular is this:

ReferenceError: module is not defined

7
can you share your project somewhere? I might be able to help. Did you try to turn on DEBUG level for testacular to see which files are actually loaded based on your configuration? For now the suspicious part is this patter: public/javascripts/lib/angular-.js - what should it match?pkozlowski.opensource
@JohnDoe Thanks that worked. If you add an answer I will mark it as resolved. The reason was that I was following the seed project, which did it that way, and which worked. I don't know if it is because it was an earlier version.Dofs
@Dofs Are "'public/javascripts/lib/angular-.js'," and "'public/controllers/.js'" typos?Ryan O'Neill
@RyanO'Neill sorry, yes this was a typo.Dofs

7 Answers

260
votes

You are missing the angular-mocks.js file.

41
votes

I had the same problem, and I understood why it wasn't working: The jasmine.js javascript must be referenced BEFORE the angular-mocks.js file. Indeed, the angular-mocks.js checks if Jasmine is loaded, and only if it is it will add the module function to the window.

Here is an extract of Angular Mocks code:

(Edit after the few comments about 'hacking' I had below: this is just an extract of the code, this is not something you need to write yourself, it's already there!)

window.jasmine && (function(window) {

[...]

  window.module = angular.mock.module = function() {
    var moduleFns = Array.prototype.slice.call(arguments, 0);
    return isSpecRunning() ? workFn() : workFn;
    /////////////////////
    [...]
  };

In a nutshell: Just reference your jasmine.js before angular-mocks.js and off you go.

36
votes

The window.module function comes in angular-mocks.js and is a shorthand for angular.mock.module. As mentioned in the docs, the module function only works with Jasmine.

Using Testacular, the following example configuration file will load angular-mocks.js.

/** example testacular.conf.js */

basePath = '../';
files = [
  JASMINE,
  JASMINE_ADAPTER,
  'path/to/angular.js',
  'path/to/angular-mocks.js',   // for angular.mock.module and inject.
  'src/js/**/*.js',             // application sources
  'test/unit/**/*.spec.js'      // specs
];
autoWatch = true;
browsers = ['Chrome'];

And, as suggested elsewhere, you can run Testacular with debug logging to see what scripts are loaded (you can also see the same in the inspector):

testacular --log-level debug start config/testacular.conf.js

The angular.mock.inject docs include a pretty complete example.

11
votes

We use 'module' without 'angular' in our unit tests and it works fine.

CoffeeScript:

describe 'DiscussionServicesSpec', ->
    beforeEach module 'DiscussionServices'
    beforeEach inject ... etc.

which compiles to

JavaScript:

describe('DiscussionServices', function() {
    beforeEach(module('DiscussionServices'));
    beforeEach(inject(function ... etc.

The only time I see something like the error you described is if in the testacular.conf.js file the angular-mocks.js file is not listed in the files section before the specs trying to use 'module'. If I put it after my tests in the 'files' list I get

ReferenceError: Can't find variable: module

(Our tests are being run through PhantomJS)

3
votes

I had included angular-mocks.js in my karma config, but was still getting the error. It turns out the order is important in the files array. (duh) Just like in the head of an html doc, if a script calls angular before it's defined, and error occurs. So I just had to include my app.js after angular.js and angular-mocks.js.

0
votes

If you're using Yeoman and its angular-generator, you probably get this error. Especially when you do the Tutorial ( ._.)
I fixed it, by copying the angular-mocks.js file, from the bower_components/angular-mocks dir to the test/mock dir. Of course you have to be sure, that your karma.conf.js file is configured correctly.
Greetings!

0
votes

I had this same issue when I was doing something like var module = angular.module('my',[]). I needed to make sure it was surrounded by IIFE