Be the first user to complete this post

  • 0
Add to List

Testing promise sequence using mocha, chai, chai-as-promised, sinon


System Under Test

Let's say we have a method call sequence to run promise based commands in sequence. For example, below command runs c1 and when it resolves it will run c2 and so forth.
Util.sequqnce([c1, c2, c3]);  // c1, c2, c3 are promises.
.sequence takes an array of promises and returns a value returned by the last resolved promise as shown below.

class Util {

    sequence(list) {
        return list.reduce(
            (prev, item) => prev.then(() => this.run(item)),
            Promise.resolve()
        );
    }

}

module.exports = Util;

NOTE: .sequence calls .run command to execute the item.

Configuration

We will require mocha ( test runner ), chai ( assertion library ), sinon( spy, stub, mock ), chai-as-promised ( to test promises ) as devDependencies in out package.json.

{
  ...

  "devDependencies": {
    "chai": "4.1.1",
    "chai-as-promised": "7.1.1",
    "istanbul": "0.4.5",
    "mocha": "3.5.0",
    "sinon": "3.2.1",
  },

  ...

}


Test case

If the commands, c1, c2, c3 when fulfilled returns 10, 20, 30 respectively - First time, .run is called with c1 which returns 10 - Second time, .run is called with c2 which returns 20 - Third time, .run is called with c3 which returns 30
const Util = require('../scripts/Util.js');

const chai = require('chai');
const sinon = require('sinon');
const chaiAsPromised = require('chai-as-promised');

// set up the middleware
chai.use(chaiAsPromised);

describe('Util', () => {

  describe('sequence', () => {

    it('Expect all the comands to run in sequence', () => {

      let util = new Util();

      // create an array of promises which resolves immediately
      let promises = [10, 20, 30].map( item => Promise.resolve(item) );

      // spy an existing function so we can inspect it
      spy = sinon.spy(util, 'run');

      // return notifies mocha to wait for the promise to be resolved
      return util.sequence(promises)
        .then(() => expect(spy.firstCall.returnValue).to.eventually.equal(10))
        .then(() => expect(spy.secondCall.returnValue).to.eventually.equal(20))
        .then(() => expect(spy.thirdCall.returnValue).to.eventually.equal(30));

      });

  });


    it('verify sequence execution by updating the result array', () => {

        let result = [],
            util = new Util();

        p3 = () => new Promise((resolve, reject) => {
            result.push(100);

            setTimeout(() => {
                result.push(200);
                resolve();
            }, 10);
        });

        p4 = () => new Promise((resolve, reject) => {
            result.push(300);
            resolve();
        });

        return util.run([ p3, p4 ]).then(() => {
            expect(result).to.have.ordered.members([ 100, 200, 300 ]);
        });

    });

});

Notes:




Also Read:

  1. Debugging nodejs applications using node-inspector and Chrome Dev Tools
  2. Understanding semver versioning for your nodejs packages
  3. A simple requestAnimationFrame example visually explained
  4. Organizing your expressjs routes in separate files.
  5. imperative vs declarative/functional programming