Testing factory toBeDefined error - angularjs

Just started jasmine karma.
the test is failing due to following errors:
PhantomJS 2.1.1 (Mac OS X 0.0.0) dataservice spec should have dataservice be defined FAILED
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
Error: [$injector:unpr] Unknown provider: dataserviceProvider <- dataservice
i have provided all dependencies namely $http and $q still getting unknown provider error.
the factory has been described inside app.core module, which i have
included into the karma conf file
What am i missing.
the factory works fine inthe project
unit testing the following http factory
(function() {
'use strict';
angular
.module('app.core', [])
.factory('dataservice', dataservice);
dataservice.$inject = ['$http', '$q'];
function dataservice($http, $q) {
return {
makeRequest: makeRequest,
};
function makeRequest(params) {
var defer = $q.defer();
if (params.method == "GET") {
$http({
method: params.method,
url: params.url,
headers: params.headers
})
.then(function(response) {
defer.resolve(response);
},
function(response) {
defer.reject(response);
})
}
if (params.method == "POST") {
$http({
method: params.method,
url: params.url,
data: params.parameters,
headers: params.headers
})
.then(function(response) {
console.log(response);
defer.resolve(response);
},
function(response) {
console.log("error");
defer.reject(response);
})
}
return defer.promise;
})();
test spec:
(function(){
'use strict'
describe('dataservice spec',function(){
var dataservice;
beforeEach(function($injector){
angular.module('app.core');
//dataservice=$injector.get('dataservice')
});
beforeEach(inject(function (_dataservice_,_$http_,_$q_) {
dataservice = _dataservice_;
$http=_$http_;
$q=_$q_;
}));
// beforeEach(inject(function() {
// var $injector = angular.injector(['app.core']);
// dataservice = $injector.get('dataservice');
// }));
it('should have dataservice be defined', function () {
expect(dataservice).toBeDefined();
});
})
})();

You'll need to update your scripts as follows:
(function () {
'use strict';
angular
.module('app.core', [])
.factory('dataservice', dataservice);
dataservice.$inject = ['$http', '$q'];
function dataservice($http, $q) {
return {
makeRequest: makeRequest
};
function makeRequest(params) {
var defer = $q.defer();
if (params.method == "GET") {
$http({
method: params.method,
url: params.url,
headers: params.headers
})
.then(function (response) {
defer.resolve(response);
},
function (response) {
defer.reject(response);
})
}
if (params.method == "POST") {
$http({
method: params.method,
url: params.url,
data: params.parameters,
headers: params.headers
})
.then(function (response) {
console.log(response);
defer.resolve(response);
},
function (response) {
console.log("error");
defer.reject(response);
})
}
return defer.promise;
}
}
})();
The Unit test:
(function () {
'use strict'
describe('dataservice spec', function () {
var dataservice,
$http,
$q;
beforeEach(module('app.core'));
beforeEach(inject(function (_dataservice_, _$http_, _$q_) {
dataservice = _dataservice_;
$http = _$http_;
$q = _$q_;
}));
it('should have dataservice be defined', function () {
expect(dataservice).toBeDefined();
});
})
})();
Just make sure you're loading your module properly: beforeEach(module('app.core'));

Related

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

Angular seavice getAll is not a function

I've got a function in an Angular controller like so:
(function () {
'use strict';
var controlledID = 'Clause.Clause';
angular.module('docapp').controller(controlledID, ['$scope', 'common', 'taskSvc', 'clauseSvc', Clauses]);
function Clauses($scope, clauseSvc, taskSvc, common) {
$scope.GetContractMaster = function GetContractMaster() {
clauseSvc.getAll()
.then(function (response) {
$scope.ContractMaster.rowData = response.d.results;
console.log(response.d.results);
});
};
$scope.GetContractMaster();
};
}
})();
My Services
(function () {
'use strict';
var app = angular.module('docapp');
app.factory("clauseSvc", ["baseSvc", function (baseService) {
var listEndPoint = '/_api/web/lists/';
var getAll = function () {
var query = listEndPoint + "GetByTitle('CLAUSE_MST')/Items?$select=Title,Title,Desc,nodes/ID&$expand=nodes";
return baseService.getRequest(query);
};
return {
getAll: getAll
};
}]);
})();
baseService
"use strict";
(function () {
angular.module("docapp")
.factory("baseSvc", ["$http", "$q", function ($http, $q) {
var baseUrl = _spPageContextInfo.siteAbsoluteUrl;
var getRequest = function (query) {
var deferred = $q.defer();
$http({
url: baseUrl + query,
method: "GET",
headers: {
"accept": "application/json;odata=verbose",
"content-Type": "application/json;odata=verbose"
}
})
.success(function (result) {
deferred.resolve(result);
})
.error(function (result, status) {
deferred.reject(status);
});
return deferred.promise;
};
return {
getRequest: getRequest
};
}]);
})();
Getting error
[true] [SYSERR] clauseSvc.getAll is not a function Object {exception:
TypeError: clauseSvc.getAll is not a function
at n.GetContractMaster
Need help
Your controller is declared as
.controller('$scope', 'common', 'taskSvc', 'clauseSvc', Clauses]);
and the function is declared as
function Clauses($scope, clauseSvc, taskSvc, common)
So, the variable clauseSvcis in fact the common service instance, and the variable common is in fact the clauseSvc service instance.
Do yourself a favor: avoid that kind of bugs and make your code easier to write and read by just avoiding this array syntax, and using ngAnnotate to make your code minifiable.

AngularJS CRUD - export.update() not calling in server controller

I'm using the following Yeoman full stack AngularJS NPM: generator-angular-fullstack
When calling update from the client controller, I receive the following error: Error: undefined is not a function (evaluating 'User.update') I'm expecting to see the following in my Web Inspector Logs:
'5586c4e7214a22b5efbd1672'
'updateUser Called' <-- Never routes to server controller
server/api/route:
//Tried PATCH and PUT
router.patch('/:id', auth.isAuthenticated(), controller.update);
//router.put('/:id', auth.isAuthenticated(), controller.update);
server/api/controller:
exports.update = function(req, res, next) {
console.log('updateUser Called');
};
client/app/controller:
'use strict';
angular.module('demoApp')
.controller('SandboxCtrl', function ($scope, $http, $location, Auth, User) {
$scope.getCurrentUser = Auth.getCurrentUser;
$scope.user = {};
$scope.profiles = {};
$scope.allergens = {};
$http.get('/api/users/me').success(function (user) {
$scope.user = user;
$scope.profiles = user.profiles;
console.log(user.name);
console.log(user.profiles);
});
// Update existing User
$scope.update = function () {
var user = $scope.user;
console.log(user._id);
User.update(function () {
$location.path('/' + user._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
});
/Client/User/Factory:
'use strict';
angular.module('demoApp')
.factory('User', function ($resource) {
return $resource('/api/users/:id/:controller', {
id: '#_id'
},
{
changePassword: {
method: 'PUT',
params: {
controller:'password'
}
},
update: { //<-- I was missing this!
method: 'PATCH'
},
get: {
method: 'GET',
params: {
id:'me'
}
}
});
});
In AngularJS NPM generator-angular-fullstack, the factory/service is tucked away under /client/components/auth/user.service.js
Added necessary object handle to existing factory solved this issue.
update: { //<-- I was missing this!
method: 'PATCH'
},

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