3

I'm not entirely sure how to do this but I have a endpoint URL which is a POST request for login authentication. When you add a request payload, you will get either a successful login credential or an error. However, I seem to have problems with fetching the response.

Here is my spec file:

describe('Service: AuthFactory',function(){

    beforeEach(function () {
        module('ui.router');
        module('users');
        module('main');
    });

    var AuthFactory, httpBackend;

    beforeEach(inject(function($httpBackend, $rootScope, $controller, _AuthFactory_){
        httpBackend = $httpBackend;
        AuthFactory = _AuthFactory_;

    }));

    it('Return a POST response from a Service function', function() {
        var url = "http://localhost:3000";
        var dataObj = JSON.stringify({
            inputUser: { user: "TestCase1" },
            inputPass: { password: "TestPass1" }
        });
        httpBackend.expect('POST', url + '/api/AuthService/signIn', dataObj)
            .respond({});

        AuthFactory.signIn(dataObj).success(function(response) {
            console.log(response);
            // outputs Object {}
            // when in reality it should
            // output the response to POST
            // eg: { "login": { "user": "Test_User", "time": 54935934593 }, "outputHead": { "token": asjfjj234kfAd } }
        });

        httpBackend.flush();

        expect(true).toBe(true);
    });
});

and here is my Service.

angular.module('users').factory('AuthFactory', ['$http', function($http) {

var AuthFactory = {};

AuthFactory.signIn = function(data) {
    return $http.post('http://127.0.0.1:3000/api/AuthService/signIn', data);
};

AuthFactory.signOut = function(data) {
    return $http.post('http://127.0.0.1:3000/api/AuthService/signOut', data);
};

return AuthFactory;

}]);

When I run the test, it passes (obviously) but the console.log() outputs Object{}.

And when I use a Chrome extension like Postman. I do an example POST request and the response that returns is the login credentials! So why is it working on Postman but not on my AngularJS Jasmine unit test?

isherwood
  • 58,414
  • 16
  • 114
  • 157
red
  • 305
  • 1
  • 4
  • 15

3 Answers3

4

This line is why you get an empty object as your response:

httpBackend.expect('POST', url + '/api/AuthService/signIn', dataObj)
        .respond({});

To give the response you want just add the following:

httpBackend.expect('POST', url + '/api/AuthService/signIn', dataObj)
            .respond({"login": { "user": "Test_User", "time": 54935934593 }, "outputHead": { "token": asjfjj234kfAd }});

See the documentation for more information.

br3w5
  • 4,403
  • 5
  • 33
  • 42
  • 2
    I see. Wait.. if you're faking a response of the service... then what exactly are you testing? I thought that was the whole point. – red Jan 11 '16 at 21:10
  • You're testing that your service performs in a specific way so you mock the response to control the test – br3w5 Jan 11 '16 at 21:11
  • So you could test how your service responds when an empty object is returned vs when a successful response vs an error response – br3w5 Jan 11 '16 at 21:11
  • 1
    Unit tests should test the unit under test i.e. the service in your case. It shouldn't test the server's response - that's called an integration test – br3w5 Jan 11 '16 at 21:12
  • What if the service method has multiple parameters and not a single object – AMRESH PANDEY May 26 '17 at 07:50
  • @AMRESHPANDEY i'm not sure what you mean. `POST` methods you typically send a single object for the post body that contains as many key value pairs as you like (encapsulated in the above example within `dataObj`). If you want to use a query string then your expectation would look like `('POST', url + '/api/AuthService/signIn?some=param')` (see https://stackoverflow.com/questions/611906/http-post-with-url-query-parameters-good-idea-or-not). – br3w5 May 26 '17 at 08:04
  • Thanks using a query string worked for me. Actually function takes multiple parameters. So, using query string is a good approach. – AMRESH PANDEY May 26 '17 at 12:29
1

The main thing to remember is that you are mocking the backend service request, and not actually hitting the service. This is done with this statement:

httpBackend.expect('POST', url + '/api/AuthService/signIn', dataObj)
    .respond({});

What this says is for a POST that matches this url, fake a response with an empty object. If you want to fake a response that looks like your real response, you can simply set up that object in the .response function call.

Example:

.respond({login:myuser,authenticated=true}).

If you are trying to test your backend API, you will want to look into other testing frameworks, such as protractor;

isherwood
  • 58,414
  • 16
  • 114
  • 157
  • Wait.. if you're faking a response of the service... then what exactly are you testing? I thought that was the whole point... – red Jan 11 '16 at 21:09
  • You are testing the fact that the service did the post to the correct URL. – Brandon Short Jan 11 '16 at 21:12
0

You are mocking your backend with the $httpBackend service, that means, there won't be a real request, but when you post to url + '/api/AuthService/signIn' your mocked backend will respond with an empty object (.respond({})) You should respond with the same kind of data that your real backend gives back. The main point is, you have the control of what cases are you want to cover with your test. So you can write API response for failed or successful logins

if you do a request in postman, that is going to use your real backend, that is the difference

more info: https://docs.angularjs.org/api/ngMock/service/$httpBackend http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html

Ins
  • 808
  • 6
  • 13