Reputation: 537
I've got a jquery ajax call that looks something like this:
$.ajax({
type: "GET",
dataType: 'json',
data: data,
url: url
}).then((data, successFlag, xhr) => {
this.props.someFunc(data)
})
In my test file, I have the jquery ajax call stubbed out with sinon and it returns a resolved promise with data:
sinon.stub($, 'ajax')
.returns(Promise.resolve({ data: 'test data' }))
And I'm also spying on my someFunc(data) function. In my test, I'm calling a function that makes the ajax call, and then expecting my someFunc(data) to be called. However, the expectation fails, but when I put a console log in my someFunc(data) function, I can see that it is clearly being called:
component.instance().makeAjaxCall()
expect($.ajax.calledOnce).to.be.true // passes
expect(someFuncSpy.calledOnce).to.be.true // fails
Now I assume that it's failing because it's checking the expectation before then .then executes and I tried looking up some solutions dealing with testing with promises but nothing I've tried works so far (or I'm implementing it wrong). How can make sure that the .then finishes executing before I check the expectation?
Upvotes: 2
Views: 1354
Reputation: 201
Use done() after call the stub method.
it('should make an ajax call', function(done) {
sinon.stub($, 'ajax').returns(Promise.resolve({ data: 'test data' }))
component.instance().makeAjaxCall()
expect($.ajax.calledOnce).to.be.true;
done(); // let Mocha know we're done async testing
expect(someFuncSpy.calledOnce).to.be.true;
});
Note: Please pass done as argument in function -- it('', function(done) {})
Upvotes: 1
Reputation: 2916
Enter sinon's excellent mocking utils sinon.createFakeServer();
(http://sinonjs.org/releases/v4.1.2/fake-xhr-and-server/)
Setup the mocks and fake server for the test, call the function, tell fake server to respond, then check expectations.
In this case, something like:
it('should call someFunc with the expected data', function () {
var server = sinon.createFakeServer();
server.respondWith("GET", "*",
[200, { "Content-Type": "application/json" },
'[{ "id": 12, "comment": "Hey there" }]']);
var comp = component.instance();
var testStub = sinon.stub(comp.props, 'someFunc');
comp.makeAjaxCall();
this.server.respond();
expect(testStub.calledOnce).to.be.true; // You should consider the sinon-chai package for nicer assertion debugging
testStub.restore();
server.restore();
}
Personally, I like being able to pass in mocked dependencies instead, as I find it more testable (eg. pass in $.ajax to the constructor, stored as an ajaxService parameter on the instance).
Upvotes: 0
Reputation: 35583
You should "register" on the ajax Promise, and put your expectation in the then
block.
Something like that,
component.instance().makeAjaxCall().then(() => {
expect($.ajax.calledOnce).to.be.true;
expect(someFuncSpy.calledOnce).to.be.true;
});
It not worked for you because Promise register a callback on the micro task queue, and it got run on the next tick.
Upvotes: 0