angular testing with sinon, mocha, chai - angularjs

I want test my angular app with mocha,sinon and chai.
Especially I interest in submit function. How to create mock or stub for LoginResoure to test this function.
Thanks!
(function () {
'use strict';
class LoginController {
constructor($state,LoginResource) {
this.resource = LoginResource;
this.$state = $state;
this.credentials = {};
}
submit() {
let promise = this.resource.login(this.credentials);
promise.then(()=>{
changeState()
}
}
changeState() {
this.$state.go('home');
}
}
angular.module('app.login').controller('LoginController', LoginController);
})();
(function () {
'use strict';
class LoginResource {
constructor($resource, API_LOGIN) {
this.$resource = $resource(API_LOGIN,{'#id':id})
}
login(data) {
return this.$resource.save(data).$promise;
}
}
angular.module('app.login').service('LoginResource', LoginResource);
})();
EDIT:
Previously I do it with jasmine in next way:
let deferred = $q.defer();
deferred.resolve('Remote call result');
mockPeopleResource = {
createPerson: jasmine.createSpy('createPerson').and.returnValue(deferred.promise)
};
or if I want mock #resource
mockThen = jasmine.createSpy();
mockGetPeoplePromise = {then: mockThen};
mockUpdate = jasmine.createSpy().and.returnValue({$promise: mockPromise});
mockSave = jasmine.createSpy().and.returnValue({$promise: mockPromise});
mockGetPeopleQuery = jasmine.createSpy().and.returnValue({$promise: mockGetPeoplePromise});
mockResource = jasmine.createSpy().and.returnValue({
get: mockGet,
update: mockUpdate,
save: mockSave,
query: mockGetPeopleQuery
});

If you want to mock a service, you can create a test module when you set the mocked value:
beforeEach(function() {
angular.module('test', []).factory('LoginResource', function($q) {
return {
/* You can mock an easy login function that succeed when
data >= 0 and fails when data < 0 */
login: function(data) {
return $q(function(resolve, reject) {
if (data >= 0) return resolve();
reject();
});
}
};
});
module('app.login', 'test');
});

Related

How to unit test of a function which are inside another one

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');
});
});
});

How to test Angular controller having a service

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);
});

Accessing Angular directive controller from Protractor

Is there a way to access a directive's controller using the .controller() method inside a Protractor test? In unit tests I can do
var el = angular.element(...);
$compile(el)(scope);
var component = el.controller('nameOfDirective');
but I can't seem to figure out how to do that in a Protractor test.
Here is the code I'm trying to test...
//registration.route.js
(function () {
'use strict';
angular.module('app.account.registration').run(appRun);
appRun.$inject = ['routerHelper'];
/* #ngInject */
function appRun(routerHelper) {
routerHelper.configureStates(getStates());
}
function getStates() {
return [
{
state: 'registration',
config: {
url: '/registration',
template: '<registration layout="column" flex/>',
title: 'registration'
}
}
];
}
})();
//registration.component.js
(function () {
'use strict';
angular.module('app.account.registration').component('registration', {
templateUrl: 'app/account/registration/registration.html',
controller: Controller
});
/* #ngInject */
function Controller($state, UserService, SweetAlert) {
var self = this;
this.$onInit = function () {
this.state = 'unverified';
this.processing = false;
};
this.register = function (formData) {
this.processing = true;
UserService.register(formData.email).then(function (response) {
self.state = 'verify';
self.email = response.data.email;
//response.data.token will only be returned on localhost for security reasons
self.token = response.data.token;
self.processing = false;
}).catch(function (error) {
if (error.status === 422) {
SweetAlert.error('Error!', formData.email + ' already exists. Please use a unique email.');
}
self.processing = false;
});
};
}
})();
If anyone needs the answer for this, here it is:
browser.executeScript(function () {
return window.angular.element(document.body)
.find('DIRECTIVE-TAG-NAME').controller('directiveName');
}).then(function (directiveControllerInstance) {
console.log(directiveControllerInstance);
});
For example, if your directive name is "testDirective", you would do:
browser.executeScript(function () {
return window.angular.element(document.body)
.find('test-directive').controller('testDirective');
}).then(function (directiveControllerInstance) {
console.log(directiveControllerInstance);
});

Jasmine mock object in test

Is it posible to mock object for service? Is it posible to mock value of cfg.user.core.token? Im mocking httpBackend like this:
$httpBackend.when("GET","/check/").respond({
data: ['success']
});
This is my code:
.service("session", function ($window, $location, $http, cfg) {
var service = {};
service.check = function () {
$http.get("/chceck/" + cfg.user.core.token).then(function (response) {
if (response.data && response.data.success !== true) {
service.logout();
}
});
};
return service;
})
my part of test:
it("check ", function () {
spyOn(session, 'check').and.callThrough();
session.check();
expect(session.check).toHaveBeenCalled();
$httpBackend.flush();
});
Assuming cfg is an angular constant:
angular.module('mymodule')
.constant('cfg', {
user: {
core: {
token: 'token'
}
}
});
So in the Jasmine tests you can stub this constant:
describe('mytest', function () {
var
cfgStub = {
user: {
core: {
token: 'stubToken'
}
}
};
beforeEach(module('mymodule'));
beforeEach(module(function($provide) {
$provide.constant('cfg', cfgStub);
}));
...
});
And use cfgStub wherever you want in the tests.

How to test function in AngularJS service with mock data

How to create Jasmine unit test for one function in AngularJS service provider. I want to create mock data for myObject and test function getObjectShape() with that mock data as parameter. How to achieve that?
(function () {
'use strict';
angular.module('objectShapes')
.provider('shapesResolver', shapesResolver);
function shapesResolver() {
this.$get = function () {
return resolver;
};
function resolver(myObject) {
var service = {
getObjectShape: getObjectShape
};
function getObjectShape() {
return myObject.Shape;
}
}
}
})();
Here's a skeleton of a test for your service.
describe('shapesResolver service', function() {
var shapesResolver;
beforeEach(module('objectShapes'));
beforeEach(inject(function(_shapesResolver_) {
shapesResolver = _shapesResolver_;
}));
it('should do something, but what?', function() {
var mockMyObject = {};
shapesResolver(mockMyObject);
// shapesResolver doesn't return anything, and doesn't
// have any side effect, so there's nothing to test.
expect(true).toBeTruthy();
});
});

Resources