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

2

9

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' }

Greylag answered 24/1, 2014 at 18:36 Comment(0)
A
3

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.

Antipyrine answered 12/2, 2014 at 11:2 Comment(1)
Thanks, I guess I will keep doing what I am doing then.Greylag
A
13

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')));
});
Airwoman answered 8/12, 2015 at 8:41 Comment(2)
The code for xhr.respond: github.com/sinonjs/sinon/blob/…Isologous
This should be the real answer nowClothesline
A
3

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.

Antipyrine answered 12/2, 2014 at 11:2 Comment(1)
Thanks, I guess I will keep doing what I am doing then.Greylag

© 2022 - 2024 — McMap. All rights reserved.