Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fake jquery.ajax() response?

I am writing some QUnit tests for a JavaScript that makes AJAX calls.

For isolation I overwrite $.ajax to write the parameter array of an AJAX call to a variable. This works to test how methods use AJAX functions, but I have difficulty testing the success handler of $.load()

From the documentation at http://api.jquery.com/load/:

When a successful response is detected (i.e. when textStatus is "success" or "notmodified"), .load() sets the HTML contents of the matched element to the returned data.

So I have attempted to return an object containing objects with the same name as variables for the success handler:

    //Mock ajax function
    $.ajax = function (param) {
        _mockAjaxOptions = param;
        var fakeAjaxSuccess = { responseText: "success", textStatus: "success", XMLHttpRequest: "success" };
        return fakeAjaxSuccess;
    };

But this approach hasn't worked.

How can I replicate the behaviour of a successful AJAX call?

like image 635
StuperUser Avatar asked Mar 11 '11 12:03

StuperUser


People also ask

How do you mock Ajax?

When you want to mock out all ajax calls across an entire suite, use install() in a beforeEach . Because jasmine-ajax stubs out the global XMLHttpRequest for the page, you'll want to uninstall() in an afterEach so specs or setup that expect to make a real ajax request can. Make your requests as normal.

Can AJAX be hacked?

If someone has complete access to a browser, then they can run any code they like in it - including modifying or adding JavaScript to your pages. That has absolutely nothing to do with a site using Ajax though — any point where the client interacts with the server may be vulnerable.

What is processData false in Ajax?

processData. If set to false it stops jQuery processing any of the data. In other words if processData is false jQuery simply sends whatever you specify as data in an Ajax request without any attempt to modify it by encoding as a query string.


3 Answers

This question has a few years and for the new versions of jQuery has changed a bit.

To do this with Jasmin you can try Michael Falaga's approach

Solution

  function ajax_response(response) {
    var deferred = $.Deferred().resolve(response);
    return deferred.promise;
  }

With Jasmine

  describe("Test test", function() {
    beforeEach(function() {
      spyOn($, 'ajax').and.returnValue(
        ajax_response([1, 2, 3])
      );
    });
    it("is it [1, 2, 3]", function() {
      var response;
      $.ajax('GET', 'some/url/i/fancy').done(function(data) {
        response = data;
      });
      expect(response).toEqual([1, 2, 3]);
    });
  });

No Jasmine

  $.ajax = ajax_response([1, 2, 3]);
  $.ajax('GET', 'some/url/i/fancy').done(function(data) {
     console.log(data); // [1, 2, 3]
  });
 
like image 84
user1634074 Avatar answered Oct 17 '22 07:10

user1634074


After reading inspired by @Robusto and @Val, I found a method that works:

//Mock ajax function
$.ajax = function (param) {
    _mockAjaxOptions = param;
    //call success handler
    param.complete("data", "textStatus", "jqXHR");
};

Instead of raising the event from any real $.ajax code or by triggering any events, I have my fake ajax object call the function (which is passed in as a parameter to $.ajax()) as part of my fake function.

like image 15
StuperUser Avatar answered Oct 17 '22 06:10

StuperUser


Use a closure to override $.ajax with a dummy response

After trying the accepted answer and the answer posted by user1634074, I devised this simple and flexible blend of the two.

In its most basic form…

function ajax_response(response) {
  return function (params) {
    params.success(response);
  };
}
$.ajax = ajax_response('{ "title": "My dummy JSON" }');

In the above example, define a function ajax_response() that accepts some JSON string as an argument (or any number of custom arguments useful for simulating a response) and returns an anonymous closure function that will be assigned to $.ajax as an override for unit testing.

The anonymous function accepts a params argument which will contain the settings object passed to the $.ajax function. And it uses the argument(s) passed to the outer function to simulate a response from the server. In this example, it always simulates a successful response from the server, by simply invoking the success callback and supplying it with the dummy JSON.

It is easy to reconfigure…

function ajax_response(response, success) {
  return function (params) {
    if (success) {
      params.success(response);
    } else {
      params.error(response);
    }
  };
}

// Simulate success
$.ajax = ajax_response('{ "title": "My dummy JSON." }', true); 
doAsyncThing(); // Function that calls $.ajax

// Simulate error
$.ajax = ajax_response('{ "error": "Who is the dummy now?" }', false); 
doAsyncThing(); // Function that calls $.ajax

Below we can see it in action…

/* FUNCTION THAT MAKES AJAX REQUEST */
function doAsyncThing() {
  $.ajax({
    type: "POST",
    url: "somefile.php",
    // data: {…},
    success: function (results) {
      var json = $.parseJSON(results),
          html = $('#ids').html();
      $('#ids').html(html + '<br />' + json.id);
    }
  });
}

/* BEGIN MOCK TEST */
// CREATE CLOSURE TO RETURN DUMMY FUNCTION AND FAKE RESPONSE
function ajax_response(response) {
  return function (params) {
    params.success(response);
  };
}

var n = prompt("Number of AJAX calls to make", 10);

for (var i = 1; i <= n; ++i) {
  
  // OVERRIDE $.ajax WITH DUMMY FUNCTION AND FAKE RESPONSE
  $.ajax = ajax_response('{ "id": ' + i + ' }');
  doAsyncThing();
}
/* END MOCK TEST */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="ids">IDs:</p>
like image 12
gfullam Avatar answered Oct 17 '22 05:10

gfullam