Antes de agregar una promesa, este código/especificación estaba pasando con éxito
// 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 Pero luego hice que ajax se disparara después de que se ejecutara otra función asíncrona. Pensé que espié las cosas correctamente y, de hecho, el console.log continúa indicando que el código se está ejecutando. De hecho, si me burlé de un valor de retorno como spyOn(catalogDOM, "updateAvailabilityForItem").and.returnValue("works") y luego en el código escribí: console.log(catalogDOM.updateAvailabilityForItem(0)) , entonces el ¡log genera "works" !
Sin embargo, la especificación falla. ¿Por qué?
// 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 errorIntenta hacer los siguientes cambios:
// 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) }Con suerte, las modificaciones anteriores deberían solucionarlo. Tratar con promesas y pruebas es difícil porque a veces en la prueba tienes que decirle a Jasmine que las promesas que se crearon en el código que se está probando, espere a que se completen antes de hacer aserciones.