128

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

Dofs
  • 17,737
  • 28
  • 75
  • 123
  • 2
    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 Nov 13 '12 at 21:54
  • @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 Nov 14 '12 at 20:14
  • @Dofs Are "'public/javascripts/lib/angular-.js'," and "'public/controllers/.js'" typos? – Ryan O'Neill Nov 15 '12 at 18:44
  • @RyanO'Neill sorry, yes this was a typo. – Dofs May 15 '13 at 20:15

7 Answers7

260

You are missing the angular-mocks.js file.

John Doe
  • 4,574
  • 2
  • 26
  • 30
  • 8
    Note that `angular.module` and `angular.mock.module` are **not** the same. The `window.module` function is an alias for `angular.mock.module`. See [this answer](http://stackoverflow.com/questions/13334749/testing-service-in-angular-returns-module-is-not-defined/14167563#14167563) for more. – Tim Schaub Jan 05 '13 at 01:41
  • As previous comment says, angular.module is not an alias for angular.mock.module. – Filippo De Luca Mar 19 '13 at 21:06
  • I'm using `requirejs`. I was experience random failing of tests until I added jasmine-boot as a dependency to angular-mocks. To be clear, I _now_ have: `shim: {"angular-mocks": {deps:["angular", "boot"], exports: "angular.mock"}}` and everything works swimmingly! (credit to @Antoine Jaussoin for this solution) – Beez Jul 09 '14 at 18:48
  • 8
    This answer would be much more useful if it offered any advice about how to provide said file. I needed to install Bower, then NgMocks. – isherwood Aug 26 '15 at 16:42
  • 5
    The answer provides only part of the solution. This is actually a comment and not an explanation. Some of the answers below are much more detailed. – Gerome Bochmann Jan 18 '16 at 14:54
  • 2
    For the beginners, you need to add a reference to `angular-mocks` in the `karma.conf.js` file, and run the tests through Karma, not Jasmine. This way, when Karma is run, it picks up the `angular-mocks` extensions and incorporates them into the environment. – Luke Sep 10 '18 at 13:35
41

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.

Antoine Jaussoin
  • 5,002
  • 4
  • 28
  • 39
  • This can also be resolved by making sure the jasmine javascript files are loaded before angular-mocks. Cleaner solution than making hacky changes to get stuff to work. – foomip May 13 '14 at 11:51
  • @foomip Who suggested making hacky changes? – Stephen May 14 '14 at 18:47
  • You essentially inserted a hack into your app to make sure that things load in the correct fashion - and I didn't mean hack in a bad way (there is nothing wrong with the way you wrote that snippet of code) but what happens when an update to jasmine or something else causes that snippet of your to break or no longer function as expected? It could or couldn't happen, but that is a liability in your code now that could be avoided, don't you think? – foomip May 19 '14 at 08:52
  • @foomip: I'm not sure what you are referring to, but if it's about my code above, this wasn't written by me, I'm merely quoting it to explain the issue. The code is part of angular-mocks. The fix is simply a matter of referencing one file before the other. – Antoine Jaussoin May 22 '14 at 12:02
36

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.

Carl
  • 853
  • 9
  • 23
Tim Schaub
  • 6,722
  • 1
  • 26
  • 17
11

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)

Ryan O'Neill
  • 3,727
  • 22
  • 27
3

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.

Erik
  • 461
  • 1
  • 4
  • 10
0

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!

alxU
  • 93
  • 5
0

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

Jackie
  • 21,969
  • 32
  • 147
  • 289