简体   繁体   中英

How to test the catch block on Promise.all()?

Got this code:

//Waiting until all records are inserted to DB
Promise.all(promises).then(function(err){   
    context.succeed({ valid: true, succeedRecords:succeedRecords, failedRecords:failedRecords });
    //Log
    console.log("Lambda function is finished - Successfully added records: " + succeedRecords.length + ",  Failed records: " + 
        failedRecords.length + "  -  Total processed records: " + event.Records.length);   
})
.catch(function (err) {
    if (err) {
        var msg = "Got error from Promise.all(), Error: " + err;
        console.log(msg);
        context.fail({ valid: false, message: msg });
    }
});

I need to know how can I test the catch block using mocha ?

Assume you just want to check if the Promise.all fails the code will be much simpler:

//Waiting until all records are inserted to DB
return Promise.all(promises).then(function(err){   
  context.succeed({ valid: true, succeedRecords:succeedRecords, failedRecords:failedRecords });
  //Log
  console.log("Lambda function is finished - Successfully added records: " + succeedRecords.length + ",  Failed records: " + 
    failedRecords.length + "  -  Total processed records: " + event.Records.length);   
});

mocha in this case will append a catch to the returned promise and fail if called.

In some contexts you want to handle the error scenario, perform some checks and fail only in specific scenarios:

//Waiting until all records are inserted to DB
return Promise.all(promises).then(function(err){   
  context.succeed({ valid: true, succeedRecords:succeedRecords, failedRecords:failedRecords });
  //Log
  console.log("Lambda function is finished - Successfully added records: " + succeedRecords.length + ",  Failed records: " + 
    failedRecords.length + "  -  Total processed records: " + event.Records.length);   
})
.catch(function (err) {
  var msg = "Got error from Promise.all(), Error: " + err;
  console.log(msg);
  // ... do some stuff here
  context.fail({ valid: false, message: msg });

  // add an expectation here to check if the error message is correct
  // If the error message is "this error" the test passes, otherwise it will fail
  expect(err).to.be.eql('this error');
});

In detail

I'll take a step back here and try to explain in detail how it works. Say you have a test with a Promise that rejects:

// your code
it('rejects', () => {

  return Promise.reject();

});

This test will fail as mocha will do the following (the actual code is here ):

// this is pseudo code for the mocha insides
var result = fn.call(ctx);
if (result && result.then) {

  result
    .then(function successCase() {
      // all fine here
      done();
    })
    .catch(function errorCase(reason) {
      done(reason);
    });
  }

So the promise you return will be chained with a .then and a .catch and two callbacks will be passed: one for success (make the test pass) and one for error (make the test fail).

In your rejection case above what happens is the following:

  // mocha code (I've just replaced the function call with its result)
  var result = Promise.reject();
  if(result && result.then){
    result.then(function successCase() {
      // this is not called!
      done();
    })
    .catch(function errorCase(reason) {
      // it will land here!
      done(reason);
    } );
  }

In the code of the OP question, the Promise may error and that error will be trapped:

Promise.reject()
  .catch( function( err ){
    var msg = "Got error from Promise.all(), Error: " + err;
    console.log(msg);
    context.fail({ valid: false, message: msg });
  }); <-- what is the output here?

The above is the case where your Promise.all rejects and you catch it within the test. The result of that catch is... success!

// your code
Promise.reject()
  .catch( function( err ){
    var msg = "Got error from Promise.all(), Error: " + err;
    console.log(msg);
    context.fail({ valid: false, message: msg });
  })

  // mocha code
  .then(function successCase() {
    // this is called! (and make the test pass)
    done();
  })
  .catch(function errorCase(reason) {
    // it will NOT call this
    done(reason);
  });

Now, say you WANT the Promise to reject, catch the error and then test something (maybe the error message? some other option? etc...). How do you do it given that the code above? Easy, you throw an error in some way. One way could be to explicitly throw the error or you can use an assertion (an assertion that fails will throw an error).

// your code
Promise.reject()
  .catch( function( err ){
    var msg = "Got error from Promise.all(), Error: " + err;
    console.log(msg);
    context.fail({ valid: false, message: msg });

    // It will throw!
    expect(true).to.be(false);

    // or you can go vanilla
    throw Error("I don't like Errors!");
  })

  // mocha code
  .then(function successCase() {
    // this is NOT called!
    done();
  })
  .catch(function errorCase(reason) {
    // it will call this! (and make the test fail)
    done(reason);
  });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM