Why does my Q chained promise rejection not behave the way I expect?

Problem

What am I doing wrong here? I have a piece of code that looks something like this:

function getUserList(requestingUserId){
  return customerRepo.getCustomersAllowedByUser(requestingUserId)
  .then(function(customers){
    return userRepo.getUserList({customers: customers});
  });
}

my repository code is stubbed out like this:

customerDeferred = q.defer();
userDeferred = q.defer();

customerRepository.getCustomersAllowedByUser = sinon.stub().returns(customerDeferred.promise);
userRepository.getUsers = sinon.stub().returns(userDeferred.promise);

It all works fine when both promises are resolved, and as expected when I reject the customer promise, however when I resolve the customer promise and reject the user promise the test breaks down. Here is the test:

it('should forward the rejection when userRepository rejects the promise', function(done){
  var rejectionError = new Error("test");
  var receivedError;

  userServices.getUserList(1)
  .then(null, function(error){
    receivedError = error;
  })
  .fin(function(){
    receivedError.should.equal(rejectionError);
    done();
  });

  customerDeferred.resolve(customerList);
  userDeferred.reject(rejectionError);
});
Problem courtesy of: Bucky Patterson

Solution

To see what's wrong, replace your test temporarily with just:

var rejectionError = new Error("test");
var receivedError;

userServices.getUserList(1).done();

customerDeferred.resolve(customerList);
userDeferred.reject(rejectionError);

This will print out the actual error. Once you've fixed all the errors that just result from typos, you'll find that it works.

The problem is that userRepo is different from userRepository and getUsers is different from getUserList.

Having fixed all these I ended up with:

var q = require('q')
var sinon = require('sinon')

var assert = require('assert')

customerDeferred = q.defer();
userDeferred = q.defer();

var customerList = []
var customerRepo = {}
var userRepo = {}

customerRepo.getCustomersAllowedByUser = sinon.stub().returns(customerDeferred.promise);
userRepo.getUsers = sinon.stub().returns(userDeferred.promise);

function getUserList(requestingUserId){
  return customerRepo.getCustomersAllowedByUser(requestingUserId)
  .then(function(customers){
    return userRepo.getUsers({customers: customers});
  });
}

var rejectionError = new Error("test");
var receivedError;

getUserList(1)
.then(null, function(error){
  receivedError = error;
})
.fin(function(){
  assert.equal(receivedError, rejectionError);
  console.log('DONE')
});

customerDeferred.resolve(customerList);
userDeferred.reject(rejectionError);

Which runs perfectly.

Solution courtesy of: ForbesLindesay

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.