Sinon's fake server is not responding

2019-07-06 11:34发布

问题:

There are a number of other questions asking about Sinon failing to respond, but they all seem to resolve with something mundane, like invalid response data or a toggled configuration option.

My situation is as follows:

In the main application (at /js/app/) requireJS is used to load website application modules.
For testing (at /js/test) requireJS is also used to load the same modules, but adds Mocha, Chai, and Sinon.

This is the bootstrap of the test application:

define(
    "testRunner",
    ["require", "chai", "module", "sinon", "mocha"],
    function( require, chai, module ){
        // Chai setup
        assert = chai.assert;
        should = chai.should();
        expect = chai.expect;

        // Mocha setup
        mocha.setup( 'bdd' );

        // tests
        require(
            module.config().tests,
            function(){
                mocha.run();
            }
        );
    }
);

require(["testRunner"]);

module.config().tests is defined in the requirejs.config({}) call as:

"config": {
    "testRunner": {
        "tests": [
            "test/format",
            "test/transfer"
        ]
    }
}

When Mocha processes the transfer tests, Sinon fails, and the test times out.

This is the entirety of the transfer tests:

define(
    ["transfer"],
    function( Transfer ){
        Transfer = new Transfer();

        describe( "Transfer", function(){
            describe.only( "#loadSomeData", function(){
                it( "should load the test data", function( done ){
                    var server = sinon.fakeServer.create();

                    server.autoRespond = true;
                    server.respondWith( "string" );

                    var async = Transfer.loadSomeData( 123 );

                    async.done( function( data, s, x ){
                        data.should.equal( "string" );
                        done();
                    });

                    server.respond();
                });
            });
        });
    }
);

The testRunner output becomes:
timeout of 2000ms exceeded

For what it's worth, Transfer.loadSomeData() will return a promise: either the output of jQuery's $.ajax() or the immediately resolved promise to a new $.Deferred object.
In either case, the response is an Ajax wrapper that will resolve with the response data.

Sinon never emits the response - the Ajax call simply times out.
After much trial and error, I reduced it to the simplest possible solution - which still failed.
That solution is on jsfiddle here.

What is going on with sinon here?
Why is the response never being emitted back to the calling location (jQuery's #ajax, in this case)?
Is there a bug in sinon?

What am I doing wrong, and how can I fix it to get this example working?

回答1:

While the problem isn't actually solved, I have worked around this issue by using a slightly different syntax for Sinon.

Here is my test suite:

describe( "Transfer", function(){
    var suite = this;

    beforeEach( function(){
        suite.server = sinon.fakeServer.create();
    });

    afterEach( function(){
        suite.server.restore();
    });

    describe( "#loadSomeData", function(){
        it( "should load the test data", function( done ){
            var async = Transfer.loadSomeData( 123 );

            suite.server.requests[0].respond(
                200,
                { "Content-Type": "application/json" },
                JSON.stringify({test: "success"})
            );

            async.done( function( data, s, x ){
                data.test.should.equal( "success" );
                done();
            });
        });
    });
});

As you can see, instead of simply instructing the server to respond, I explicitly select the first request object (requests[0]), then call the respond method on it.

I don't know if the previous syntax (server.respond()) actually works, but explicitly selecting the request object from the list of requests the server has received and responding to it directly works fine.