Jasmine error when using $httpBackend - angularjs

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

Related

Angular/Jasmin promise unit test not working

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

Is it possible to test $resource success and error callbacks in a controller?

I would like to test $resource success and error callbacks in my controller. I don’t want to use $httpBackend as that would be used to test the data service. It seems that there is no way to do it though - the only solution I have found is to use promises instead which I could either resolve or reject. Does this sound right? Anyway, here is what I have at the moment - currently it only tests whether the $resource get() is called:
The controller:
angular
.module('myModule')
.controller('MyCtrl', MyCtrl);
MyCtrl.$inject = [
'dataService'
];
function MyCtrl(
dataService
) {
var vm = this;
vm.getData = getData;
function getData() {
dataService.getData().get(function(response) {
// stuff to test
},
function(error) {
// stuff to test
});
}
The test:
describe('Controller: MyCtrl', function() {
var MyCtrl;
var rootScope;
var scope;
var dataServiceMock = {
getData: jasmine.createSpy('getData')
};
beforeEach(function()
inject(function($controller, $rootScope) {
rootScope = $rootScope;
scope = $rootScope.$new();
MyCtrl = $controller('MyCtrl as vm', {
dataService: dataServiceMock,
});
});
});
describe('vm.getData()', function() {
beforeEach(function() {
dataServiceMock.getData.and.returnValue({
get: jasmine.createSpy('get')
});
});
it('gets the data', function() {
scope.vm.getData();
expect(dataServiceMock.getData().get).toHaveBeenCalled();
});
});
});
Try this
function getData (query) {
var deferred = $q.defer();
var httpPromise = $resource(query,{},{
post:{
method:"GET",
isArray: false,
responseType: "json"
}
});
httpPromise.post({}, {},
function(data) {
try {
var results = {}
results.totalItems = data.response;
deferred.resolve(results);
} catch (error) {
console.log(error.stack);
deferred.reject();
}
},
function(error) {
deferred.reject();
}
);
return deferred.promise;
}

I am using jasmine and angular mock to check if a method is been called but is not working

I have a service object that makes a call to the backend to fetch a project by id, it works fine but when I mock the get method during testing the method is not being called, I am not sure what I am doing wrong. I am using a Jasmine2 and do not mock the httpbackend, I use the returnValue to set the response but somehow the returnValue is not waorking
This is the service
(function() {
'use strict';
angular
.module('moduleName')
.factory('Project', Project);
Project.$inject = ['$resource'];
function Project ($resource) {
var resourceUrl = 'api/projects/:id';
return $resource(resourceUrl, {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
if (data) {
data = angular.fromJson(data);
}
return data;
}
},
'update': { method:'PUT' }
});
}
})();
The controller looks like this
(function () {
'use strict';
angular
.module('moduleName')
.controller('ProjectController', ProjectController);
ProjectController.$inject = ['Project'];
function ProjectControllerr(Project) {
var vm = this;
vm.project = Project.get(1);
}
})();
This is the test
'use strict';
describe('Project Controller Tests', function () {
beforeEach(module('moduleName'));
describe('Project Controller', function () {
var $scope, $state, ProjectMock, stateMock, stateParamsMock;
beforeEach(inject(function ($rootScope) {
$scope = $rootScope.$new();
ProjectMock = jasmine.createSpyObj('Project', ['get']);
ProjectMock.get.and.returnValue({id:1,name:'data'});
stateParamsMock = {projectId: 1};
}));
describe('When a project is not empty', function () {
beforeEach(inject(function ($controller,Project) {
$controller('ProjectsController as vm',
{
$scope: $scope,
Project: ProjectMock,
$state: stateMock
});
}));
it('Should fetch current project by id', function () {
expect(ProjectMock.get).toHaveBeenCalled();
expect($scope.vm.project.id).toBe(1);
});
});
});
});
You are not calling ProjectMock.get(); That's why you are not getting response.So,your expectation toHaveBeenCalled is false if you checked it.
Do the following changes.
it('Should fetch current project by id', function () {
ProjectMock.get();
expect(ProjectMock.get).toHaveBeenCalled();
expect($scope.vm.project.id).toBe(1);
});

angularjs http service unit testing

I am trying to test a simple service for learning purposes..However; I can't figure out how it must be done:
service:
.factory('myService', function($http) {
var myService = {
async: function() {
var promise = $http.get('test.json').then(function (response)
{
return response.data;
});
return promise;
}
};
return myService;
});
controller:
myService.async().then(function(d) {
$scope.data = d;
$scope.e = $scope.data.txt;
});
test:
'use strict';
describe("myService", function(){
beforeEach(module("testingExpApp"));
var myService,
$httpBackend;
beforeEach(inject(function(myService, _$httpBackend_){
myService = myService;
$httpBackend = _$httpBackend_;
}));
describe("get", function(){
it('should return test.json data', function () {
var url = "../mock/test.json";
var x = $httpBackend.expectGET(url).respond(200, 'txt from json');
// flush response
$httpBackend.flush();
expect(x).toBe('txt from json');
});
});
});
I get 'no pending request to flush!'
I just want to test that myservice.get() get the test.json file data..I have tried everything but can't get it working..
Any tips?
Thanks a lot in advance!
What I was missing is to call service function
it had to be:
it('should return test.json data', function () {
var url = "../../mock/test.json";
$httpBackend.expectGET(url).respond(200, 'data from test.json');
//Execute service func here..
myServiceFunc.async().then(function(result) {
console.log(result);
expect(result).toEqual('data from test.json');
});
$httpBackend.flush();
});

Mocking HTTP service unit test with AngularJS and Jasmine

I am attempting to build a mock service so that my unit tests can verify certain functions are called and updated accordingly. Unfortunately I cannot get this to work.
Im currently getting an error undefined is not a function on this line:
spyOn(statusService, 'getModuleStatus').andCallThrough();
My actual service looks like this:
serviceStatusServices.factory('serviceStatusAppAPIservice', function ($http) {
var serviceStatusAppAPI = {};
serviceStatusAppAPI.getModuleStatus = function () {
return $http({
method: 'JSON',
url: '/settings/getservicestatusandconfiguration'
});
}
serviceStatusAppAPI.setModuleStatus = function (module) {
return $http({
method: 'POST',
url: '/settings/setservicestatusandconfiguration',
data: { moduleId: module.ModuleId, configData: module.ConfigValues }
});
}
return serviceStatusAppAPI;
});
My update function
serviceStatusControllers.controller('serviceStatusController', ['$scope', 'serviceStatusAppAPIservice', '$filter', '$timeout', function ($scope, serviceStatusAppAPIservice, $filter, $timeout) {
$scope.update = function () {
$scope.loading = true;
serviceStatusAppAPIservice.getModuleStatus().then(function (response) {
$scope.modules = $filter('orderBy')(response.data.moduleData, 'ModuleName')
...
My tests look like this
describe('ServiceStatusController', function () {
beforeEach(module("serviceStatusApp"));
var scope;
var statusService;
var controller;
var q;
var deferred;
// define the mock people service
beforeEach(function () {
statusService = {
getModuleStatus: function () {
deferred = q.defer();
return deferred.promise;
}
};
});
// inject the required services and instantiate the controller
beforeEach(inject(function ($rootScope, $controller, $q) {
scope = $rootScope.$new();
q = $q;
controller = $controller('serviceStatusController', {
$scope: scope, serviceStatusAppAPIservice: statusService });
}));
describe("$scope.update", function () {
it("Updates screen", function () {
spyOn(statusService, 'getModuleStatus').andCallThrough();
scope.update();
deferred.resolve();
expect(statusService.getModuleStatus).toHaveBeenCalled();
expect(scope.modules).not.toBe([]);
});
});
});
Also, how do I pass any mock data returned from the service to the caller. Currently in my model I do serviceStatusAppAPI.getModuleStatus(data) then use data.Data to get out the returned JSON.
I assume if you are doing something like this in your ctrl
scope.update = function() {
serviceStatusAppAPIservice.setModuleStatus(url).then(function (data) {
scope.modules = data;
})
};
Service which returns promise
.factory('serviceStatusAppAPI', function($http, $q) {
return {
getModuleStatus: function() {
var defer = $q.defer();
$http({method: 'GET', url: '/settings/getservicestatusandconfiguration'})
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
defer.resolve(data);
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
window.data = data;
});
return defer.promise;
}
};
});
So in you controller you will get data like this
serviceStatusAppAPI.getModuleStatus().then(function (data) {
$scope.modules = $filter('orderBy')(data.moduleData, 'ModuleName')
})
This is how you can run your unit test case
beforeEach(function() {
var statusService = {};
module('myApp', function($provide) {
$provide.value('serviceStatusAppAPIservice', statusService);
});
statusService.modalStatus = {
moduleData: [{ModuleName: 'abc'}, {ModuleName: 'def'}]
};
inject(function ($q) {
statusService.setModuleStatus = function () {
var defer = $q.defer();
defer.resolve(this.modalStatus);
return defer.promise;
};
statusService.getModuleStatus = function () {
var defer = $q.defer();
defer.resolve(this.modalStatus);
return defer.promise;
};
});
});
beforeEach(inject(function ($rootScope, $controller, _$stateParams_) {
scope = $rootScope.$new();
stateParams = _$stateParams_;
controller = $controller;
}));
var myCtrl = function() {
return controller('ServiceStatusController', {
$scope: scope,
});
};
it('should load status', function () {
myCtrl();
scope.update();
scope.$digest();
expect(scope.modules).toBe({
status: 'active'
});
});

Resources