frank
frank

Reputation: 511

Sinon.JS stub that resolves a promise returns "{}"

I have a Node.js function that returns a promise. I am using Sinon.JS stubs to resolve the promise. My console.log statements in the code show that the stub is working. However, what is returned is {} instead of what the Promise resolves to.

I reviewed these other SO posts, but neither were exactly the problem I am running into:

Here is the function:

function publishMessage(pubsub, topicName, data) {   
  const topic = pubsub.topic(topicName);   
  const publisher = topic.publisher();

  return publisher.publish(data)
    .then((results) => {
      const messageId = results[0];
      return messageId;
    })
    .catch((error) => {
      console.log('Error ', error);
      return error;
    }); };

Here is the test:

describe('publishMessage', function() {
  describe('Success', function() {
    it('should return the messageId', function(done) {
      var publishMessage = index.__get__('publishMessage');
      var promise = sinon.stub().resolves(['1111']);
      var publisher = {
        publish: promise
      };
      var topic = {
        publisher: sinon.stub().returns(publisher)
      };
      var pubsub = {
        topic: sinon.stub().returns(topic)
      };
      assert.equal('1111', publishMessage(pubsub, 'st', 'ds'));
      assert.isTrue(topic.publisher.calledWith());
      done();
    });
  });
});

And when I execute the test, the output from the console.log shows the resolve value is printed:

  publishMessage
    Success
      1) should return the messageId
1111


  0 passing (256ms)
  1 failing

  1) publishMessage
       Success
         should return the messageId:
     AssertionError: expected '1111' to equal {}
      at Context.<anonymous> (test/index.spec.js:63:14)

Upvotes: 1

Views: 5092

Answers (2)

c1moore
c1moore

Reputation: 1867

There's a few potential problem areas that I noticed.

First, I don't see where index is defined, so I can't confirm whether or not the function you expect is being returned from index.__get__('publishMessage');. You can confirm that the right function is returned by visually inspecting the result of

publishMessage.toString();

The other problem I see (and more likely the cause of your problem) is that you are returning a Promise from publishMessage(), but comparing the result of a call to that function to the value to which the Promise will eventually resolve. In other words, your comparing a Promise to a String. Unless your assertion library waits for the Promise to resolve before checking the result (similar to Jasmine), you are comparing a String to a Promise. To remedy this, simply wait for the Promise to resolve:

it('should return the messageId', function(done) {
    // Set up the test case by defining publishMessage, etc.

    publishMessage(pubsub, 'st', 'ds').then((result) => {
        assert.equal(result, '1111');
        assert.isTrue(topic.publisher.calledWith());

        done();
    }).catch(done);
}

Notice I added a .catch() on the Promise. This makes sure that any errors thrown in the Promise will show the appropriate error as opposed to just a timed out error.

If you're using a testing framework like Mocha or Karma/Jasmine, you can improve this a little more by directly returning the Promise instead of using done(). In my experience, returning the Promise results in much better stack traces and more helpful and accurate error messages when trying to debug a test case that uses Promises. As an example:

it('should return the messageId', function() {
    // Set up the test case by defining publishMessage, etc.

    return publishMessage(pubsub, 'st', 'ds').then((result) => {
        assert.equal(result, '1111');
        assert.isTrue(topic.publisher.calledWith());
    });
}

Notice that I don't accept an argument in the test case anymore. In Mocha and Karma, this is how the framework determines how to treat the test case.

Upvotes: 3

Johannes Merz
Johannes Merz

Reputation: 3340

You don't wait for your promise to be resolved.

Try

publishMessage(pubsub, 'st', 'ds').then(result => {
  assert.equal('1111', result);
  assert.isTrue(topic.publisher.calledWith());
  done();
}

Upvotes: 2

Related Questions