4

The scenario is I have a ChildCtrl controller that inherits from BaseCtrl following this inheritance pattern:

angular.module('my-module', [])
    .controller('BaseCtrl', function ($scope, frobnicate) {
        console.log('BaseCtrl instantiated');

        $scope.foo = frobnicate();

        // do a bunch of stuff
    })

    .controller('ChildCtrl', function ($controller, $scope) {
        $controller('BaseCtrl', {
            $scope: $scope,
            frobnicate: function () {
                return 123;
            }
        });
    });

Assuming BaseCtrl does a bunch of stuff and is already well tested, I want to test that ChildCtrl instantiates BaseCtrl with certain arguments. My initial thought was something along these lines:

describe("ChildCtrl", function () {
    var BaseCtrl;

    beforeEach(module('my-module'));

    beforeEach(module(function($provide) {
        BaseCtrl = jasmine.createSpy();
        $provide.value('BaseCtrl', BaseCtrl);
    }));

    it("inherits from BaseCtrl", inject(function ($controller, $rootScope) {
        $controller('ChildCtrl', { $scope: $rootScope.$new() });

        expect(BaseCtrl).toHaveBeenCalled();
    }));
});

However when I run the test the spy is never called and the console shows "BaseCtrl instantiated", indicating that $controller is using the actual controller instead of the instance I am providing with $provide.value().

What's the best way to test this?

1 Answer 1

5

So it looks like $controller doesn't search for controllers by name in the $provide.value() namespace. Instead you have to use the $controllerProvider.register() method, which is only accessible from the module.config() block. Fortunately it looks like there's a hook we can use to get access to $controllerProvider on the module under test.

The updated test code looks like:

describe("ChildCtrl", function () {
    var BaseCtrl;

    beforeEach(module('my-module', function ($controllerProvider) {
        BaseCtrl = jasmine.createSpy();
        BaseCtrl.$inject = ['$scope', 'frobnicate'];

        $controllerProvider.register('BaseCtrl', BaseCtrl);
    }));

    beforeEach(inject(function ($controller, $rootScope) {
        $controller('ChildCtrl', { $scope: $rootScope.$new() });
    }));

    it("inherits from BaseCtrl", inject(function ($controller, $rootScope) {
        expect(BaseCtrl).toHaveBeenCalled();
    }));

    it("passes frobnicate() function to BaseCtrl that returns 123", function () {
        var args = BaseCtrl.calls.argsFor(0);
        var frobnicate = args[1];

        expect(frobnicate()).toEqual(123);
    });
});
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.