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