Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QUnit, Sinon.js - How do I ensure Post to Fake Server has correct request body?

I have a JavaScript function that does a Post to a remote API that I am looking at writing a unit test for. The method I want to test is this:

var functionToTest = function(callback, fail) {
    $.ajax({
        url: "/myapi/",
        type: "POST",
        data: { one: 'one', two: 'two' },
        accept: "application/json",
        contentType: "application/json"
    }).done(function(x) {
        log = generateLogMessage('Success');
        callback(log);
    }).fail(function(x, s, e) {
        log = generateLogMessage('Fail');
        fail(log);
    });
}

I have a unit test (in QUnit leveraging Sinon.js) that tests that the callback is called correctly when the request succeeds:

QUnit.test('Test that the thing works', function () {

    var server = this.sandbox.useFakeServer();

    server.respondWith(
        'POST',
        '/myapi/',
        [
            200,
            {'Content-Type': 'application/json'},
            '{"Success":true}'
        ]
    );

    var callback = this.spy();
    functionToTest(callback, callback);
    server.respond();

    QUnit.ok(callback.calledWith(generateLogMessage('Success')));
});

This test works, but it returns successfully regardless of what the request body. What I want to do is only have the Fake Server respond if the request body is { one: 'one', two: 'two' }

like image 798
BeardedCoder Avatar asked Jan 24 '14 18:01

BeardedCoder


2 Answers

Almost two years later now, but still relevant:

This can be achieved by passing a function instead of an array as the third parameter to server.respondWith. The function takes one argument 'request', on which you can call request.respond(statusCode, headers, body);

You'll still have to extract the values from request.requestBody, but at least it's doable.

QUnit.test('Test that the thing works', function () {

    var server = this.sandbox.useFakeServer();

    server.respondWith(
        'POST',
        '/myapi/',
        function (request) {
            console.log(request.requestBody); // <- assert here :-)
            request.respond(200, {'Content-Type': 'application/json'}, '{"Success":true}');
        }
    );

    var callback = this.spy();
    functionToTest(callback, callback);
    server.respond();

    QUnit.ok(callback.calledWith(generateLogMessage('Success')));
});
like image 112
sgtdck Avatar answered Oct 01 '22 10:10

sgtdck


I was going to suggest that you use filtered requests. However this is not possible with the current implementation of sinon.

excerpt from documentation:

Add a filter that will decide whether or not to fake a request. The filter will be called when xhr.open is called, with the exact same arguments (method, url, async, username, password). If the filter returns truthy, the request will not be faked.

You don't have ability to filter on the data.

EDIT: If I understand the problem correctly, you might be able to do something like this:

functionToTest(...);
var request = server.requests[0];
var data = JSON.parse(request.requestBody);
if (data.one == 'one' && data.two == 'two') {
  request.respond(200, jsonHeaders, JSON.stringify(specialResponse));
}
else {
  request.respond(200, jsonHeaders, JSON.stringify(otherResponse));
}

I know that code will get the correct result that you want, but there's not a way to programmatically accomplish that with sinon right now.

like image 45
fearphage Avatar answered Oct 01 '22 09:10

fearphage