I am writing a unit test for a controller that runs $modal and uses the promise returned to execute some logic. I can check the parent controller that runs $ modal, but I canβt understand for life how to mock a successful promise.
I tried several ways, including using $q and $scope.$apply() , to force the resolution of the promise. However, the closest I got is to put together something similar to the last answer in this in the SO post;
I have seen this several times with the "old" $dialog modal. I canβt learn much about how to do this with the βnewβ $dialog modal.
Some pointers will be appreciated.
To illustrate the problem, I use the example provided in the UT Bootstrap docs with some minor changes.
Controllers (main and modal)
'use strict'; angular.module('angularUiModalApp') .controller('MainCtrl', function($scope, $modal, $log) { $scope.items = ['item1', 'item2', 'item3']; $scope.open = function() { $scope.modalInstance = $modal.open({ templateUrl: 'myModalContent.html', controller: 'ModalInstanceCtrl', resolve: { items: function() { return $scope.items; } } }); $scope.modalInstance.result.then(function(selectedItem) { $scope.selected = selectedItem; }, function() { $log.info('Modal dismissed at: ' + new Date()); }); }; }) .controller('ModalInstanceCtrl', function($scope, $modalInstance, items) { $scope.items = items; $scope.selected = { item: $scope.items[0] }; $scope.ok = function() { $modalInstance.close($scope.selected.item); }; $scope.cancel = function() { $modalInstance.dismiss('cancel'); }; });
View (main.html)
<div ng-controller="MainCtrl"> <script type="text/ng-template" id="myModalContent.html"> <div class="modal-header"> <h3>I is a modal!</h3> </div> <div class="modal-body"> <ul> <li ng-repeat="item in items"> <a ng-click="selected.item = item">{{ item }}</a> </li> </ul> Selected: <b>{{ selected.item }}</b> </div> <div class="modal-footer"> <button class="btn btn-primary" ng-click="ok()">OK</button> <button class="btn btn-warning" ng-click="cancel()">Cancel</button> </div> </script> <button class="btn btn-default" ng-click="open()">Open me!</button> <div ng-show="selected">Selection from a modal: {{ selected }}</div> </div>
Test
'use strict'; describe('Controller: MainCtrl', function() { // load the controller module beforeEach(module('angularUiModalApp')); var MainCtrl, scope; var fakeModal = { open: function() { return { result: { then: function(callback) { callback("item1"); } } }; } }; beforeEach(inject(function($modal) { spyOn($modal, 'open').andReturn(fakeModal); })); // Initialize the controller and a mock scope beforeEach(inject(function($controller, $rootScope, _$modal_) { scope = $rootScope.$new(); MainCtrl = $controller('MainCtrl', { $scope: scope, $modal: _$modal_ }); })); it('should show success when modal login returns success response', function() { expect(scope.items).toEqual(['item1', 'item2', 'item3']); // Mock out the modal closing, resolving with a selected item, say 1 scope.open(); // Open the modal scope.modalInstance.close('item1'); expect(scope.selected).toEqual('item1'); // No dice (scope.selected) is not defined according to Jasmine. }); });