Search code examples
javascriptunit-testingintegration-testingsinonchai

Chai/Sinon: How to spy on the return value of a promise returned by a function?


I'm setting up unit + integration tests for onAfterDelete:

Assessment.onAfterDelete = async () => {
  ...

  // Log assessment deleted
  await Activity.create({
    assessmentId,
    activityTypeId: ACTIVITY_TYPE.ASSESSMENT_DELETED,
  }, options);

  ...
};

While I know how to test that Activity.create was called, I'd really like to test that the Activity was successfully created.

If it wasn't asynchronous, then I'd use Sinon.spy as follows:

it('logs the assessment deleted activity', async () => {
  sinon.spy(Activity, 'create');
  await Assessment.onAfterDelete(...);
  expect(Activity.create).returned({
    activityTypeId: ACTIVITY_TYPE.ASSESSMENT_DELETED,
    assessmentId: standardAssessmentData.id,
  });
  Activity.create.restore();
});

Of course, this doesn't work as Activity.create returns a Promise.

After an hour Googling the various flavors of Chai and Sinon with promises, I'm yet to find a solution to this use case. How can I test this return value?


Solution

  • You can use chai-as-promised:

    const chai           = require('chai');
    const chaiAsPromised = require('chai-as-promised');
    chai.use(chaiAsPromised);
    
    it('logs the assessment deleted activity', async () => {
      sinon.spy(Activity, 'create');
      await Assessment.onAfterDelete();
    
      // Make sure `Activity.create()` got called.
      expect(Activity.create.called).to.be.true;
    
      // Check the resolved value.
      await expect(Activity.create.firstCall.returnValue).to.eventually.equal({
        activityTypeId : ACTIVITY_TYPE.ASSESSMENT_DELETED,
        assessmentId   : standardAssessmentData.id,
      });
    
      // Restore the original.
      Activity.create.restore();
    });