Loading angular-mocks.js as a mock module – Angular integration tests

Reason

To make use of ngMockE2E, or more specifically $httpBackend, in integration tests sporting Protractor, Selenium and Jasmine, the documentation suggests including a reference to angular-mocks.js in a script-tag.

Doing so clutters production code with references to test frameworks, which is a big no-no in my book. Hence we’ll load the angular-mocks.js API as a mock module instead using Protractor’s own API.

Pros:

  • No need to modify production code.
  • Load angular mocks only for specific specs/scenarios easily.

Cons:

  • None that I know of.

Code

The following snippet just reads the contents of the angular-mocks.js file and exposes it via the mock field of the exported object. Placing this in a separate file makes it easy to reuse across specs.

// File: "angularMocks.module.js"
module.exports = {
    mock: getScript()
};

function getScript() {
    var path = require("path"),
        fs = require("fs"),
        angularMocksDir = path.dirname(require.resolve("angular-mocks")),
        angularMocksFilePath = path.join(angularMocksDir, "angular-mocks.js"),
        script = fs.readFileSync(angularMocksFilePath).toString();
    return script;
}

Example

Now that the mock script is easily available it can be sent to the “browser under test” using browser.addMockModule(“<module name>”, <payload>) in a beforeEach. If you’re certain that you need the $httpBackend mock in all your specs you could opt to load it in a beforeAll function instead, and move the browser.clearMockModules() to a afterAll function.

To make the application we’re testing load ngMockE2E we need an intermediary module which depends on both our “main app module” and ngMockE2E as per the installation instructions.

// File: "WeekSchedule.controller.spec.js"
describe("Controller: WeekSchedule", function () {
    beforeEach(function () {
        // Load angular-mocks.js into the browser.
        var angularMocksScript = require("./path/to/file/angularMocks.module.js").mock;
        browser.addMockModule("ngMockE2E", angularMocksScript);

        // Load our "trigger module", which depends on both our app and ngMockE2E, into the browser.
        browser.addMockModule("SomeNameThatsNotInUse", mockModuleLoader);
    });

    afterEach(function(){
        // Remove the mock modules again as this isn't done automatically.
        browser.clearMockModules();        
    });

    function mockModuleLoader() {
        angular.module("SomeNameThatsNotInUse", ["WorkSchedule", "ngMockE2E"])
            .run(function ($httpBackend) {
                // Define mock logic here:

                // E.g. ".../WeekSchedule/2015-W35"
                $httpBackend.whenGET(/\/api\/v1\/WeekSchedule\/\d{4}-W\d{2}/).respond(200, [{message:"Hello World!"}]);

                // Pass through all other requests, throw an error or whatever fits the spec.
                $httpBackend.whenGET(/.*/).passThrough();
            });
    }

    it("should fetch data from the backend", function () {
      // [...]
    });
})

2 thoughts on “Loading angular-mocks.js as a mock module – Angular integration tests

  1. Thank you!!! Was looking for a way to solve exactly these issues:
    – No need to modify production code.
    – Load angular mocks only for some specific specs/scenarios.
    Additional notes for those who might come to this page:
    If you get an error “unknown error: [$injector:strictdi] function($httpBackend) is not using explicit annotation and cannot be invoked in strict mode”, you need just a small modification:
    change
    .run(function ($httpBackend) { … })
    to:
    .run([‘$httpBackend’, function ($httpBackend) { … }])
    Or use alternative way from this post:
    http://stackoverflow.com/questions/31983135/httpbackend-explicit-annotation-for-angular-app-in-strict-mode

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s