AngularJS Change Constant Value that gets passed to Config for Unit Test

All we need is an easy explanation of the problem, so here it is.

Is there anyway to change the constant value that gets sent to the config function of the module for a Unit Test?

I have the following (fiddle here):

//--- CODE --------------------------
var module = angular.module("myApp", []);
module.constant("myConstant", "foo");
module.provider("awesomeStuff", function () {
    var value;

    this.setValue = function (val) {
        value = val;
    };

    this.$get = function () {
        return {
            myValue: value
        };
    };
});
module.config(function (myConstant, awesomeStuffProvider) {
    //want to mock myConstant
    awesomeStuffProvider.setValue(myConstant);
});



//--- SPECS -------------------------
describe("foo", function() {
    beforeEach(angular.mock.module("myApp", function ($provide) {
        //Attempt to override the myConstant value that gets passed to config
        $provide.constant("myConstant", "bar");
    }));

  it("has a value of bar", inject(function(awesomeStuff, $injector) {
    expect($injector.get("myConstant")).toBe("bar");
    expect(awesomeStuff.myValue).toBe("bar");
  }));
});

I know this is a trivial example, but I want to know if its possible to get a different constant to be injected into the config… I know it is possible to get a reference to the provider and call setValue function from unit test (i.e. configuring provider via this SO post), but this is not what I’m looking for.

Thanks for any help.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Consider the following:

beforeEach(angular.mock.module("myApp"));

This will load the module and execute the registered config functions.

In your case you have:

beforeEach(angular.mock.module("myApp", function ($provide) {
    //Attempt to override the myConstant value that gets passed to config
    $provide.constant("myConstant", "bar");
}));

What happens now is basically the same as if you had the following:

var module = angular.module("myApp", []);

... Constant and Provider omitted ...

module.config(function(myConstant, awesomeStuffProvider) {

  awesomeStuffProvider.setValue(myConstant);
});

module.config(function($provide) {

  $provide.constant("myConstant", "bar");
});

As the registered config functions will be executed in order of registration this will not have the desired result.

If you need to mock a constant before it’s used in any config function I would recommend to put it in a separate module.

Depending on your use case, you can now either:

  1. Create two versions of this module – one for production and one for the tests
  2. Create only the real version and mock the constant in the test

The second case would look something like this:

App:

angular.module("configuration", []).constant("myConstant", "foo");

var module = angular.module("myApp", ["configuration"]);

module.provider("awesomeStuff", function () {
    var value;

    this.setValue = function (val) {
        value = val;
    };

    this.$get = function () {
        return {
            myValue: value
        };
    };
});

module.config(function (myConstant, awesomeStuffProvider) {
    awesomeStuffProvider.setValue(myConstant);
});

Test:

describe("foo", function () {

    beforeEach(function () {

        angular.mock.module("configuration", function ($provide) {
            $provide.constant("myConstant", "bar");
        });

        angular.mock.module("myApp", function () {
            // Something else
        });
    });

    it("has a value of bar", inject(function (awesomeStuff, $injector) {
        expect($injector.get("myConstant")).toBe("bar");
        expect(awesomeStuff.myValue).toBe("bar");
    }));
});

JSFiddle: http://jsfiddle.net/f0nmbv3c/

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply