Testing AngularJS resource with Jasmine - angularjs

I would like to test my resource with following URL:
$resource(API_URL+'items/:id', {});
Where API_URL equals /app/api/
describe('item',function(){
it('should return same item id',function(){
$httpBackend.expectGET(API_URL+'items/1').respond({id:1});
var result = ItemService.item.get({id:1});
$httpBackend.flush();
expect(result.id).toEqual(1);
});
});
But the problem is that this test fails for some strange reason:
Error: Unexpected request: GET modules/home/partials/home.html
No more request expected
at $httpBackend
And when I add slash to $httpBackend URL like this:
$httpBackend.expectGET(API_URL+'/items/1').respond({id:1});
It throws following expection:
Error: Unexpected request: GET /app/api/items/1
Expected GET /app/api//items/1
at $httpBackend
Note double slash in expected GET.
How to fix it?
Update:
Code from ItemService:
var itemService = angular.module("ItemServiceModule", []);
itemService.factory("ItemService", [ "$resource", "API_URL", function($resource,API_URL) {
var itemService = {
item: $resource(API_URL+'items/:id', {})
};
return itemService;
}]);
Update2:
If I change httpBackend url like this (just add localhost and not adding slash before items):
$httpBackend.expectGET('http://localhost:8080'+API_URL+'items/1').respond({id:1});
Then the error is:
Error: Unexpected request: GET /app/api/items/1
Expected GET http://localhost:8080/app/api/items/1
at $httpBackend
Update3:
If I for example hard code that API_URL like this:
var url = 'app/api/items/1';
$httpBackend.expectGET(url).respond({id:1});
The error is:
Error: Unexpected request: GET /app/api/items/1
Expected GET app/api/items/1
at $httpBackend
But when I add slash at the begining of url, then it requests home partial modules/home/partials/home.html as with API_URL.
Error: Unexpected request: GET modules/home/partials/home.html
No more request expected
at $httpBackend

It turned out that the problem was with ui-router. Namely, the following configuration:
$urlRouterProvider.otherwise("/");
I just needed to eliminate this configuration in the tests:
beforeEach(module(function ($urlRouterProvider) {
$urlRouterProvider.otherwise(function(){return false;});
}));
Found this solution on https://github.com/angular-ui/ui-router/issues/212

Related

AngularJS $http error No more request expected

I m trying to connect my angular front end with Jenkins API.
my service.js
angular.module('jenkinsLightApp')
.factory('JenkinsService', function (CONFIG, $location, $http, $httpBackend) {
return {
getJobs: function () {
var viewParameter = 'All';
if ($location.search().view) {
// Set the value of the view query parameter
viewParameter = $location.search().view;
}
// Call Jenkins API
var promise = $http({method: 'GET', url: 'http://xx.xx.xxx.xxx:xxxx/pic/view/All/api/json'}).
then(function successCallback(response) {
alert('promise');
// Initialize jobs data
var data = response.data;
var jobs = [];
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
};
I have removed the authentication from jenkins, so angular can be able to connect.
But I have the following error:
Error: Unexpected request: GET http://xx.xx.xxx.xxx:xxxx/pic/view/All/api/json
No more request expected
$httpBackend#http://localhost:9000/bower_components/angular-mocks/angular- mocks.js:1180:1
sendReq#http://localhost:9000/bower_components/angular/angular.js:8442:1 http/serverRequest#(http://localhost:9000/bower_components/angular/angular.js:8162:16qFactory/defer/deferred.promise.then/wrappedCallbackhttp://localhost:9000/bower_components/angular/angular.js:11722:3
I have also tried to add
$httpBackend.whenGET(/pic/).passThrough();
that removed the error but I m still unable to dislplay any jenkins job in the browser.
Thanks for your help

Unexpected Request Error with $HttpBackend (AngularJS)

I am using HttpBackend to mock some Http responses for some calls that my Angular app is making.
However, I am getting the error "Unexpected Request: [object Object] undefined" when I run my tests.
I know that usually this error means you're missing or mistyped one of the $http requests that the app makes so it can't find a response. But my error is not specific like the other ones which usually say like "Unexpected Request: GET api/call" so I don't know what is wrong.
Has anyone ever encountered this specific error before?
Sample Code
angular controller:
app.controller( 'ctrl',
[ '$scope' , '$http' , '$location', function( $scope, $http, $location ) {
$http.get(
"/api/1.0/id/" + id,
{
headers: getAuthHeaders()
}
).success(function( data ){ //... })]
);
jasmine test:
it('should ...', function(){
httpBackend.whenGET('/api/1.0/id/*').respond(200,{"test":"Test"});
//...
});
I tried your code and test by myself. I add a function to set the ID, but I think you have something simular:
//PRESET ID
var id = 'deajedgwe1e213df';
//FUNCTION TO CAPSULATE API CALL
this.callApi = function () {
http.get(
"/api/1.0/id/" + id,
{
//headers: getAuthHeaders()
}
).success(function( data ){
console.log('success', data);
}).error(function (err) {
console.log('error', err);
});
};
//FUNCTION TO SET ID
this.setId = function (ID) {
id = ID;
};
then I copied your test and modified it like this:
it('should ...', function(){
ctrl.setId('test123ID');
httpBackend.expectGET('/api/1.0/id/test123ID').respond(200,{"test":"Test"});
ctrl.callApi();
httpBackend.flush();
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
this works. alternative you could do this:
it('should ...', function(){
httpBackend.expectGET(/api/i).respond(200,{"test":"Test"});
ctrl.callApi();
httpBackend.flush();
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
this works too, but it only verifies, that /api has been called... I don't if this is that, what you want to test.
I think the major problem is your asterisk notation at the api-call. try to modify your code like mine. if this shouldn't help, you should have a call on your header function.
Good luck.

Use token from localStorageService with interceptor

I'm very new to Angular, so it's perfectly possible I made some stupid mistakes.
What I'm trying to do is use a token that is saved in localStorage and put that in all requests.
I have this code block:
.config(['$httpProvider', 'localStorageService', function($httpProvider, localStorageService) {
//Http Interceptor to check auth failures for xhr requests
$httpProvider.interceptors.push('authHttpResponseInterceptor');
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.headers.common.Authorization = 'Token token=' + localStorageService.get("TemponiaToken")
}])
And I'm getting this error message:
Uncaught Error: [$injector:modulerr] Failed to instantiate module starter due to:
Error: [$injector:unpr] Unknown provider: localStorageService
I found this question and answer which (I think) explains the problem: Why can't I use the localStorage in my .config when it's include in the .module definition?
However: how can I solve this? Change the .config into .run ? Thanks for any pointers in the right direction.
As the answer you found says is not possible to inject services during the config phase.
There are two possible solution to your problem.
The first one is to use the native localStorage object
localStorage.getItem("TemponiaToken") // it just works without injecting any service
The other one is to correctly define the interceptor
yourApp.factory('AuthInterceptor', function (localStorageService) {
return {
request: function (config) {
config.headers = config.headers || {};
config.headers.Authorization = 'Token token=' + localStorageService.get("TemponiaToken")
return config;
}
};
});
yourApp.config(function ($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
});
The documentation of ngStorage says thus:
Usage from config phase
To read and set values during the Angular config phase use the .get/.set functions provided by the provider.
var app = angular.module('app', ['ngStorage'])
.config(['$localStorageProvider',
function ($localStorageProvider) {
$localStorageProvider.get('MyKey');
$localStorageProvider.set('MyKey', { k: 'value' });
}]);

angular how to pass in http dependency?

trying to call an angular service from my ngapp in my jasmine script:
it('should create client', function () {
browser.executeAsyncScript(function(callback) {
var api = angular.injector(['$http','myservices']).get('custService');
api.saveClient({name:'Ted'},function(data){
console.log(data);
callback(data);
});
});
});
My question is how can I pass in the http dependency because now I am getting this error:
UnknownError: javascript error: [$injector:modulerr] Failed to instantiate module $http due to:
Error: [$injector:nomod] Module '$http' is not available! You either misspelled the module name or forgot to load it.
You should use mock data instead of creating a real object.
Doing a real http request is not a good idea.
Use mocking in the responses as #merlin said in the comments. Try to use $httpBackend to mock your response.
A quote from the documentation :
$http service sends the request to a real server using $httpBackend service
You can inject your mock there like in the example :
beforeEach(
inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
authRequestHandler = $httpBackend.when('GET', '/auth.py')
.respond({userId: 'userX'}, {'A-Token': 'xxx'});
// ...
}
If you need the http service anyway, you should inject it like the following
var myHttpService;
beforeEach( inject(function($http) {
myHttpService = $http;
}));
After that you can expect a http GET for example to happen. You should call the $httpBackend.flush because in a test scenario it won't run async and $http uses promises in the background. See examples in the documentation.

AngularJS $httpBackend - "No more request expected" error

It seems this is working solution that shows how to work with $httpBacked http://jsfiddle.net/EgMpe/8/
But for my case:
routes
app.config(['$routeProvider', function($routeProvider) { $routeProvider.
when('/', {templateUrl: 'partials/user-list.html'}).
...
faked service:
app.run(function($httpBackend) {
var users = [{"id":1,"name":"bob","email":"bob#bobs.com"}, {"id":2,"name":"bob2","email":"bob2#bobs.com"}]
$httpBackend.whenGET('/rest/users').respond(function(method,url,data) {
console.log("Getting users");
return [200, users, {}];
});
});
..
real service:
services.factory('Users', function($resource){
return $resource('/rest/users', {}, {
get: {method: 'GET', isArray:true}
});
});
I have error when go to my "/" route that redirects me to user-list.html page:
Error: Unexpected request: GET partials/user-list.html No more request
expected
at $httpBackend .../mysite/public/angular/libs/angular-1.2.0/angular-mocks.js:1060:9)
Question1: Does httpBackend prevent doing any other http request?
I tried to use passThrough method to let http hit real server side:
$httpBackend.whenGET(/^\/mysite\//).passThrough();
But this does not help.
Using $httpBackend you have to specify in advance all request you are going to perform. Maybe this short excerpt from Mastering Web Application Development with AngularJS will clarify why:
The verifyNoOutstandingExpectation method verifies that all the expected
calls were made ($http methods invoked and responses flushed), while the
verifyNoOutstandingRequest call makes sure that code under test didn't trigger
any unexpected XHR calls. Using those two methods we can make sure that the code
under the test invokes all the expected methods and only the expected ones.
Ah.. Sorry I just was wrong with my RegEx:
if type this $httpBackend.whenGET(/partials/).passThrough();
Then all start working.
So, I got my lesson: don't forget to put: passThrough(); with right RegEx.

Resources