$httpBackend: Angular Unit-Testing that a GET request is sent - angularjs

I'd like to test that a (component's) controller is sending a GET request to some URL (without caring about the response). I was expecting that
httpBackend.expectGET('/some/random/url');
would spy on the http backend and fail if it did not get the GET request, so I was expecting the following spec to fail:
describe('myApp', function() {
var httpBackend;
beforeEach(module('myApp'));
beforeEach(inject(function($httpBackend) {
httpBackend = $httpBackend;
}));
it('sends a GET request to /some/random/url', function() {
httpBackend.expectGET('/some/random/url');
httpBackend.expect('GET', '/some/random/url');
});
});
But this seems to pass trivially
Starting the Teaspoon server...
Teaspoon running default suite at http://127.0.0.1:56255/teaspoon/default
..
Finished in 0.01200 seconds
2 examples, 0 failures
with this:
angular.module('myApp', []);
So I suppose I am misunderstanding what expectGET is doing and this is not the way the way to check what I am trying to check.

I usually add the following code to any spec (test) files deal with http mocking. This makes sure that the call is flushed and that there are no outstanding expectations / requests.
afterEach(() => {
try {
$httpBackend.flush();
} catch (e) {
}
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
This would change your code like so
describe('myApp', function() {
var httpBackend;
beforeEach(module('myApp'));
beforeEach(inject(function($httpBackend) {
httpBackend = $httpBackend;
}));
afterEach(() => {
try {
httpBackend.flush();
} catch (e) { // entering here is a sign your unit test failed
}
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
it('sends a GET request to /some/random/url', function() {
httpBackend.expectGET('/some/random/url');
httpBackend.expect('GET', '/some/random/url');
});
});

You forgot to call flush() on httpBackend. That's when it will check that all the expected requests have been received.

Related

Jasmine. Angular Services. Angular Promises. How to make them play together?

I was following this example.
We have test suite like:
describe('Basic Test Suite', function(){
var DataService, httpBackend;
beforeEach(module('iorder'));
beforeEach(inject(
function (_DataService_, $httpBackend) {
DataService = _DataService_;
httpBackend = $httpBackend;
}
));
//And following test method:
it('should call data url ', function () {
var promise = DataService.getMyData();
promise.then(function(result) {
console.log(result, promise); // Don't gets here
}).finally(function (res) {
console.log(res); // And this is also missed
})
})
});
How to make jasmine + karma work with angular services, that returns promise?
I have seen this question, but looks like it's about using promises in test cases. Not about testing promises.
You need to tell jasmine that your test is asynchronous so that it waits for the promises to resolve. You do this by adding a done parameter to your test:
describe('Basic Test Suite', function(){
var DataService, httpBackend;
beforeEach(module('iorder'));
beforeEach(inject(
function (_DataService_, $httpBackend) {
DataService = _DataService_;
httpBackend = $httpBackend;
}
));
//And following test method:
it('should call data url ', function (done) {
var promise = DataService.getMyData();
promise.then(function(result) {
console.log(result, promise); // Don't gets here
done();//this is me telling jasmine that the test is ended
}).finally(function (res) {
console.log(res); // And this is also missed
//since done is only called in the `then` portion, the test will timeout if there was an error that by-passes the `then`
});
})
});
By adding done to the test method, you are letting jasmine know that it is an asynchronous test and it will wait until either done is called, or a timeout. I usually just put a call to done in my then and rely on a timeout to fail the test. Alternatively, I believe you can call done with some kind of error object which will also fail the test, so you could call it in the catch.

Calling a method from an injected service in Jasmine

I'm attempted to unit test a service. I've injected the service however the method call getAllProducts() doesn't appear to run however the test still passes!
Plnkr
service.js
angular.module('vsApp')
.factory('productsDataService', function($http) {
var service = {
getAllProducts: getAllProducts
};
// get all products
function getAllProducts() {
return $http.get('/apiv1/getAllProducts/').then(function(data) {
return (data);
});
}
return service;
});
spec.js
// jasmine
describe('products data service', function () {
var $httpBackend, productsDataService;
beforeEach(module('vsApp'));
beforeEach(inject(function(_$httpBackend_, _productsDataService_) {
$httpBackend = _$httpBackend_;
productsDataService = _productsDataService_;
}));
it('should get all products', inject(function() {
console.info("get all");
// mock response for the http call in the service
$httpBackend.when('GET', '/apiv1/getAllProducts/')
.respond({name: 'item', price: '932'});
//this doesn't seem to run??
productsDataService.getAllProducts().then(function(response) {
expect(response.data.length).toBeGreaterThan(1);
});
}));
});
Ok, you have to make it sync. (all pending request will get resolved) using $http.flush();
Working demo as expected
productsDataService.getAllProducts().then(function(response) {
console.log(response);
expect(response.data.length).toBeGreaterThan(999);
});
$httpBackend.flush(); // <=============== here.

Fixing unexpected GET request in service unit test

In my unit test for a service, I'm testing a GET request. I'm getting the following error, even when I explicitly state $httpBackend.expectGET('/api/example').respond(200, {});.
Error: Unexpected request: GET /api/another/example
Expected GET /api/example
Unit test
describe('MyService', function() {
var MyService,
$httpBackend;
beforeEach(module('example'));
beforeEach(function() {
inject(function(_MyService_, _$httpBackend_) {
MyService = _MyService_;
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('/api/example').respond(200, {});
});
})
describe('#get', function() {
beforeEach(function() {
// this is what i want to test
$httpBackend
.expectGET('/api/another/example')
.respond(200, {});
});
it('should send a get request', function() {
MyService.get();
$httpBackend.flush();
});
});
});
I can't see the content of your MyService.get() function, but I'll go ahead and assume it's calling GET /api/another/example.
If I remember correctly, you have to serve your expected requests on $httpBackend in the order you list them.
Assuming both beforeEach segments get triggered you would have to set off a GET request against /api/example before you can access GET /api/another/example.

Why unit testing response is always successful?

I was reading posts related for don't repeat the question.
I have the next unit testing code:
describe('service', function() {
var questionApiService;
beforeEach(module('myApp'));
beforeEach(inject(function (_questionApiService_) {
questionApiService = _questionApiService_;
}));
// Test service availability
it('check the existence of get field question service', inject(function(questionApiService) {
//expect(1).toEqual(100);
questionApiService.getField()
.then(function(data) {
//console.log(data);
expect(1).toEqual(100);
});
}));
});
If I run the code expect(1).toEqual(100); outside the service, the result is Error, but if I write the same code expect(1).toEqual(100); inside the service, the result is Success, which makes me think that the validator is not entering the service.
Whats wrong?
EDIT 1:
Hello Asta, I think ur idea is very good and i'm trying to implement it. I have an error in my code and i don't know how do debugging:
defer = $q.defer();
spyOn(questionApiService, 'getField').andReturn(defer.promise);
defer.resolve(data);
expect(data.nextQ).toEqual(1);
My unit testing always fails. If promise is successful, the "data" object must have nextQ attribute.
EDIT 2:
Hi Asta, your code is amazing. I'm trying to execute your code in my system and still with error. The ut fails:
Error: Unexpected request: GET http://mi.url.com/api/thefield No more request expected
Do u know what's wrong? Clarify that the code works fine on my application but ut is the problem.
Question Api Service code:
angular.module('myApp.services')
.factory('questionApiService', function($http, $q) {
var myService = {
getField: function() {
var defer = $q.defer();
$http.get('http://mi.url.com/api/thefield')
.success( function(data) {
defer.resolve(data);
})
.error( function(data) {
defer.reject(data);
});
return defer.promise;
};
return myService;
});
Your test:
describe('myApp', function () {
beforeEach(function () {
module('myApp');
});
describe('questionApiService', function () {
it('should check the existence of get field question service', inject(function($rootScope, questionApiService) {
var response = null;
var promise = questionApiService.getField();
promise.then(function(data) {
response = data;
});
$rootScope.$apply();
var expectedResponse = { "nextQ": 1 };
console.log(response);
//expect(JSON.parse(response.nextQ)).toEqual(expectedResponse.nextQ);
}));
});
});
I think you just need to move your expectation outside the then and do a $rootScope.$apply().
it('should check the existence of the get field question service', inject(function($rootScope, questionApiService) {
response = null;
promise = questionApiService.getField()
promise.then(function(data) {
response = data;
});
$rootScope.$apply();
expectedResponse = { "nextQ": "value" }
expect(JSON.parse(response)).toEqual(expectedResponse);
}));
I created a jsFiddle you can use to play around with. It sets up a service that returns JSON via a promise which I used to test http://jsfiddle.net/neridum/9uumwfzc/
Alternatively if you want to test this service from another service you can mock it out using spies. Here you would mock the response as a promise and then resolve it
defer = $q.defer();
spyOn(questionApiService, 'getField').andReturn(defer.promise);
defer.resolve(data);
expect(data).toEqual('100');

Angular Unit test fails with Error: Unexpected request: GET

I am new to angularjs testing and have been trying to run this test but it fails with same error again and again. I have viewed questions here and read the docs but haven't got to the cause of this error.
A help will be greatly appreciated. Thanks in advance.
my service.js
'use strict';
var services = angular.module('services',['ngResource'])
services.factory('callAppsList',['$resource',function($resource){
return $resource('/api/apps/:appId', {}, {
query: {method:'GET', isArray:false},
get: {method:'GET', isArray:false},
});
}])
serviceSpec.js
//serviceSpec testing
describe("Testing service", function() {
beforeEach(module('services'));
var service, $httpBackend, response;
var url = 'http://0.0.0.0:5000/api/apps/a365cc3520c7a70a553e95ee354670264'
beforeEach(inject(function( _$httpBackend_, callAppsList) {
$httpBackend = _$httpBackend_;
res = { msg :'name'};
service = callAppsList;
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
//tests
it("callAppsList should be defined", function () {
expect(service).toBeDefined();
});
it('should send a ping and return the response',(function () {
res = service.get({appId: 'a365cc3520c7a70a553e95ee354670264'});
$httpBackend.whenGET(url).respond(res);
$httpBackend.expectGET(url)
$httpBackend.flush();
//expect(res.msg).toEqual('name');
}));
});
the first test (when I am testing if it is defined passes) but the next one fails.
error :
Error: Unexpected request: GET /api/apps/a365cc3520c7a70a553e95ee354670264
Expected GET http://0.0.0.0:5000/api/apps/a365cc3520c7a70a553e95ee354670264 in /home/anurag/anurag/projects/betablide/applunge/glide/static/test/lib/angular-mocks.js (line 1179)
A flask server is running in another terminal.
Please let me know what I am doing wrong here and how to proceed further.
As mentioned in the comments, changing the url worked out. I have also changed new lines in the spec file. Hope this may help others.
//serviceSpec testing
describe("Testing service", function() {
beforeEach(module('services'));
var service, $httpBackend, response;
var url = '/api/apps/a365cc3520c7a70a553e95ee354670264'
beforeEach(inject(function( _$httpBackend_, callAppsList) {
$httpBackend = _$httpBackend_;
service = callAppsList;
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
//tests
it("callAppsList should be defined", function () {
expect(service).toBeDefined();
});
it('should send a ping and return the response',(function () {
res = service.get({appId: 'a365cc3520c7a70a553e95ee354670264'});
$httpBackend.whenGET(url).respond({status: 200});
//explicitly flushes pending requests
$httpBackend.flush();
expect(res.status).toEqual(200);
}));
});

Resources