Reputation: 4047
Prior to adding a promise, this code/spec was successfully passing
// Code
function getAvailability() {
$.ajax({
type:"POST",
url: "/get-availability",
dataType:"json",
contentType:"application/json",
data: params,
success: function() {
// ...
},
error: function() {
console.log(">> in error")
catalogDOM.updateAvailabilityForItem(0)
}
})
}
// Spec
describe("if ajax fails", function() {
beforeEach(function() {
ajaxSpy = spyOn($, "ajax")
ajaxSpy.and.callFake(function(e) {
e.error()
})
spyOn(catalogDOM, "updateAvailabilityForItem")
getAvailability()
})
it("should call updateAvailabilityForItem with 0", function() {
expect(catalogDOM.updateAvailabilityForItem).toHaveBeenCalledWith(0)
}
})
// Console output
>> in error
But then I made the ajax
fire after another async function ran. I thought I spied on things correctly, and in fact, the console.log
continues to indicate that the code is running. In fact, if I mocked a return value for like so spyOn(catalogDOM, "updateAvailabilityForItem").and.returnValue("works")
and then in the code wrote: console.log(catalogDOM.updateAvailabilityForItem(0))
, then the log does output "works"
!
Yet the spec fails. Why?
// Code
function getAvailability() {
//////// START NEW LINE
utilityOrders.checkElement('#overlay').then((selector) => {
//////// END NEW LINE
$.ajax({
type:"POST",
url: "/get-availability",
dataType:"json",
contentType:"application/json",
data: params,
success: function() {
// ...
},
error: function() {
console.log(">> in error")
catalogDOM.updateAvailabilityForItem(0)
}
})
})
}
// Spec
describe("if ajax fails", function() {
beforeEach(function() {
//////// START NEW LINE
resolved_promise = new Promise(function(resolve, reject) { resolve() })
spyOn(utilityOrders,"checkElement").and.returnValue(resolved_promise)
//////// END NEW LINE
ajaxSpy = spyOn($, "ajax")
ajaxSpy.and.callFake(function(e) {
e.error()
})
spyOn(catalogDOM, "updateAvailabilityForItem")
getAvailability()
})
it("should call updateAvailabilityForItem with 0", function() {
expect(catalogDOM.updateAvailabilityForItem).toHaveBeenCalledWith(0)
}
})
// Console output
>> in error
Upvotes: 2
Views: 39
Reputation: 18889
Try making the following changes:
// Code
// !! add async here so we have control to wait until it goes inside of the .then before continuing !!
async function getAvailability() {
//////// START NEW LINE
utilityOrders.checkElement('#overlay').then((selector) => {
//////// END NEW LINE
$.ajax({
type:"POST",
url: "/get-availability",
dataType:"json",
contentType:"application/json",
data: params,
success: function() {
// ...
},
error: function() {
console.log(">> in error")
catalogDOM.updateAvailabilityForItem(0)
}
})
})
}
// Spec
describe("if ajax fails", function() {
// !! add async and done argument to call when we are done with this function !!
beforeEach(async function(done) {
//////// START NEW LINE
resolved_promise = new Promise(function(resolve, reject) { resolve() })
spyOn(utilityOrders,"checkElement").and.returnValue(resolved_promise)
//////// END NEW LINE
ajaxSpy = spyOn($, "ajax")
ajaxSpy.and.callFake(function(e) {
e.error()
})
spyOn(catalogDOM, "updateAvailabilityForItem")
// await getAvailability so the promise is resolved before proceeding (then is called)
await getAvailability();
// call done to let Jasmine know you're done with the test
done();
})
it("should call updateAvailabilityForItem with 0", function() {
expect(catalogDOM.updateAvailabilityForItem).toHaveBeenCalledWith(0)
}
The above modifications should hopefully fix it for you. Dealing with promises and tests is difficult because sometimes in the test you have to tell Jasmine that the promises that were created in the code that is being tested, wait for them to complete before doing assertions.
Upvotes: 0