james
james

Reputation: 4047

Unable to pass jasmine spec due to a promise

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

Answers (1)

AliF50
AliF50

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

Related Questions