Jasmine unit test controller - angularjs

I need to check two thing here:
The response length. specified the mock data as [{ name: 'John', id: 1 }, { name: 'Josh', id: 2 }] so the response length should be 2. it is failing this test always getting the length as 1.
The response data should be equal. ie. expect(IndexSummaryService.getIndexSummaryQueues).toEqual([{ name: 'John', id: 1 }, { name: 'Josh', id: 2 }]);
The test is failing with Message: Expected Function to equal [object({ name:'john', id:1}), object({ name:'josh', id:2}) ]
My service is bit different which takes api as parameter which is the URL.
Please suggest how to make these unit test working.
This is the service code
app.service("IndexSummaryService", ['$http', function ($http) {
this.getIndexSummaryQueues = function (api) {
return $http.get(api, { cache: false });
};
}]);
This is the controller
$scope.loadRecords = function (api) {
$scope.loading = true;
var GetIndexSummaryQueue = IndexSummaryService.getIndexSummaryQueues(api);
GetIndexSummaryQueue.then(function (response) {
$scope.Queues = response.data;
}, function (error) {
if (error.status == 500) {
$scope.errorStatus = "Error " + error.status;
$scope.errorMsg = error.data.message;
}
else {
$scope.errorStatus = "Error " + error.status;
$scope.errorMsg = GlobalConstants.errormessage;
}
$scope.errorpage = true;
$scope.success = false;
console.log("Status Data : " + error.data.message);
console.log("Status Error : " + error.status);
}).then(function () {
$scope.loading = false;
});
}
I have written unit test in jasmine below is the jasmine code.
describe("ISummary ->", function () {
beforeEach(function () {
module("ApplicationModule");
});
var $httpBackend;
var scope, createController;
beforeEach(inject(function ($rootScope, _$httpBackend_, $controller) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new();
createController = function () {
return $controller('IndexingSummaryController', {
$scope: scope
});
};
$httpBackend.when("GET", "https://domain.com/captivaapi/api/capturestats/pldindexingSummary")
.respond([{ name: 'John', id: 1 }, { name: 'Josh', id: 2 }]);
}));
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe("Service->", function () {
it("can load topics", inject(function (IndexSummaryService) {
$httpBackend.expectGET("https://domain.com/captivaapi/api/capturestats/pldindexingSummary");
IndexSummaryService.getIndexSummaryQueues('https://domain/captivaapi/api/capturestats/pldindexingSummary');
$httpBackend.flush();
expect(IndexSummaryService.getIndexSummaryQueues.length).toBeGreaterThan(0);
expect(IndexSummaryService.getIndexSummaryQueues.length).toEqual(2);
expect(IndexSummaryService.getIndexSummaryQueues).toEqual([{ name: 'John', id: 1 }, { name: 'Josh', id: 2 }]);
}));
});

You're not testing the response of the promise, try the below (might not be exact as it's been a while since I used Angular, but basically make your assertions in a then block, once the promise has resolved).
describe("Service->", function () {
it("can load topics", inject(function (IndexSummaryService) {
$httpBackend.expectGET("https://domain.com/captivaapi/api/capturestats/pldindexingSummary");
IndexSummaryService.getIndexSummaryQueues('https://domain/captivaapi/api/capturestats/pldindexingSummary').then(function(res) {
expect(res.length).toBeGreaterThan(0);
expect(res.length).toEqual(2);
expect(res).toEqual([{ name: 'John', id: 1 }, { name: 'Josh', id: 2 }]);
});
$httpBackend.flush();
}));
});

Related

TypeError: service.getForums() is not a function - jasmine unit testing for AngularJS

Hello I am new to AngularJS. I am trying to test angular service ForumService. For that I have to mock the response that I get while calling the service method. I did something but I don't know if its right or not. I am getting an error
"ForumService should use Function FAILED"
"TypeError: service.getForums is not a function"
This is the service that I am testing
(function() {
'use strict';
function ForumService($q, $http, config, Forum) {
var service = {};
/**
* Sends a GET request to backend API for all forums.
*
* #return {Promise}
*/
service.getForums = function(onSuccessCallback, onErrorCallback) {
$http.get(config.apiBaseUrl + '/api/forums')
.then(
function handleSuccess(response) {
onSuccessCallback(response.data.data);
},
function handleError(response) {
onErrorCallback(response.data.error);
}
);
};
/**
* Sends a GET request to backend API for all forums.
*
* #return {Promise}
*/
service.getForumsPromise = function() {
var q = $q.defer();
$http.get(config.apiBaseUrl + '/api/forums')
.then(
function success(response) {
q.resolve(buildForumArray(response.data.data));
},
function error(response) {
q.reject(response.data.error);
}
);
return q.promise;
};
function buildForumArray(data) {
var forumArray = [];
data.forEach(function(forumData) {
forumArray.push(new Forum(forumData));
});
return forumArray;
}
return service;
}
ForumService.$inject = [
'$q',
'$http',
'config',
'Forum'
];
angular
.module('app.services')
.factory('ForumService', ForumService);
})();
The following is the code where I am testing the first method service.getForums()
'use strict';
describe('ForumService', function() {
var service, $q, config, httpBackend;
beforeEach(module('app.services'));
beforeEach(module('app.models'));
beforeEach(module(function($provide) {
$provide.service('config', function() {
this.apiBaseUrl = "localhost";
});
$provide.service('ForumService', function() {
this.constructor = jasmine.createSpy('ForumService')
});
$provide.service('Forum', function() {
this.constructor = jasmine.createSpy('Forum')
});
}));
//2.
beforeEach(function() {
inject(function($injector) {
service = $injector.get('ForumService');
httpBackend = $injector.get('$httpBackend');
$q = $injector.get('$q');
});
});
// 5. make sure no expectations were missed in your tests.
afterEach(function() {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
it('should use Function', function() {
var returnData = [
{
id: 1,
name: "Programming Questions",
description: "Please post all Questions you have in regards to programming here"
}, {
id: 2,
name: "OOP",
description: "Object Oriented Programming"
}
];
console.info('foo');
httpBackend.when('GET', 'localhost/api/forums').respond(200, returnData);
service.getForums().then(function(response) {
console.info(response); // to see the response
expect(response.data.id).toBe(1);
expect(response.data.name).toBe("Programming Questions");
expect(response.data.description).toBe("Please post all Questions you have in regards to programming here");
});
httpBackend.flush();
});
});
And this is my model class
(function() {
'use strict';
angular
.module('app.models')
.factory('Forum', Forum);
Forum.$inject = [];
function Forum() {
/**
* Forum prototype (constructor function).
*
* #param data
* #constructor
*/
function Forum(data) {
var self = this;
if (angular.isDefined(data)) {
self.id = data.id;
self.name = data.name;
self.description = data.description;
} else {
self.id = 0;
self.name = '';
self.description = '';
}
}
return Forum;
}
})();
There were are lot of issues with the test cases and the code you've written. Fixed a few of them here
Do read the inline comments for the explainations
This should be the definition of you getForums method:
service.getForums = function(onSuccessCallback, onErrorCallback) {
$http.get(config.apiBaseUrl + '/api/forums').then(function handleSuccess(response) {
// You'll get the data inside response.data and not response.data.data
// onSuccessCallback(response.data.data);
onSuccessCallback(response.data);
}, function handleError(response) {
onErrorCallback(response.data.error);
});
};
If you really wanted to return promise from getForumsPromise method, you could have simply done this:
service.getForumsPromise = function() {
return $http.get(config.apiBaseUrl + '/api/forums');
};
$http.get returns a promise anyways.
And this is how you should be writing the test case:
'use strict';
describe('ForumService', function() {
var returnData = [{
id: 1,
name: "Programming Questions",
description: "Please post all Questions you have in regards to programming here"
}, {
id: 2,
name: "OOP",
description: "Object Oriented Programming"
}];
//Below line of code is not required.
// var service, $q, config, httpBackend;
beforeEach(module('app.services'));
beforeEach(module('app.models'));
beforeEach(module(function($provide) {
$provide.service('config', function() {
this.apiBaseUrl = "localhost";
});
// Below line of code is not required.
// $provide.service('ForumService', function() {
// this.constructor = jasmine.createSpy('ForumService')
// });
// $provide.service('Forum', function() {
// this.constructor = jasmine.createSpy('Forum')
// });
}));
//2.
// Instead of injecting the services like this
// beforeEach(function() {
// inject(function($injector) {
// service = $injector.get('ForumService');
// httpBackend = $injector.get('$httpBackend');
// $q = $injector.get('$q');
// });
// });
// Inject them like this
beforeEach(inject(function(_ForumService_, _$httpBackend_) {
ForumService = _ForumService_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', 'localhost/api/forums').respond(200, returnData);
}))
// 5. make sure no expectations were missed in your tests.
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should use Function', function() {
// This data should be outside a specific it block so that it could be reused.
// Moved it outside.
// var returnData = [{
// id: 1,
// name: "Programming Questions",
// description: "Please post all Questions you have in regards to programming here"
// }, {
// id: 2,
// name: "OOP",
// description: "Object Oriented Programming"
// }];
console.info('foo');
// This should be inside beforeEach block so that it could be reused.
// httpBackend.when('GET', 'localhost/api/forums').respond(200, returnData);
// You call httpBackend's flush right after the call to your service's method and then expect.
// Also your expectations are wrong. So you might get errors.
// Fixing those.
// service.getForums().then(function(response) {
// console.info(response); // to see the response
// expect(response.data.id).toBe(1);
// expect(response.data.name).toBe("Programming Questions");
// expect(response.data.description).toBe("Please post all Questions you have in regards to programming here");
// });
// httpBackend.flush();
// Like this.
var successCallback = function(data) {
expect(data.length).toEqual(2);
expect(data[0].id).toBe(1);
expect(data[0].name).toBe("Programming Questions");
expect(data[0].description).toBe("Please post all Questions you have in regards to programming here");
}
var errorCallback = function(error) {
}
ForumService.getForums(successCallback, errorCallback);
$httpBackend.flush();
});
});
Hope this helps

$httpBackend being ignored, Jasmine calling actual endpoint

I'm writing a test to simply check that an endpoint is being called by a service. I'm using $httpBackend to mock this response, however the test is still hitting the real backend endpoint, and not using the $httpBackend mock.
Service
function getOptions() {
return $http.get('/apiv1/something').then(function (data) {
return [{
name: "eGo C"
image: "http://www.google.co.uk/logo.png"
}];
};
}
Test
describe('product service', function () {
var $httpBackend, service, $rootScope;
var failTest = function (error) {
expect(error).toBeUndefined();
};
beforeEach(module('appName'));
beforeEach(inject(function (_$httpBackend_, productService, _$rootScope_) {
$httpBackend = _$httpBackend_;
$rootScope = _$rootScope_;
service = productService;
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('getOptions', function () {
it('should make a call to the backend', function () {
var handler,
myThings,
errorStatus,
mockResponce;
mockResponce = [
{
name: 'evod kit',
img: 'img.jpg'
}
];
myThings = [];
errorStatus = '';
handler = {
success: function(data) {
console.log("success " + data);
myThings = data;
},
error: function(data) {
console.log("error " + data);
errorStatus = data;
}
};
spyOn(handler, 'success').and.callThrough();
spyOn(handler, 'error').and.callThrough()
$httpBackend.when('GET', '/apiv1/something').respond(mockResponce);
service.getOptions().then(handler.success, handler.error);
$httpBackend.flush();
console.log("MY THINGS ", myThings);
// PROBLEM!!! == FROM THE SERVICE -> [{name: "eGo C"
// image: "http://www.google.co.uk/logo.png"
// }]
});
});
try this instead :
let $rootScope
beforeEach(angular.mock.inject(function( _$httpBackend_, _$rootScope_){
$rootScope = _$rootScope_
$rootScope.httpbackend = _$httpBackend_
}
Essentially.. I'm an idiot. In the service I was returning a hardcoded array as the backend is yet to be built. $httpBackend was doing its job and returning the new data, but of course, it was not getting returned by the service. Sigh. I need a beer.

Angularjs unit test resolve promise inside custom directive with external template

I have a custom directive that uses an external template and is passed data from a service. I decided to ensure that the promise was resolved before modifying the data, which was fine in the actual code but broke my unit tests, which is annoying. I have tried a number of variations but am now stuck. I am using 'ng-html2js' preprocessor.
Here is the unit test
describe('ccAccordion', function () {
var elm, scope, deferred, promise, things;
beforeEach(module('ccAccordion'));
// load the templates
beforeEach(module('components/accordion/accordion.html'));
beforeEach(inject(function ($rootScope, $compile, $q) {
elm = angular.element(
'<cc-accordion items="genres"></cc-accordion>'
);
scope = $rootScope;
things = [{
title: 'Scifi',
description: 'Scifi description'
}, {
title: 'Comedy',
description: 'Comedy description'
}];
deferred = $q.defer();
promise = deferred.promise;
promise.then(function (things) {
scope.items = things;
});
// Simulate resolving of promise
deferred.resolve(things);
// Propagate promise resolution to 'then' functions using $apply().
scope.$apply();
// compile the template?
$compile(elm)(scope);
scope.$digest();
}));
it('should create clickable titles', function () {
var titles = elm.find('.cc-accord h2');
expect(titles.length).toBe(2);
expect(titles.eq(0).text().trim()).toBe('Scifi');
expect(titles.eq(1).text().trim()).toBe('Comedy');
});
I have left out the custom addMatchers and the rest of the tests. The error I get is
TypeError: 'undefined' is not an object (evaluating 'scope.items.$promise')
Here is the directive
var ccAccordion = angular.module("ccAccordion", []);
ccAccordion.directive("ccAccordion", function () {
return {
restrict: "AE",
templateUrl: "components/accordion/accordion.html",
scope: {
items: "="
},
link: function (scope) {
scope.items.$promise.then(function (items) {
angular.forEach(scope.items, function (item) {
item.selected = false;
});
items[0].selected = true;
});
scope.select = function (desiredItem) {
(desiredItem.selected === true) ? desiredItem.selected = false : desiredItem.selected = true;
angular.forEach(scope.items, function (item) {
if (item !== desiredItem) {
item.selected = false;
}
});
};
}
};
});
This is where the directive is used in main.html
<cc-accordion items="genres"></cc-accordion>
In the main controller the genres service is passed in ie
angular.module('magicApp')
.controller('GenresCtrl', ['$scope', 'BREAKPOINTS', 'Genre',
function ($scope, BREAKPOINTS, Genre) {
$scope.bp = BREAKPOINTS;
$scope.genres = Genre.query();
}]);
Okay, I would move that code you put in link into the controller. The data processing should probably happen in a service. I know you've been told big controllers are bad, but big linking functions are generally worse, and should never do that kind of data processing.
.controller('GenresCtrl', ['$scope', 'BREAKPOINTS', 'Genre',
function ($scope, BREAKPOINTS, Genre) {
$scope.bp = BREAKPOINTS;
$scope.genres = Genre.query().then(function (items) {
angular.forEach(scope.items, function (item) {
item.selected = false;
});
items[0].selected = true;
});
scope.select = function (desiredItem) {
(desiredItem.selected === true) ? desiredItem.selected = false : desiredItem.selected = true;
angular.forEach(scope.items, function (item) {
if (item !== desiredItem) {
item.selected = false;
}
});
};
});
Your link function is now empty. Define items on the rootScope instead, this ensures that the isolateScope and your directive interface are working correctly.
beforeEach(inject(function ($rootScope, $compile, $q) {
elm = angular.element(
'<cc-accordion items="genres"></cc-accordion>'
);
scope = $rootScope;
things = [{
title: 'Scifi',
description: 'Scifi description'
}, {
title: 'Comedy',
description: 'Comedy description'
}];
scope.items = things; // Tests your directive interface
// compile the template?
$compile(elm)(scope);
scope.$digest();
}));
The behavior of the promise should be tested in a controller test, by mocking the return value of the service. Your problem with the $promise test has been solved.
The actual issue was that you were assuming that $q.defer() gave you the same kind of promise as the angular $http, but that is solved by design instead.
As peter said remove the promise from the directive and add it to the controller
angular.module('magicApp')
.controller('MainCtrl', ['$scope', 'Genre',
function ($scope, Genre) {
$scope.genres = Genre.query();
$scope.genres.$promise.then(function () {
angular.forEach($scope.genres, function (genre) {
genre.selected = false;
});
$scope.genres[0].selected = true;
});
}]);
This will also allow the controller to specify which tab is selected to begin with.
In the directive
var ccAccordion = angular.module("ccAccordion", []);
ccAccordion.directive("ccAccordion", function () {
return {
restrict: "AE",
templateUrl: "components/accordion/accordion.html",
scope: {
items: "="
},
link: function (scope) {
scope.select = function (desiredItem) {
(desiredItem.selected === true) ? desiredItem.selected = false : desiredItem.selected = true;
angular.forEach(scope.items, function (item) {
if (item !== desiredItem) {
item.selected = false;
}
});
};
}
};
});
The directive unit test now looks like this
describe('ccAccordion', function () {
var elm, scope, deferred, promise, things;
beforeEach(module('ccAccordion'));
beforeEach(function () {
jasmine.addMatchers({
toHaveClass: function () {
return {
compare: function (actual, expected) {
var classTest = actual.hasClass(expected);
classTest ? classTest = true : classTest = false;
return {
pass: classTest,
message: 'Expected ' + angular.mock.dump(actual) + ' to have class ' + expected
};
}
};
}
});
});
// load the templates
beforeEach(module('components/accordion/accordion.html'));
beforeEach(inject(function ($rootScope, $compile, $q) {
elm = angular.element(
'<cc-accordion items="genres"></cc-accordion>'
);
scope = $rootScope;
scope.genres = [{
title: 'Scifi',
description: 'Scifi description'
}, {
title: 'Comedy',
description: 'Comedy description'
}];
$compile(elm)(scope);
scope.$digest();
}));
it('should create clickable titles', function () {
var titles = elm.find('.cc-accord h2');
expect(titles.length).toBe(2);
expect(titles.eq(0).text().trim()).toBe('Scifi');
expect(titles.eq(1).text().trim()).toBe('Comedy');
});
it('should bind the content', function () {
var contents = elm.find('.cc-accord-content div:first-child');
expect(contents.length).toBe(2);
expect(contents.eq(0).text().trim()).toBe('Scifi description');
expect(contents.eq(1).text().trim()).toBe('Comedy description');
});
it('should change active content when header clicked', function () {
var titles = elm.find('.cc-accord h2'),
divs = elm.find('.cc-accord');
// click the second header
titles.eq(1).find('a').click();
// second div should be active
expect(divs.eq(0)).not.toHaveClass('active');
expect(divs.eq(1)).toHaveClass('active');
});
});
And the unit test for main controller now has the added property of selected
'use-strict';
describe('magicApp controllers', function () {
// using addMatcher because $resource is not $http and returns a promise
beforeEach(function () {
jasmine.addMatchers({
toEqualData: function () {
return {
compare: function (actual, expected) {
return {
pass: angular.equals(actual, expected)
};
}
};
}
});
});
beforeEach(module('magicApp'));
beforeEach(module('magicServices'));
describe('MainCtrl', function () {
var scope, ctrl, $httpBackend;
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('/api/genres').
respond([{title: 'Scifi', selected: true}, {title: 'Comedy', selected: false}]);
scope = $rootScope.$new();
ctrl = $controller('MainCtrl', {$scope: scope});
}));
it('should create "genres" model with 2 genres fetched from xhr', function () {
expect(scope.genres).toEqualData([]);
$httpBackend.flush();
expect(scope.genres).toEqualData(
[{title: 'Scifi', selected: true}, {title: 'Comedy', selected: false}]);
});
});
});

Mock not being used in Unit Test

I am stumped. I have written modal tests a few times now but in the controller I am currently testing I keep getting a TypeError: 'undefined' is not a function (evaluating 'pressReleaseCampaignService.deleteCampaign(global.activeOrganizationId, accountId, campaign.entityId) error. I want the test to use my mock however and Im not sure why it keep referencing the original controller. Does anyone see my mistake?
Controller:
angular.module('pb.campaigns.controllers')
.controller('ConfirmDeleteModalController', ['$scope', '$stateParams', '$state', '$modal', '$modalInstance', 'global', 'pbRoles', 'campaign', 'accountId', 'pressReleaseCampaignService',
function ($scope, $stateParams, $state, $modal, $modalInstance, global, pbRoles, pressReleaseCampaignService, campaign, accountId) {
$scope.campaign = campaign;
$scope.currentAccountId = accountId;
$scope.delete = function (accountId, campaign) {
global.setFormSubmitInProgress(true);
pressReleaseCampaignService.deleteCampaign(global.activeOrganizationId, accountId, campaign.entityId).then(function () {
global.setFormSubmitInProgress(false);
$modalInstance.close();
},
function (errorData) {
global.setFormSubmitInProgress(false);
});
};
$scope.cancel = function () {
global.setFormSubmitInProgress(false);
$modalInstance.dismiss('cancel');
};
}]);
Test:
describe('ConfirmDeleteModalController', function () {
beforeEach(module('pb.roles'));
beforeEach(module('pb.campaigns.controllers'));
beforeEach(module('ui.router'));
beforeEach(module('ui.bootstrap'));
var mockModalInstance = {};
var mockcampaignBuyRequestService = {};
var mockGlobal = {};
var mockStateParams = {};
var mockState = {};
var mockPbRoles = {};
beforeEach(inject(function ($q) {
mockGlobal = {
setFormSubmitInProgress: function (boolean) {
this.formProgress = boolean;
},
formProgress: false,
activeOrganizationId: 0
};
mockStateParams = {
orgId: 1,
accountId: 3,
entityId: 94,
campaignId: 45,
page: 3,
length: 12
};
mockModalInstance = {
close: jasmine.createSpy('mockModalInstance.close'),
dismiss: jasmine.createSpy('mockModalInstance.dismiss'),
result: {
then: jasmine.createSpy('mockModalInstance.result.then')
}
};
mockPressReleaseCampaignService = {
campaign: { entityId: 2, page: 19, length: 200 },
deleteCampaign: function (activeOrganizationId, entityId) {
var defer = $q.defer();
defer.resolve();
return defer.promise;
}
};
}));
beforeEach(inject(function ($rootScope, _$controller_) {
scope = $rootScope.$new();
$controller = _$controller_;
controller = $controller('ConfirmDeleteModalController', {
$modalInstance: mockModalInstance,
$scope: scope,
$stateParams: mockStateParams,
$state: mockState,
global: mockGlobal,
pbRoles: mockPbRoles,
pressReleaseCampaignService: mockPressReleaseCampaignService,
campaign: function () {
return mockPressReleaseCampaignService.campaign
},
accountId: function () {
return mockPressReleaseCampaignService.accountId
}
});
}));
describe("delete() function", function () {
it("calls deleteCampaign with proper params", function () {
spyOn(mockPressReleaseCampaignService, "deleteCampaign").and.callThrough();
scope.delete(mockStateParams.accountId, mockPressReleaseCampaignService.campaign);
expect(mockPressReleaseCampaignService.deleteCampaign).toHaveBeenCalledWith(mockGlobal.activeOrganizationId, mockStateParams.accountId, mockPressReleaseCampaignService.campaign.entityId);
});
it("calls close and toggles setFormSubmitionInProgress status", function () {
scope.delete(mockStateParams.accountId, mockPressReleaseCampaignService.campaign);
expect(mockGlobal.formProgress).toEqual(true);
scope.$digest();
expect(mockModalInstance.close).toHaveBeenCalled();
expect(mockGlobal.formProgress).toEqual(false);
});
});
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);
});
});
});
The order of the service names is not the same as the order of the variables:
'campaign', 'accountId', 'pressReleaseCampaignService'
vs.
pressReleaseCampaignService, campaign, accountId
So, when your code calls a method on pressReleaseCampaignService, it actually calls a method on the campaign service.

Jasmine Test- Need to manually set values to be expected

For testing with Angular.js, Mocha, and Jasmine I have this test for DeviceVal value file:
describe("load balancer device: value", function() {
var DeviceVal;
DeviceVal = null;
beforeEach(function() {
return module("main.loadbalancer");
});
beforeEach(inject(function(_DeviceVal_) {
return DeviceVal = _DeviceVal_;
}));
return it("should default the id to 'device not loaded'", function() {
return expect(DeviceVal).toEqual({
readonly: false,
lb: "device not loaded"
});
});
});
For one of my other tests, I have this which uses the DeviceVal value file:
describe("load balancer controller: readonly", function() {
$scope = DeviceVal = LoadBalancerSvc = SearchSvc = $state = $sce = null;
beforeEach(function() {
module('main');
});
beforeEach(inject(function($controller, $rootScope, _$state_, _LoadBalancerSvc_, _DeviceVal_) {
$scope = $rootScope.$new();
$state = _$state_;
LoadBalancerSvc = _LoadBalancerSvc_;
DeviceVal = _DeviceVal_;
$controller('HeaderCtrl', {$scope: $scope});
//to resolve all the promises we have on the mocked service
$scope.$digest();
lb = { ha_status: "secondary", id: "34584"};
this.lb = lb;
spyOn(LoadBalancerSvc, "searchDevice").and.returnValue(
{get: function() {
return { then: function(fn) { fn(lb)} }}});
spyOn($state, "go");
}));
it('scope data memembers to have their stuff', function() {
$scope.searchButton.submit();
expect(lb).toEqual(this.lb);
expect(lb['ha_status']).toEqual("secondary");
expect(DeviceVal.readonly).toBe(true);
expect($state.go).toHaveBeenCalledWith("main.loadbalancer.vips", {id: this.lb.id});
});
});
The issue I am having is I want to manually set the values in the second test of DeviceVal to custom values. But instead, the test expects the values to be the values in the first DeviceVal test file. It complains of:
Expected { readonly : true, lb : { ha_status : 'secondary', id : '34584' } } to equal { readonly : false, lb : 'device not loaded' }.
How can I make the second test where I can manually set the values DeviceVal.lb = { ha_status: "secondary", id: "34584"}; and have expect(lb['ha_status']).toEqual("secondary"); and expect(DeviceVal.readonly).toBe(true);?
UPDATE:
Here it is with mock DeviceVal, but I still get Error: Expected { readonly : true, lb : { ha_status : 'secondary', id : '34584' } } to equal { readonly : fals
e, lb : 'device not loaded' }.:
describe("load balancer controller: readonly", function() {
$scope = DeviceVal = LoadBalancerSvc = SearchSvc = $state = $sce = null;
beforeEach(function() {
module('main');
});
beforeEach(inject(function($controller, $rootScope, _$state_, _LoadBalancerSvc_, _DeviceVal_) {
$scope = $rootScope.$new();
$state = _$state_;
LoadBalancerSvc = _LoadBalancerSvc_;
DeviceVal = _DeviceVal_;
$controller('HeaderCtrl', {$scope: $scope});
//to resolve all the promises we have on the mocked service
$scope.$digest();
//MY ATTEMPT AT MOCKING THIS DATA
DeviceVal.lb = { ha_status: "secondary", id: "34584"};
DeviceVal.readonly = true;
spyOn(LoadBalancerSvc, "searchDevice").and.returnValue(
{get: function() {
return { then: function(fn) { fn(DeviceVal.lb)} }}});
spyOn($state, "go");
}));
it('scope data memembers to have their stuff', function() {
$scope.searchButton.submit();
expect(DeviceVal.lb).toEqual({ha_status: "secondary", id: "34584"});
expect(DeviceVal.lb['ha_status']).toEqual("secondary");
expect(DeviceVal.readonly).toBe(true);
expect($state.go).toHaveBeenCalledWith("main.loadbalancer.vips", {id: DeviceVal.lb.id});
});
});
Fixed it. From http://angular-tips.com/blog/2014/06/introduction-to-unit-test-controllers/, I created the mock data like this:
describe("load balancer controller: readonly", function() {
$scope = DeviceVal = LoadBalancerSvc = SearchSvc = $state = $sce = null;
beforeEach(function() {
eviceVal = {}
module('main', function($provide) {
$provide.value('DeviceVal', eviceVal);
});
inject(function() {
eviceVal.lb = { ha_status: "secondary", id: "34584"};
eviceVal.readonly = true;
});
});

Resources