0

I'm using Angular-Bootstrap modals and have a basic controller like so:

.controller('DashboardHelpController', ['$scope', '$uibModal', function ($scope, $uibModal) {

    var dhc = this;

    dhc.open = function (size, resource) {
        var modalInstance = $uibModal.open({
            templateUrl: 'resourcePlayModal.html',
            controller: 'ModalInstanceCtrl as mic',
            size: size,
            resolve: {
                resource: function () {
                    return resource;
                }
            }
        });
    };
}])

It calls a standard modal instance controller:

.controller('ModalInstanceCtrl', ['$uibModalInstance', 'resource', function ($uibModalInstance, resource) {
    this.resource = resource;

    this.cancel = function () {
        $uibModalInstance.dismiss();
    };
}])

And here's my unit test, modeled after another SO post:

describe('Modal controller', function () {
    var modalCtrl, scope, modalInstance;

    beforeEach(module('MyApp'));

    // initialize the controller and a mock scope
    beforeEach(inject(function ($controller, $rootScope) {
        scope = $rootScope.$new();

        modalInstance = {
            // create a mock object using spies
            close: jasmine.createSpy('modalInstance.close'),
            dismiss: jasmine.createSpy('modalInstance.dismiss'),
            result: {
                then: jasmine.createSpy('modalInstance.result.then')
            }
        };

        modalCtrl = $controller('DashboardHelpController', {
            $scope: scope,
            $uibModalInstance: modalInstance
        });
    }));

    it('should instantiate the mock controller', function () {
        expect(modalCtrl).not.toBeUndefined();
    });

    it('should have called the modal dismiss function', function () {
        scope.cancel;
        expect(modalInstance.dismiss).toHaveBeenCalled();
    });
});

The problem is that the cancel function isn't found on the scope:

Expected spy modalInstance.dismiss to have been called with [ 'cancel' ] but it was never called.

UPDATE: I had originally attempted to call cancel as a function:

it('should have called the modal dismiss function', function () {
    scope.cancel();
    expect(modalInstance.dismiss).toHaveBeenCalled();
});

That didn't work. My code above is an attempt to solve the original problem:

TypeError: scope.cancel is not a function

Things are complicated a bit my my use of the Controller as syntax, but this should work. Thanks for any help.

Community
  • 1
  • 1
isherwood
  • 58,414
  • 16
  • 114
  • 157
  • cancel is a function. `scope.cancel` doesn't call it. Even if you had parentheses, cancel() is a function of ModalInstanceCtrl, that you never instantiate anywhere, and not a funtion of $scope. – JB Nizet Jan 22 '16 at 20:08
  • Right you are. Please see my update. `cancel()` is a function of the instance controller. My problem lies with my inability to track scope through the various controllers and functions. – isherwood Jan 22 '16 at 20:11
  • Not sure why you care about the scope, since none of the 2 controllers use it. Why do you try to test cancel(), which is a function of ModalInstanceCtrl, inside a test of DashboardHelpController? – JB Nizet Jan 22 '16 at 20:13
  • By scope I mean the object that's being mocked. Good question, though. I may have let myself get twisted up a bit with my various attempts at testing the modal. How would you test the modal's functionality? I have no Accept/Decline type functions, just a video playback modal. – isherwood Jan 22 '16 at 20:17
  • There isn't much to test here. You should first avoid using undefined global variables like `resource`. The only things you can test is that dhc.open call $uibModal.open() with the expected arguments, and that ModalInstanceCtrl.cancel() calls dismiss() on the $uibModalInstance. But such unit tests don't really have much value. – JB Nizet Jan 22 '16 at 20:23
  • `resource` is passed in from the view model. Is there no value in verifying that the modal library is present and functional? – isherwood Jan 22 '16 at 20:45

1 Answers1

2

scope.cancel is a function, but you aren't invoking it as such.

it('should have called the modal dismiss function', function () {
    scope.cancel();
    expect(modalInstance.dismiss).toHaveBeenCalledWith();
});

In addition, scope.cancel() is never defined on DashboardHelpController, even though that is the scope that you create for your tests. You need to create a method on your dashboard controller that calls through to the modal instance close method after the modalInstance has been created.

var modalInstance = $uibModal.open({
...
dhc.cancel = function ()  {
    modalInstance.dismiss();
}
David L
  • 32,885
  • 8
  • 62
  • 93