How do I test a function that calls an AJAX function without firing it using jasmine?

六眼飞鱼酱① 提交于 2019-12-30 07:30:33

问题


I've checked in How do I verify jQuery AJAX events with Jasmine? and How to test an Angular controller with a function that makes an AJAX call without mocking the AJAX call? but for some reason they don't necessarily come out with a format that works for me.

My issue is that I'm unit testing a function that makes a call to a function that fires off an AJAX request. I want to test the outer function without firing off the AJAX request (or halt that request) so I don't get a bunch of faulty data shot into the data server.

Here is my outer function (which calls the function containing the AJAX):

vm.clickSubmit = function () {
    vm.loading = true; // starts the loading spinner
    vm.updateData(); // makes current data current in the data model
    vm.inputData = {    // build the data to be submitted
        ...
    };
    vm.submit(); // calls the AJAX function
};

Here is my AJAX function:

vm.submit = function () {
    var d = $.ajax({
        type: "POST"
        , data: angular.toJson(vm.inputData)
        , url: "http://submit_the_data"
        , contentType: "application/json"
        , xhrFields: { withCredentials: true }
        , crossDomain: true
    })
    .success(function (resp) {
        DataService.ticketNumber = resp; // returns ticket# for the data model
    })
    .error(function (error) {
        DataService.ticketNumber = DataService.submitError;
    });
    d.then(function (d) {
        vm.loading = false; // stops the loading spinner
        DataService.tickets = []; // empty's the array to be filled anew
        $location.path('/submitted'); // success splash html
        $scope.$apply();
    });
};

I've written all the tests that will read and verify the values in the inputData object, but I'm not sure how to surround the call to clickSubmit() so nothing is actually submitted to the server. I've gotten to this point in my unit testing:

'use strict';

describe('Controller: HomeController', function () {
    beforeEach(module('tickets'));
    var controller, scope, $location, DataService;
    var tests = 0;
    beforeEach(inject(function ($rootScope, $controller, _$location_, _DataService_) {
        $location = _$location_;
        DataService = _DataService_;
        scope = $rootScope.$new();
        controller = $controller('HomeController', {
            $scope: scope
        });
    }));
    afterEach(function () {
        tests += 1;
    });
    describe('clickSubmit should verify data and submit new ticket', function () {
        beforeEach(function () {
            jasmine.Ajax.install();
            controller.loading = false;
                ... // inputData fields filled in with test data
        });
        afterEach(function () {
            jasmine.Ajax.uninstall();
        });
        it('should start the spinner when called', function () {
            controller.clickSubmit();
            expect(controller.loading).toBeTruthy();
        });
        // other it('') tests
    });
    it('should have tests', function () {
        expect(tests).toBeGreaterThan(0);
    });
});

So what should go after the expect on the loading spinner to cancel the call to vm.submit() in the actual code?

Thanks,

-C§


回答1:


I suggest mocking out the call rather than actually calling it. The granularity is up to you, you can either stub the ajax call, or stub the whole submit function.

Here is how you can stub the submit function:

spyOn(controller, 'submit').and.callFake(function() {
    DataService.ticketNumber = somevalue;
});

Place that code prior to the actually call to the controller which caller.clickSubmit().

You can then follow up with expectations on the spy, such as:

expect(controller.submit).toHaveBeenCalled()

Or any of the other expectations related to spyOn.

Here are the jasmine docs: http://jasmine.github.io/2.0/introduction.html
Look down in the 'spies' area.

If you want to mock up the ajax call, you will have to mock a promise like this:

spyOn($, 'ajax').and.callFake(function() {
    var deferred = $q.defer();
    deferred.resolve(someResponse);
    return deferred.promise;
});

Also, in order to get the code waiting on the promise to resolve, after the submit call has been made, you need to run a $scope.$digest() so that angular can handle the promise resolution. Then you can check your expectations on code that depended on the resolution or rejection of the promise.



来源:https://stackoverflow.com/questions/31975928/how-do-i-test-a-function-that-calls-an-ajax-function-without-firing-it-using-jas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!