For unit testing I use jasmine.I want to test the filterList function .
How could I do that ? The problem is I mock the service object, but how to declare the method inside the mock object so that I can test filterList function.
Ignore syntax , because I copy paste the code and delete some lines, so chances are high that there is lots of syntax error.
function (_,angular) {
'use strict';
var ngDependencies = ['StateService','$scope','$rootScope'];
var Constructor = function Constructor(StateService,$scope,$rootScope) {
var self = this;
self.defaultSelectedCompany = {};
self.companies = {
available: []
};
var ChangeListener = StateService.subscribe(function () {
self.companies.available = StateService.getAvailable('clients');
self.myCompanyList = _.map(self.companies.available, function companyList(user) {
return {
id: user.name};
});
self.filterList = function filterList($searchVal, $list) {
return _.filter($list, function (item) {
return item.displayValue.toLowerCase().indexOf($searchVal.toLowerCase()) >= 0 ||
item.secondaryValue.toLowerCase().indexOf($searchVal.toLowerCase()) >= 0;
});
};
self.updateDefaultCompany(self.myCompanyList[0]);
});
self.updateDefaultCompany = function updateDefaultCompanyPreference(selected) {
self.defaultSelectedCompany = selected;
};
$scope.$on('$destroy', ChangeListener);
};
Constructor.$inject = ngDependencies;
return Constructor;
And my spec files is as bellow
function (angular, _) {
'use strict';
var MockStateService = {
name: 'GlobalStateService',
subscribe: jasmine.createSpy('subscribe').and.callFake(function subscribe(state){
return {
filterList : function filterList($searchVal, $list) {
return _.filter($list, function (item) {
return item.displayValue.toLowerCase().indexOf($searchVal.toLowerCase()) >= 0 ||
item.secondaryValue.toLowerCase().indexOf($searchVal.toLowerCase()) >= 0;
});
}
};
})
};
describe('Controller', function () {
beforeEach(function () {
module(Module.name);
utils.useMocks([
MockStateService
]);
});
beforeEach(inject(function ($controller, $rootScope) {
this.scope = $rootScope.$new();
this.reqDrawerCtrl = $controller('SettingsController', {$scope: this.scope});
}));
describe('filterList', function () {
it('is a function', function () {
expect(typeof this.reqDrawerCtrl.filterList).toBe('function');
});
});
});
Related
I'm trying to write a unit test using karma and jasmine for an Angular controller that depends on a service
storesController.js
(function () {
var app = angular.module('storesController', ['storesService']);
app.controller('StoresListController', function ($scope, StoresService) {
$scope.getStores = function () {
StoresService.getStores().then(function (data) {
$scope.stores = data.data;
});
};
$scope.getStores();
$scope.deleteStore = function (id) {
StoresService.deleteStore(id).then(function () {
$scope.getStores();
});
};
});
storesService.js
(function () {
var app = angular.module('storesService', []);
app.factory('StoresService', ['$http', function ($http) {
var stores = [];
stores.getStores = function () {
return $http.get(/api/getStores');
};
stores.deleteStore = function (storeID) {
return $http.delete(/api/deleteStore/'+storeID);
};
return stores;
}]);
})();
And the test,
controllers.spec.js
describe('StoresController', function () {
beforeEach(module('storesController'));
var scope;
var storesServiceMock;
var controller;
beforeEach(inject(function ($controller, $rootScope) {
storesServiceMock = {
getStores: function() {
},
deleteStores: function() {
}
};
spyOn(storesServiceMock, 'getStores').and.returnValue({name : 'TestName', country : 'TestCountry'})
scope = $rootScope.$new();
controller = $controller('StoresListController', {
$scope: scope, StoresService: storesServiceMock
});
}));
it('scope.stores should be defined', function () {
expect(scope.stores).toBeDefined;
});
});
And I'm getting
TypeError: StoresService.getStores(...).then is not a function at n.$scope.getStores
I've also tried width httpBackend but I'm not be able to make it work, any clue about what I'm doing wrong?
Have the spy return a promise.
With ES2015:
spyOn(storesServiceMock, 'getStores').and.returnValue(Promise.resolve({name : 'TestName', country : 'TestCountry'}));
With $q:
spyOn(storesServiceMock, 'getStores').and.callFake(function() {
var deferred = $q.defer();
deferred.resolve({name : 'TestName', country : 'TestCountry'}));
return deferred.promise;
});
I am having a controller and service like below
(function () {
var mockController = function ($scope, MockService) {
$scope.message = "This is a text message";
$scope.getCities = function () {
$scope.places = [];
MockService.getCities().then(function (response) {
var places = response.data["weather-app:root"].city;
if (places) {
if (Array.isArray(places)) {
$scope.places = places;
} else {
$scope.places.push(places);
}
}
});
};
};
var mockService = function ($http) {
this.getCities = function () {
return $http.get("../rest/url", {
headers: {
'Accept': 'application/yang.data+json'
}
});
};
};
angular.module("MockApp", [])
.service("MockService", mockService)
.controller("MockController", mockController);
}())
I created a mock service like below for mocking the service for unit testing.
(function () {
angular.module('mock.service', [])
.service('MockService', function ($q) {
var mockService = {};
mockService.getCities = function () {
var mydata = {
"weather-app:root": {
"city": [
{
"city-name": "Chennai"
, "country-name": "India"
}
, {
"city-name": "Mangalore"
, "country-name": "India"
}
]
}
}
return $q.when(mydata);
};
return mockService;
});
}());
My test case is like
describe("MockController", function () {
var $scope;
beforeEach(function () {
module("MockApp");
beforeEach(module('mock.service'));
inject(function (_$controller_, _$rootScope_, _MockService_) {
$scope = _$rootScope_.$new();
controller = _$controller_("MockController", {
$scope: $scope
, MockService: _MockService_
});
});
});
describe("Test", function () {
it("Should be Bangalore", function () {
$scope.getCities();
console.log($scope.places);
});
});
});
the problem is that the then method in controller is not getting called. How can I resolve the issue ?
Three things to fix...
Don't nest the beforeEach calls. You can init multiple modules with module.
beforeEach(function() {
module('MockApp', 'mock.service');
// and so on
Your mock data does not quite match what you'd see from an $http based promise response
return $q.when({data: mydata});
In order to process promises, you need to trigger a digest cycle
it("Should be Bangalore", function() {
$scope.getCities();
$scope.$apply();
console.log($scope.places);
});
I am trying to unit test the init function of this controller.I cannot find a way of doing this and keep getting the error
TypeError: 'undefined' is not a function (evaluating '$state.includes('profile.details')')
My main concern is to mock the state so that this error goes away and my other tests can pass and then I will focus on writing the test for the init statement. I have tried mocking the state as a string and using transitionTo, has anyone else found a way of testing includes for states?
var init = function () {
$scope.global = global;
$scope.partialViews = {
personForm: "/app/users/views/details/_personForm.html",
passwordForm: "/app/users/views/details/_passwordForm.html"
};
if (!$state.includes('profile.details') && !$state.includes('profile.organizations')) {
if (global.activeProfile.defaultOrganizationId) {
$state.go("dashboard.notifications", { orgId: global.activeProfile.defaultOrganizationId });
} else {
$state.go("profile.organizations");
}
}
};
As an aside I went back to reading the docs to see how the .includes method works in hopes that it would help me figure out what I am doing wrong in my unit tests. in the MDN docs the .includes example is [1, 2, 3].includes(2); but typing this into the console responded with a
Uncaught TypeError: undefined is not a function
why is that?
my tests:
beforeEach(module('pb.users.controllers'));
beforeEach(module('ui.router'));
beforeEach(module('ui.bootstrap'));
var mockUserService = {};
var mockOrganizationService = {};
var mockPersonInvitationService = {};
var mockStateParams = {};
var mockState = "profile.details";
var mockGlobal = {};
var mockForm = {};
var mockModal = {};
var invitation = {};
beforeEach(inject(function ($q) {
invitation = {
organizationId: 6542643
};
mockForm = {
submitIfValid: function (promiseHandler) {
return promiseHandler();
}
};
mockStateParams = {
accountId: 7672891,
entityId: 532,
orgId: 67,
page: 43,
length: 12
};
mockGlobal = {
setFormSubmitInProgress: function (boolean) {
this.formProgress = boolean;
},
formProgress: false,
activeOrganizationId: 432,
organizationsUpdated: function () {
return "updated!"
}
};
mockUserService = {
user: {
person: {
name: 'Regan Perkins'
}
},
getUser: function () {
var defer = $q.defer();
defer.resolve(this.user);
return defer.promise;
},
updateExtendedInfo: function (person) {
var defer = $q.defer();
defer.resolve(this.user);
return defer.promise;
}
};
mockOrganizationService = {
organizations: {
groups: ["PressBoard", "MySite"]
},
getOrganizations: function () {
var defer = $q.defer();
defer.resolve(this.organizations);
return defer.promise;
}
};
mockPersonInvitationService = {
invitations: ["invite one", "invite two"],
getInvitations: function () {
var defer = $q.defer();
defer.resolve(this.invitations);
return defer.promise;
},
acceptInvitation: function (organizationId) {
var defer = $q.defer();
defer.resolve(invitation);
return defer.promise;
}
};
}));
beforeEach(inject(function ($rootScope, _$controller_) {
scope = $rootScope.$new();
$controller = _$controller_;
controller = $controller('ProfilesController', {
$scope: scope,
$stateParams: mockStateParams,
$state: mockState,
$modal: mockModal,
global: mockGlobal,
userService: mockUserService,
organizationService: mockOrganizationService,
personInvitationService: mockPersonInvitationService
});
}));
describe('init() function', function () {
it('should set activeOrganizationId', function () {
expect(scope.global.activeOrganizationId).toEqual(mockGlobal.activeOrganizationId);
});
it('should set global', function () {
expect(scope.global).toEqual(mockGlobal);
});
});
describe('get() function', function () {
it('should resolve a promise', function () {
scope.get();
scope.$digest();
expect(scope.person).toEqual(mockUserService.user.person);
});
});
describe("edit() function", function () {
it("should toggle personFormSuccess", function () {
spyOn(mockUserService, "updateExtendedInfo").and.callThrough();
scope.edit(mockForm, mockUserService.user);
expect(mockUserService.updateExtendedInfo).toHaveBeenCalledWith(mockUserService.user);
});
it("should call updateExtendedInfo()", function () {
spyOn(mockUserService, "updateExtendedInfo").and.callThrough();
scope.edit(mockForm, mockUserService.user);
expect(scope.personFormSuccess).toBe(false);
scope.$digest();
expect(scope.personFormSuccess).toBe(true);
});
});
describe('getOrganizations() function', function () {
it('should resolve a promise', function () {
scope.getOrganizations();
scope.$digest();
expect(scope.organizations).toEqual(mockOrganizationService.organizations);
});
});
describe('getInvitations() function', function () {
it('should resolve a promise', function () {
scope.getInvitations();
scope.$digest();
expect(scope.invitations).toEqual(mockPersonInvitationService.invitations);
});
});
describe('acceptInvitation() function', function () {
it('should toggle form progress', function () {
scope.invitations = mockPersonInvitationService.invitations;
scope.acceptInvitation(invitation, 1);
scope.$digest();
expect(scope.invitations).toEqual(mockPersonInvitationService.invitations);
});
it('should resolve a promise', function () {
scope.invitations = mockPersonInvitationService.invitations;
scope.acceptInvitation(invitation, 1);
scope.$digest();
expect(scope.invitations).toEqual(mockPersonInvitationService.invitations);
});
it('should resolve a promise', function () {
scope.invitations = mockPersonInvitationService.invitations;
scope.acceptInvitation(invitation, 1);
scope.$digest();
expect(scope.invitations).toEqual(['invite one']);
});
});
describe("openRejectInvitation() function", function () {
var actualOptions;
var modalOptions = {
templateUrl: '/app/users/views/organizations/_removeInvite.html',
controller: 'RejectInvitationModalController',
resolve: {
invitation: function () {
return invitation;
}
}
};
beforeEach(inject(function ($injector, $q) {
mockModal.open = function (options) {
actualOptions = options;
var defer = $q.defer();
defer.resolve();
return { result: defer.promise };
}
}));
it("make sure modalInstance.result.then is executed", function () {
scope.invitations = mockPersonInvitationService.invitations;
scope.openRejectInvitation(invitation, 1);
expect(scope.invitations).toEqual(['invite one', 'invite two']);
scope.$digest();
expect(scope.invitations).toEqual(['invite one']);
});
it("make sure modal.open is called", function () {
spyOn(mockModal, 'open').and.callThrough();
scope.openRejectInvitation(invitation, 1);
expect(mockModal.open).toHaveBeenCalledWith(actualOptions);
});
it("make sure 'webSite' is passed by modalInstance.resolve", function () {
scope.openRejectInvitation(invitation, 1);
expect(actualOptions.resolve.invitation()).toEqual(invitation);
});
});
});
Incase this helps anyone else with this problem the way I was able to bypass this error was to mock the includes method on my mockState.
var mockState = {
includes: function (string) {
return false
}
};
I am looking to test these two functions in my modal controller but Im not sure how to test $scope.$on functions. does anyone have any ideas?
$scope.$on("filesUploaded", function (e, files) {
for (var i = 0; i < files.length; i++) {
$scope.images.items.unshift(files[i]);
}
$scope.images.total += files.length;
});
$scope.$on("filesUploadCompleted", function () {
if (!$scope.$$phase) $scope.$apply();
});
my full test set up so far is:
describe('pbImagePickerModalController', function () {
beforeEach(module('pb.campaigns.controllers'));
beforeEach(module('ui.router'));
beforeEach(module('ui.bootstrap'));
//var mockWindow = {};
//var mockDocument = {};
var mockState = {};
var mockModal = {};
var mockGlobal = {};
var mockStateParams = {};
var mockAccountFileService = {};
var continuationToken = {};
beforeEach(inject(function ($q) {
mockStateParams = {
accountId: 543,
length: 12
};
mockGlobal = {
setFormSubmitInProgress: function (boolean) {
this.formProgress = boolean;
},
formProgress: false,
activeOrganizationId: 0
};
mockModalInstance = {
close: jasmine.createSpy('mockModalInstance.close'),
dismiss: jasmine.createSpy('mockModalInstance.dismiss'),
result: {
then: jasmine.createSpy('mockModalInstance.result.then')
}
};
mockAccountFileService = {
getFiles: function (activeOrganizationId, accountId, length, continuationToken) {
var defer = $q.defer();
defer.resolve(images);
return defer.promise;
}
};
}));
beforeEach(inject(function ($rootScope, _$controller_) {
scope = $rootScope.$new();
$controller = _$controller_;
controller = $controller('pbImagePickerModalController', {
$scope: scope,
$state: mockState,
$stateParams: mockStateParams,
global: mockGlobal,
accountFileService: mockAccountFileService,
$modal: mockModal,
$modalInstance: mockModalInstance,
//$window: mockWindow,
//$document: mockDocument,
accountId: mockStateParams.accountId
//accountId: function () {
// return mockStateParams.accountId;
//}
});
}));
describe("init() function", function () {
it('should call getImages()', function () {
spyOn(scope, 'getImages');
expect(scope.getImages).toHaveBeenCalledWith(50);
});
});
describe("getImages() function", function () {
it('should call getFiles with proper params', function () {
spyOn(mockAccountFileService, 'getFiles').and.callThrough();
scope.getImages(mockStateParams.length, continuationToken);
scope.$digest();
expect(mockAccountFileService.getFiles).toHaveBeenCalledWith(mockGlobal.activeOrganizationId, mockStateParams.accountId, mockStateParams.length, continuationToken);
});
it('should assign scope.images to promise result if scope.images does not exist', function () {
scope.getImages(mockStateParams.length, continuationToken);
scope.$digest();
expect(scope.images).toEqual(mockAccountFileService.images);
});
describe('with existing images', function () {
beforeEach(function () {
var existingLinks = {
continuationToken: 0002,
total: 2,
items: ['sponser_image01.png', 'sponser_image02.png']
};
scope.images = existingLinks;
});
it('should assign promise continuationToken to scope.images.continuationToken if scope.images exists', function () {
scope.getImages(mockStateParams.length, continuationToken);
scope.$digest();
expect(scope.images.continuationToken).toEqual(mockAccountFileService.images.continuationToken);
});
it('should assign promise data and existing images to scope if scope.images exists', function () {
scope.getImages(mockStateParams.length, continuationToken);
scope.$digest();
expect(scope.images.total).toEqual(4);
});
it('should push exisiting campaign links to link Array', function () {
scope.getImages(mockStateParams.length, continuationToken);
scope.$digest();
expect(scope.images.items).toEqual(['sponser_image01.png', 'sponser_image02.png', 'sponser_image03.png', 'sponser_image04.png']);
});
});
});
describe("cancel() function", function () {
it("changes formProgress from true to false", function () {
mockGlobal.setFormSubmitInProgress.formProgress = true;
scope.cancel();
expect(mockModalInstance.dismiss).toHaveBeenCalled();
expect(mockGlobal.formProgress).toEqual(false);
});
});
});
and my full controller is:
angular.module('pb.campaigns.controllers')
.controller('pbImagePickerModalController', ['$window', '$scope', '$document', '$modal', '$modalInstance', 'global', 'accountId', 'accountFileService', function ($window, $scope, $document, $modal, $modalInstance, global, accountId, accountFileService) {
$scope.currentAccountId = accountId;
var init = function () {
$scope.getImages(50);
};
$scope.getImages = function (length, continuationToken) {
// show all existing images
accountFileService.getFiles(global.activeOrganizationId, accountId, length, continuationToken).then(function (data) {
if ($scope.images) {
$scope.images.continuationToken = data.continuationToken;
$scope.images.total += data.total;
angular.forEach(data.items, function (value, key) {
$scope.images.items.push(data.items[key]);
});
} else {
$scope.images = data;
}
});
};
init();
$scope.$on("filesUploaded", function (e, files) {
for (var i = 0; i < files.length; i++) {
$scope.images.items.unshift(files[i]);
}
$scope.images.total += files.length;
});
$scope.$on("filesUploadCompleted", function () {
if (!$scope.$$phase) $scope.$apply();
});
//$scope.add = function (accountId, file) {
// global.setFormSubmitInProgress(true);
// accountFileService.createFile(global.activeOrganizationId, accountId, file).then(function () {
// global.setFormSubmitInProgress(false);
// $modalInstance.close();
// },
// function (errorData) {
// global.setFormSubmitInProgress(false);
// });
//};
$scope.select = function (image) {
$modalInstance.close(image);
};
$scope.cancel = function () {
global.setFormSubmitInProgress(false);
$modalInstance.dismiss('cancel');
};
}]);
You could test it with rootScope itself.
Example:-
$rootScope.$broadcast('filesUploaded', fileListStub); //broadcast the event with stub data
scope.$digest(); //Triger digest cycle to invoke on handler
expect(scope.images.total).toEqual(fileListStub.length+whateverinitialcount);
Demo
I am trying to get the "make sure modalInstance.result.then is executed" test in my code to pass. Right now it says Expected [ undefined, 'http://www.link1.com', 'http://www.link2.com', 'http://www.link3.com' ] to contain 'http://www.pressboardmedia.com' I believe this has something to do with the promise needing to be mocked so it passes along the campaignLink but I am unsure if this is the problem and cannot seem to get it to work regardless. please let know if you have any ideas.
Thanks!
Controller File
angular.module('pb.campaignLinks.controllers')
.controller('CampaignLinksController', ['$scope', '$timeout', '$modal', '$stateParams', 'global', 'campaignLinkService', function ($scope, $timeout, $modal, $stateParams, global, campaignLinkService) {
$scope.init = function (currentView) {
$scope.partialViews = {
campaignLinkList: "/app/campaignLinks/views/_list.html",
};
$scope.currentView = currentView;
$scope.getCampaignLinks(currentView, 10);
};
$scope.getCampaignLinks = function (currentView, length, continuationToken) {
// When loading list items, display loading image
if ($scope.campaignLinks) $scope.campaignLinks.loading = true;
var promiseObj = null;
if (currentView.campaignId && currentView.campaignId !== 0 && !currentView.buyRequestId) {
promiseObj = campaignLinkService.getCampaignLinks(global.activeOrganizationId, currentView.campaignId, length, continuationToken)
} else if (currentView.campaignId && currentView.buyRequestId && currentView.campaignId !== 0 && currentView.buyRequestId !== '') {
promiseObj = campaignLinkService.getCampaignBuyRequestLinks(global.activeOrganizationId, currentView.campaignId, currentView.buyRequestId, length, continuationToken);
} else if (currentView.webSiteId && currentView.buyRequestId && currentView.webSiteId !== 0 && currentView.buyRequestId !== '') {
promiseObj = campaignLinkService.getWebSiteBuyRequestLinks(global.activeOrganizationId, currentView.webSiteId, currentView.buyRequestId, length, continuationToken);
}
if (promiseObj) {
promiseObj.then(function (data) {
// If there are already some campaign links being displayed, add newly loaded list to the end
if ($scope.campaignLinks) {
$scope.campaignLinks.continuationToken = data.continuationToken;
$scope.campaignLinks.total += data.total;
$.each(data.items, function (index) {
$scope.campaignLinks.items.push(data.items[index]);
});
} else {
// Otherwise add loaded list to scope
$scope.campaignLinks = data;
}
// When done loading, hide loading image
$scope.campaignLinks.loading = false;
});
}
};
$scope.openAddCampaignLink = function (campaignId) {
var modalOptions = {
templateUrl: '/app/campaignLinks/views/_add.html',
controller: 'AddCampaignLinksModalController',
resolve: {
campaignId: function () {
return campaignId;
}
}
};
var modalInstance = $modal.open(modalOptions);
modalInstance.result.then(function (campaignLink) {
// Add new item to list, otherwise wait for it to be loaded manually.
$scope.campaignLinks.items.unshift(campaignLink);
$scope.campaignLinks.total += 1;
}, function () {
console.log('Modal dismissed at: ' + new Date());
});
};
$scope.openRemoveCampaignLink = function (campaignId, campaignLink, index) {
var modalOptions = {
templateUrl: '/app/campaignLinks/views/_delete.html',
controller: 'RemoveCampaignLinksModalController',
resolve: {
campaignId: function () {
return campaignId;
},
campaignLink: function () {
return campaignLink;
}
}
};
var modalInstance = $modal.open(modalOptions);
modalInstance.result.then(function () {
// Splice the deleted item from the list without reloading all
$scope.campaignLinks.items.splice(index, 1);
$scope.campaignLinks.total -= 1;
}, function () {
console.log('Modal dismissed at: ' + new Date());
});
};
// Once everything is loaded, initialize controller
// init();
}]);
Test file:
describe('CampaignLinksController', function () {
//make module avalible to tests
beforeEach(module('pb.campaignLinks.controllers'));
beforeEach(module('ui.router'));
beforeEach(module('ui.bootstrap'));
var $controller;
var mockPromiseObj;
var length = 200;
var mockModal = {};
var mockCampaignLinks = {
total: 3,
items: ['http://www.link1.com', 'http://www.link2.com', 'http://www.link3.com']
};
var mockCurrentView = {};
var mockGlobal = { activeOrganizationId: 54 };
var continuationToken = {
nextRowKey: 'fdsf2',
nextPartitionKey: '5432gee'
};
var campaignDetails = {
campaignId: 453,
campaignLink: 'http://www.pressboardmedia.com',
index: 1
};
var mockCampaignLinkService = {
//move campaignDetails here
campaignLinks: {
total: 3,
//length here
items: ['http://www.link1.com', 'http://www.link2.com', 'http://www.link3.com']
},
//all but delete must return a promiseObj
getCampaignLinks: jasmine.createSpy('mockCampaignLinkService.getCampaignLinks').and.returnValue(mockPromiseObj),
getCampaignBuyRequestLinks: jasmine.createSpy('mockCampaignLinkService.getCampaignBuyRequestLinks').and.returnValue(mockPromiseObj),
getWebSiteBuyRequestLinks: jasmine.createSpy('mockCampaignLinkService.getWebSiteBuyRequestLinks').and.returnValue(mockPromiseObj),
deleteCampaignLink: jasmine.createSpy('mockCampaignLinkService.deleteCampaignLinks')
};
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
beforeEach(inject(function ($rootScope) {
controller = $controller('CampaignLinksController',
{
$scope: scope,
$modal: mockModal,
//$stateParams: mockStateParams,
global: mockGlobal,
campaignLinks: mockCampaignLinks,
campaignLinkService: mockCampaignLinkService,
currentVeiw: mockCurrentView,
//promiseObj: mockPromiseObj
});
}));
describe('openAddCampaignLink()', function () {
var actualOptions;
var modalOptions = {
templateUrl: '/app/campaignLinks/views/_add.html',
controller: 'AddCampaignLinksModalController',
resolve: {
campaignId: jasmine.any(Function)
}
};
beforeEach(inject(function ($q) {
mockModal.open = function (options) {
actualOptions = options;
var defer = $q.defer();
defer.resolve();
return { result: defer.promise };
}
}));
it("make sure modalInstance.result.then is executed", function () {
scope.campaignLinks = mockCampaignLinkService.campaignLinks;
scope.openAddCampaignLink(campaignDetails.campaignId, campaignDetails.campaignLink, campaignDetails.index);
scope.$digest();
expect(scope.campaignLinks.total).toEqual(4);
expect(scope.campaignLinks.items).toContain(campaignDetails.campaignLink);
});
});
I think your problem is that the argument "campaignLink" that is supplied to your modalInstance.result.then function will always be undefined when you test this. The code that calls the modal close should be tested that it is supplying the campaignLink correctly. You only want to test that the proper code gets executed when the modal is closed. We do that by supplying a function that can be tested on it's own to the modalInstance.result.then call instead of doing an inline function so it can be tested easier.
Here's an example:
Here's the code that opens the modal:
$scope.editGradeClick = function () {
var modalInstance = $modal.open({
templateUrl: templateSrv.templateUrl('/Templates/App/Courses/CourseLessonGradeModal.html'),
controller: courseLessonGradeModalBootstrap,
backdrop: 'static',
keyboard: false,
resolve: {
data: $scope.editGradeModalResolve
}
});
modalInstance.result.then(
null,
$scope.editGradeModalDismissCallback
);
};
Notice how we supply a function $scope.editGradeModalDismissCallback instead of writting an inline function there for a modal dismiss. This allows us to test that logic in it's own test.
Now here is the test. We only care that the above function was called since we will be testing the specific function in it's own test. That happens at the last line in the test.
var $controllerConstructor, $scope, $q;
beforeEach(function () {
module('appModule');
inject(function ($controller, $rootScope, _$q_) {
$controllerConstructor = $controller;
$scope = $rootScope.$new();
$q = _$q_;
});
});
it('should execute $scope.editGradeModalDismissCallback when modal is dismissed', inject(function (templateSrv) {
var $modal = {};
$modal.open = function () {
var queryPromise = $q.defer();
queryPromise.reject();
return { result: queryPromise.promise };
};
$controllerConstructor('CourseLessonGradeListCtrl', { $scope: $scope, $modal: $modal, templateSrv: templateSrv});
spyOn($modal, "open").andCallThrough();
spyOn($scope, "editGradeModalDismissCallback");
$scope.editGradeClick();
$scope.$root.$digest();
expect($scope.editGradeModalDismissCallback).toHaveBeenCalled();
}));
I hope this helps you. In this example we are rejecting the promise because we are testing the modal dismiss not close, fyi...