Unit testing a factory with angularjs and acute reaching the API - angularjs

I want to unit test a $resource but actually reach the REST API and get it's respone. So, I don't want to mock it.
I am very new to unit testing and here is what I did:
describe('Factory: PartnersResource', function () {
var PartnersResource,
$httpBackend;
beforeEach(module('app'));
beforeEach(inject(function (_PartnersResource_, _$httpBackend_) {
PartnersResource = _PartnersResource_;
$httpBackend = _$httpBackend_;
}));
it('when post, it should query all partners and return them', function () {
var result = PartnersResource.query();
$httpBackend.flush();
});
});
It does not work obviously :)
Error: Unexpected request: GET https://www-dev.mysite.com/film/partner
No more request expected
The resource works, normally but it won't in this unit test.
I use ngMocks to simulate a fake back-end for modules of the app I am working, ahead of the API.
I have setul the mocks to allow calls to my url:
$httpBackend.whenGET(/www-dev/).passThrough();
Can anyone help?

Related

Accessing $httpBackend in Jasmine it block

Please see my code example below, I have a protractor test that get's run as a GULP task by angular-protractor.
I want to be able to mock some REST calls for all it blocks, but also have access to the httpBackend for specific it blocks.
I'm having trouble sharing the $httpBackend variable around though:
I can't use this.VARIABLE_NAME because of the scope I am in inside the run function.
Code Example
describe('Train Station Search Component', function() {
beforeEach(function() {
//Mock any REST calls here.
browser.addMockModule('httpBackendMock', function() {
angular.module('httpBackendMock', ['MyApp', 'ngMockE2E'])
.run(function($httpBackend) {
//Mock call relevant to both it blocks.
$httpBackend.whenPOST(/^(.*\/api\/search)/).respond({...});
});
});
);
it('should check one piece of functionality', function() {
//Expect call with data relevant only for this it block.
$httpBackend.expectPOST(...);
});
it('should check another piece of functionality', function() {
//Expect call with data relevant only for this it block.
$httpBackend.expectPOST(...);
});
};
Any help appreciated.
You can use $injector to inject $httpBackEnd service.
var $httpBackend
beforeEach(inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
});
Go through the link https://docs.angularjs.org/api/ngMock/service/$httpBackend

AngularJS testing with Jasmine

I'm a newbie to programming and I'm trying to figure out how to unit test angularJS code with jasmine, and its driving me insane!
This is the angular code im trying to test, its all set up on an asp.net web application using abpBoilerplate and angular. The result of the code below is that when a button is clicked on the web page, a 'success' popup appears and "true" appears in a text box, if the service is available. The service is being pulled from classes within a web api project.
(function() {
var controllerId = 'app.views.home';
angular.module('app').controller(controllerId, [
'$scope', 'abp.services.lfcservice.webapi', function($scope,lfcServices) {
var vm = this;
//Home logic...
vm.CheckLfcIsAvailable = function () {
lfcServices.lfcIsAvailable()
.success(function () {
abp.notify.info('Success');
vm.Available = 'True';
});
};
I just need to know how to write a jasmine test that passes when it expects a true value for the lfc service. Ive tried loads of different combinations with no success, I could paste in 10 different attempts ive had in here but they are all very different.
Any help would be much appreciated!
First, you need to know how to test a controller, mocking the service.
Then, you need to mock the service API to return a promise.
let's say thet the controller is initiated with Available = false;.
Test an angular 1.x controller (see jsFiddle):
describe("app.views.home controller spec", function() {
var ctrl;
//depend on the module
beforeEach(module('app'));
beforeEach(inject(function($controller) {
//use angular's "$controller" to get the controller
ctrl = $controller("app.views.home");
}));
it("available should be false", function() {
expect(ctrl.Available).toBe(false);
});
});
Now, let's asume that the service returns a simple result (without promises) and see how do we provide a mock service instead of the real service.
Test an angular 1.x controller with mock service (see jsFiddle):
beforeEach(module(function($provide) {
var mockService = jasmine.createSpyObj('mock', ['lfcIsAvailable']);
mockService.lfcIsAvailable.and.returnValue(true);
$provide.value('abp.services.lfcservice.webapi', mockService);
}));
Now, let's see how to mock a promise response. for this we will use $q.
Mock angular 1.x promise (see jsFiddle):
it('should change after promise resolved', inject(function($q, $rootScope) {
//create promise
var deferred = $q.defer();
//mock service response
mockService.lfcIsAvailable.and.returnValue(deferred.promise);
//call CheckLfcIsAvailable ()
ctrl.CheckLfcIsAvailable ();
expect(ctrl.Available).toBe(false);
deferred.resolve(true);
//not yet...
expect(ctrl.Available).toBeNull(false);
//from angular $q documentation:
//"it's important to know that the resolution of promises is tied to the digest cycle"
$rootScope.$apply();
//now!
expect(ctrl.Available).toBe(true);
}));

Verifying a call on $httpBackend in angularjs test

I am trying to write a test for angularjs which is mocking $httpBackend. Following is the test.
describe('test', function() {
beforeEach(function (){
module('abcApp');
});
var $httpBackend, filterService;
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
filterService = $injector.get('filterService');
}));
it('getCompany calls get on http with correct parameter', function () {
$httpBackend.when('GET', 'api/Abc').respond([]);
filterService.getAbc();
$httpBackend.flush();
expect($httpBackend.get).toHaveBeenCalled();
});
});
when I run the test I get the following error:-
Error: Expected a spy, but got undefined.
Any ideas how I would I assert that $httpBackend.get have been called with required parameter using expect.
expect($httpBackend.get).toHaveBeenCalled();
is invalid. First because $httpBackend doesn't have any (documented) get() method. Second, because $httpBackend.get is not spied by Jasmine, so you can't add Jasmine if this method has been called.
You should just test that, given the empty array returned by the http backend, the service returns the right thing, or has the desired side effect. You could also use
$httpBackend.expectGET('api/Abc').respond([]);
and
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
so that $httpBackend verifies for you that the expected request has been sent.

How to test $http without mock with jasmine and angular-mocks?

I want to make an integration test with real calls to my server, so, I don't want to use the $httpBackend module from angular-mocks, So I try this:
beforeEach(inject(function($rootScope,_MembersDataSvc_){
service = _MembersDataSvc_;
}));
it('test',function(done){
service.me().then(function(){done();});
});
And the service is:
function me() {
return $http
.get('urlBase/me')
.then(meSuccess);
function meSuccess(response) {
return response.data.members[0];
}
}
This never call the $http, it seems that angular-mocks override the $http service an never made the call.
Some ideas?
EDIT 1:
According to this post: http://base2.io/2013/10/29/conditionally-mock-http-backend/
you can make a passThrough for that $http calls that you don't want to mock, so y try this:
var service;
var scope;
var $httpBackend;
beforeEach(inject(function($rootScope,_MembersDataSvc_,_$httpBackend_){
service = _MembersDataSvc_;
scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
}));
it('test',function(done){
//this.timeout(10000);
$httpBackend.whenGET(/views\/\w+.*/).passThrough();
$httpBackend.whenGET(/^\w+.*/).passThrough();
$httpBackend.whenPOST(/^\w+.*/).passThrough();
service.me().then(function(response){console.log(response);done();});
scope.$apply();
//service.getDevices(member).then(function(response){console.log(response);done();})
});
But the passThrough is undefined here.
EDIT 2:
I read this post: http://blog.xebia.com/2014/03/08/angularjs-e2e-testing-using-ngmocke2e/, but I supose that is an stanalone test??, I want to run with karma and jasmine.
This is my entire test.
describe('integration test', function () {
beforeEach(function () {
module('MyAngularApp');
});
var service;
var scope;
var $httpBackend;
beforeEach(inject(function($rootScope,_MembersDataSvc_,_$httpBackend_){
service = _MembersDataSvc_;
scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
}));
it('test for test',function(done){
$httpBackend.whenGET(/views\/\w+.*/).passThrough();
$httpBackend.whenGET(/^\w+.*/).passThrough();
$httpBackend.whenPOST(/^\w+.*/).passThrough();
service.me().then(function(response){console.log(response);done();});
scope.$apply();
});
});
I recomend using ngMidwayTester that allows you to connect to the real backend, I use it to make integration tests on the code level - so something in between unit and e2e testing:
Two types of tests in AngularJS (plus one more) - Full-Spectrum Testing with AngularJS and Karma

How to check the http request in unit testing?

I am trying to write an unit test for my app. It contains http request call in my case.
Test file
'use strict';
describe('Controller: testCtrl', function () {
// load the controller's module
beforeEach(module('myApp'));
var testCtrl, scope, $httpBackend;
beforeEach(inject(function (_$controller_, _$rootScope_, _$httpBackend_, $cookies) {
scope = _$rootScope_.$new();
$httpBackend = _$httpBackend_;
testCtrl = _$controller_('testCtrl', {
$scope: scope,
});
}));
it("should return product data", function() {
$httpBackend.whenGET('/api/store/' + productID + '/products').respond([{
//not sure what I should do next...
}])
})
controller file
$http.get(('/api/store/' + productID + '/products').success(
function(data) {
//the data could contain 10 objects with 10+ property within each object.
}
);
Since the http request return a very complex object, I am not sure how to write my test. Can anyone help me about it? Thanks a lot!
You assume that your API works correctly, and what you're trying to actually test is:
does your app respond to the URL it should?
does it do any processing of th data it should?
So return a mock object in your whenGET, with enough detail for any data processing code.
As far as the test goes, you will have to return a mock object response. That being said, you do not need to pollute your test case with your 1000 line mock JSON. Simply save it in a separate file and use karma-ng-json2js-preprocessor to return it from the whenGET.

Resources