Node: how to test multiple events generated by an async process

Viewed 42

I need to test an async Node.js library which periodically generates events (through EventEmitter) until done. Specifically I need to test data object passed to these events. The following is an example using mocha + chai:

require('mocha');
const { expect } = require('chai');
const { AsyncLib } = require('async-lib');

describe('Test suite', () => {

  const onDataHandler = (data) => {
    expect(data.foo).to.exist;
    expect(data.bar).to.exist;
    expect(data.bar.length).to.be.greaterThan(0);
  };

  it('test 1', async () => {
    const asyncLib = new AsyncLib();

    asyncLib.on('event', onDataHandler); // This handler should be called/tested multiple times

    await asyncLib.start(); // Will generate several 'events' until done

    await asyncLib.close();
  });
});

The problem is that even in case of an AssertionError, mocha marks the test as passed and the program terminates with exit code 0 (instead of 1 as I expected).

The following uses done callback instead of async syntax, but the result is the same:

require('mocha');
const { expect } = require('chai');
const { AsyncLib } = require('async-lib');

describe('Test suite', () => {

  const onDataHandler = (data) => {
    expect(data.foo).to.exist;
    expect(data.bar).to.exist;
    expect(data.bar.length).to.be.greaterThan(0);
  };

  it('test 1', (done) => {
    const asyncLib = new AsyncLib();

    asyncLib.on('event', onDataHandler);

    asyncLib.start()
      .then(asyncLib.close)
      .then(() => done());    
  });
});

I have also tried with a "pure" Node.js approach using the native assert.ok without any 3rd part library:

const { strict: assert } = require('assert');
const { AsyncLib } = require('async-lib');

const test = async () => {
    const onDataHandler = (data) => {
      assert.ok(data.foo != null);
      assert.ok(data.bar != null);
      assert.ok(data.bar.length > 0);
    };

    asyncLib.on('event', onDataHandler);

    const asyncLib = new AsyncLib();

    await asyncLib.start();

    await asyncLib.close();
}

(async () => {
  await test();
})();

Even in this case, an AssertionError would make the program to terminate with exit code 0 instead of 1.

How can I properly test this code and make the tests correctly fail in case of an assertion error?

1 Answers

There are some things that you need to fix to make it works:

  1. Make your test async, because the test is going to execute the expects after a certain event is received meaning it's going to be asyncronous.
  2. Your event handler in this case onDataHandler should receive the done callback because there is the way how you can indicate to mocha that the test was finished successful as long as the expects don't fail.

I wrote some code and tested it out and it works, you have to make some changes to adapt your async library though:

describe('Test suite', function () {

  const onDataHandler = (data, done) => {
    expect(data.foo).to.exist;
    expect(data.bar).to.exist;
    expect(data.bar.length).to.be.greaterThan(0);
    done();
  };

  it('test 1', async function (done) {
    eventEmitter.on('event', (data) => onDataHandler(data, done));

    setTimeout(() =>{
      eventEmitter.emit('event', {
      })
    }, 400)

  });

});
Related