2

I'm testing a callback function which accepts a response object as it's only parameter. This object is the response of a HTTP request made elsewhere so I don't want to user $httpBackend in this test as the request has nothing to do with this function.

It's in home.js which is a controller for the homepage of my app.

Here is the function being tested:

 function submitLogin() {
      LoginService.login(loginPost, ctrl.username, ctrl.password, successCallback, errorCallback);
  }

// gets called in LoginService if login reponse is 201, otherwise errorCallback called
function successCallback(response) {
    // get details needed to determine correct forms for user
    var sessionData = {
      token: response.data.token,
      user_id: response.data.user_id,
      institution_name: response.data.institution_name,
      status: response.data.status,
      form_uri: getFormURI(response.data.forms) //extracts form URI for list of available forms for particular app
    };

    ctrl.formCheckInProgress = true;

    // update users forms from backend and cache them
    FormFetcherService.updateCachedForms(sessionData.user_id, sessionData.form_uri).then(function (response) {
      if (response == 'updated') {
        toastr.success('Your forms have been updated to the newest version', 'Forms Updated');
      }
      else {
        toastr.success('Your forms are already up-to-date', 'No Update     Required');
      }
    });

}

Login Service:

    angular.module('appName').service('LoginService', ['$http', function     ($http) {
    this.login = function (url, username, password, successCallback, errorCallback) {
        var data = {
            username: username,
            password: password
        };

        $http.post(url, $.param(data), {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                },
                timeout: 10000
            }
        ).then(successCallback, errorCallback);
    }
}]);

I want to load an object which will take the place of the 'response' object being passed into the function.

Is there any way I could put a .json file in my /tests directory, load the JSON and parse it into a Javascript object and then use said object in my unit test?

I've searched around and most solutions assume a request is being made in the function being tested - which isn't the case here.

Cheers,

Dean

10
  • show your controller's code, and you can mock $http service Commented Nov 4, 2016 at 17:59
  • Edited to show function from controller being tested. Commented Nov 4, 2016 at 18:04
  • show where this function is referenced in code Commented Nov 4, 2016 at 18:05
  • and now show LoginService.login :) Commented Nov 4, 2016 at 18:10
  • Done - successCallback gets called from LoginService if response code is 201. The response object is passed to the successCallback from within LoginService. So to test the successCallback it would be easier to just pass an objected loaded and parsed from a local .json file. Commented Nov 4, 2016 at 18:10

2 Answers 2

1

@dean-sherwin Though this might not actually answer the question, I'd like to share the piece of code that I've been using to load the json from a file for jasmine testing because:

  • not always do you want to keep the huge json data in one test spec
  • helps in sharing that json data across multiple specs if need be

spyOn(SomeClass, 'someMethod').and.returnValue( $.ajax({ url: "somefolder/anotherfolder/theJSONFile.json", async: false, dataType: "json" }).then(function(data) { return data }) );

Sign up to request clarification or add additional context in comments.

Comments

0

You can do it like this:

var LoginService, $controller;

var formFetcherService = {
    updateCachedForms: jasmine.createSpy('sessionData');
}

var response = {
    data: {
        user_id: 4,
        forms: 'some'
    }
}

beforeEach(module(function($provide) {
    $provide.value('LoginService', {
        login: function(url, username, password, successCallback, errorCallback) {
            successCallback(response);
        }
    });

    $provide.value('FormFetcherService', formFetcherService);
}))

beforeEach(inject(function(_$controller_) {
    $controller = _$controller_;
});

it('should create sessionData', function() {
    var controller = $controller('HomeController');
    controller.submitLogin();
    expect(formFetcherService.updateCachedForms).toHaveBeenCalledWith(response.user_id, response.form_uri);
});

5 Comments

Thank you for the help so far. I really appreciate it. But is this not just a more complicated way of hard coding the JSON into the unit test file? The actual response of huge (hundreds of fields) which is why I'd rather just have something like: var response = <get local file>;
@DeanSherwin, the problem is that you can't access sessionData directly, that's why you need to mock formFetcherService service. JSON is irrelavent here because you are testing successCallback function and it doesnt' matter how you create it.
Why can't I access sessiondata directly? The test is for HomeController which is where its declared. So to test that function in isolation I just need to 'fake' a response object being passed into it and check the output at the end, no? (I'm new to unit testing in angular)
No. I'll post the home controller later though. Thanks for your help. I just didn't think it would be a big deal to load JSON from a file.
Sorry to leave you hanging on this. Your answer helped me greatly. I was just getting started with unit testing for Angular and a lot of core concepts were alien to me (particularly using Jamsine spies). I've marked you answer as correct as it's core implementation solved the problem I was facing, even if I didnt use it in its entirety.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.