The following Angular controller works fine:
angular.module("mymodule", [])
.service('svc', function($q) {
this.call = function() {
return $q.when(3);
};
})
.controller('MainCtrl', function($scope,svc) {
svc.call()
.then(function successCallback(response) {
$scope.var1 = response;
console.log($scope.var1);
});
});
However the related Jasmin unit test returns an error:
describe('Testing a Controller that uses a Promise', function () {
var $scope;
var $q;
var deferred;
beforeEach(module('mymodule'));
beforeEach(inject(function($controller, _$rootScope_, _$q_, svc) {
$q = _$q_;
$scope = _$rootScope_.$new();
deferred = _$q_.defer();
spyOn(svc, 'call').and.returnValue(deferred.promise);
$controller('MainCtrl', {
$scope: $scope,
svc: svc
});
}));
it('should resolve promise', function () {
deferred.resolve(11);
$scope.$apply();
expect($scope.var1).toBe(11);
});
The error:
TypeError: undefined is not a constructor (evaluating 'svc.call()
.then(function successCallback(response) {
$scope.var1 = response;
console.log($scope.var1);
})') in test/cookbook2.js (line 11)
Any ideas how to fix this problem?
PLUNK: http://plnkr.co/edit/j8J8J31ver1IE3fl6GyY?p=preview
Related
I want to mock my Angular JS method using Jamine. My code is:-
<script type="text/javascript">
var app = angular.module('mymodulee', []);
app.controller('mycontroller', function ($scope, $http, $log) {
$scope.ButtonClick = function (Id) {
var response = $http({
method: "get",
url: http://localhost:8080/Access/Tasks.DefectManagement/Services/Services.asmx/GetEligibilityDetails",
params: {
CovId: Id
}
});
return response;
}
});
And my Jasmine Test Case is:-
it('EligibilityDetails', function () {
var myserv, httpBackend;
inject(function ($httpBackend, _myserv_) {
myserv = _myserv_;
httpBackend = $httpBackend;
});
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
var $scope = {};
var controller = $controller('PatientDefectManagementCtrl', { $scope: $scope });
var returnData = {};
httpBackend.expectGET("http://localhost:8080/Access/Tasks.DefectManagement/Services/Services.asmx/GetEligibilityDetails").respond(returnData);
var returnedPromise = myserv.get(3904142);
var result;
returnedPromise.then(function (response) {
result = response.data;
});
httpBackend.flush();
expect(result).toEqual(returnData);
});
But its is giving an error. Can anyone please tell what changes I should make in my code so that i can run the test case using Jasmine Unit test.
Please help.
Thanks
describe('test',function(){
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();});
var myserv, httpBackend;
beforeEach(inject(function(_$httpBackend_,_myserv__){
myserv = _myserv_;
httpBackend = $httpBackend;});
it('EligibilityDetails', function () {
var $scope = {};
var controller = $controller('PatientDefectManagementCtrl', { $scope: $scope });
var returnData = {};
httpBackend.expectGET("http://localhost:8080/Access/Tasks.DefectManagement/Services/Services.asmx/GetEligibilityDetails").respond(returnData);
var returnedPromise = myserv.get(3904142);
var result;
returnedPromise.then(function (response) {
result = response.data;
});
httpBackend.flush();
expect(result).toEqual(returnData);});});
I am using angularjs and i have to test wrapped $http
ang.factory("HttpService", ["$http", "$q", function ($http, $q) {
return {
get: function (url) {
var result = $q.defer();
$http.get(url).success(function ($data) {
result.resolve($data);
}).error(function ($data) {
result.reject($data);
});
return result.promise;
}
};
}]);
And i think test should be something like
beforeEach(module('ngBoilerplate.employee', function ($provide) {
HttpService = jasmine.createSpyObj("HttpService", ["get", "post"]);
$provide.value("HttpService", HttpService);
}));
beforeEach(inject(function (_$controller_, _$rootScope_, _HttpService_) {
$scope = _$rootScope_.$new();
HttpService = _HttpService_;
$controller = _$controller_('EmployeeCtrl', {$scope: $scope, HttpService: HttpService});
}));
PS: I am using ngBoilerplate.
Thanks
I want to test that my injected service is being called in my controller.
login.controller.js
angular.module('exampleModule')
.controller('LoginCtrl', ['$state', 'AuthService',
function($state, AuthService) {
var self = this;
self.submit = function() {
AuthService.login(self.credentials)
.then(function(res) {
console.log('success');
$state.go('home');
}, function(res) {
if (res.status === 400) {
console.log('error')
}
});
};
}
]);
login.service.js
angular.module('exampleModule')
.factory('AuthService', ['$http',
function($http) {
var authService = {};
authService.login = function(credentials) {
return $http.post('/api/authenticate', credentials);
.then(function(res) {
return res;
});
};
return authService;
}
]);
login.controller.test.js
describe('Controller: LoginCtrl', function() {
beforeEach(module('exampleModule'));
var ctrl, authService;
beforeEach(inject(function($controller, AuthService){
ctrl = $controller('LoginCtrl');
authService = AuthService;
}));
describe('submit function', function() {
beforeEach(function(){
ctrl.submit();
});
it('should call AuthService', function() {
expect(authService.login).toHaveBeenCalled();
});
});
});
How do I properly test whether AuthService.login was called? With the way I'm injecting the AuthService into my test, I'm getting these errors:
TypeError: 'undefined' is not an object (evaluating 'AuthService.login(self.credentials).then')
You need to mock the login() method and make it return a promise:
describe('Controller: LoginCtrl', function() {
beforeEach(module('exampleModule'));
var ctrl, authService, $q;
beforeEach(inject(function($controller, _$q_, AuthService){
ctrl = $controller('LoginCtrl');
$q = _$q_;
authService = AuthService;
}));
describe('submit function', function() {
beforeEach(function(){
var deferred = $q.defer();
spyOn(authService, 'login').and.returnValue(deferred.promise);
ctrl.submit();
});
it('should call AuthService', function() {
expect(authService.login).toHaveBeenCalled();
});
});
});
Working Plunker
This is a function in my controller which uses Toastr for notifications. How would I test Toastr in my Jasmine unit test for this function.
$scope.login = function(user) {
$scope.user = user;
MyAuthService.login($scope.user)
.then(function(response) {
MyConfig.setUser(response.data.data);
toastr.success('Welcome', 'Login!',{closeButton: true});
});
}
As you are using promises you should use $q to mock myAuthService.login to return a resolved promise. You also want to spy on toastr.success and MyConfig.setUser. After calling $scope.login() you need to resolve the resolved promise and then call $rootScope.$digest();:
describe('MyCtrl', function() {
var createController, $scope, $rootScope, myAuthService, myConfig, toastr, deferred;
beforeEach(module('app'));
beforeEach(inject(function($controller, _$rootScope_, $q) {
$rootScope = _$rootScope_;
deferred = $q.defer();
myConfig = {
setUser: function (data) {
}
};
spyOn(myConfig, 'setUser');
myAuthService = {
login: function () {
}
};
spyOn(myAuthService, 'login').and.returnValue(deferred.promise);
toastr = {
success: function (message, title, options) {
}
};
spyOn(toastr, 'success');
$scope = $rootScope.$new();
createController = function() {
return $controller('MyCtrl',
{
$scope: $scope,
MyAuthService: myAuthService,
MyConfig: myConfig,
toastr: toastr
});
};
}));
it('login sets user in config and shows success toastr', function() {
//Arrange
createController();
var response = {
data: {
data: {
username: 'test'
}
}
};
$scope.user = {
username: 'test'
};
//Act
$scope.login();
deferred.resolve(response);
$rootScope.$digest();
//Assert
expect(myAuthService.login).toHaveBeenCalledWith($scope.user);
expect(myConfig.setUser).toHaveBeenCalledWith(response.data.data);
expect(toastr.success).toHaveBeenCalledWith('Welcome', 'Login!', {closeButton: true});
});
});
Plunkr
I'm using Jasmine in Visual Studio with chutzpah test adapter on top of AngularJs.
I get this error when running the test:
Error: Unexpected request: GET /webapi/api/Map
Error: Unsatisfied requests: GET /webapi/api/Map/
service:
var services = angular.module('mapService', ['ngResource']);
services.factory('mapService', ['$resource',
function ($resource) {
var objects = undefined;
var res = $resource('/webapi/api/Map/', {}, {
query: {
method: 'GET',
isArray: true
}
});
return {
getObjects: function (callback) {
res.query(function(successResult) {
objects = successResult;
});
return objects;
}
}
}]);
test:
describe('testing the department controller', function () {
var $scope, $location, mapController, $httpBackend, myMapService;
beforeEach(module('app'));
beforeEach(inject(function ($injector, $rootScope, $controller, _$httpBackend_, mapService) {
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', '/webapi/api/Map/')
.respond([jasonArray]);
myMapService = mapService;
}));
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should have objects', function () {
$httpBackend.expect('GET', '/webapi/api/Map/');
var objects = myMapService.getObjects(function (result) {
objects = result;
});
$httpBackend.flush();
expect(objects.length).toBeGreaterThan(0);
});
});
Can anyone suggest what I'm missing?
The error was in the url:
Just removed the trailing slash and it worked fine.
$httpBackend.when('GET', '/webapi/api/Map')