EventEmitter unit test using mocha and sinon doesn't work

Viewed 84

The part of my codes "expect(spy.called).to.be.true" is supposed to be true. but the test result shows something like this.

  AssertionError: expected false to be true
  + expected - actual

  -false
  +true

I tried to do an unit test of EventEmitter with mocha. Soon, I realized that I needed to check the listener function is called. So I imported sinon module. But anything I expected didn't happen to me. My codes are as follows. Please let me know what is wrong with my codes. thanks a lot in advance.

<test.js>

const findPattern = require('./findPatterns');
const expect = require('chai').expect;
const sinon = require('sinon');
const FakeTimers = require('@sinonjs/fake-timers');

describe('findPattern', function() {

  const sampleFiles = ['./sample/sample1.txt', './sample/sample2.txt', './sample/sample3.txt'];
  const regEx = /[0-9]+/g;

  it('findPattern', function() {
    const clock = FakeTimers.createClock();

    const o = {
      f: (file) => console.log('Read from ' + file)
    };

    const spy = sinon.spy(o, "f");

    findPattern(sampleFiles, regEx)
      .on('error', (err) => console.log('error: ' + err))
      .on('read', spy)
      .on('found', (file, match) => console.log('Matched ' + match + ' in file' + file));

    clock.setTimeout(function() {
      expect(spy.called).to.be.true;
    }, 1000);

    clock.tick(1000);
  });
});

<findPatterns.js>

const EventEmitter = require('events');
const fs = require('fs');

function findPattern(files, regex) {
  const emitter = new EventEmitter();

  files.forEach(function(file) {
    fs.readFile(file, "utf-8", (err, content) => {
      if (err) {
        return emitter.emit('error', err);
      }

      emitter.emit('read', file);

      const matches = content.match(regex);
      if (matches) {
        matches.forEach(i => {
          emitter.emit('found', file, i);
        });
      }
    }); 
  });

  return emitter;
}

module.exports = findPattern;
1 Answers

Well, I think I found out a kind of solution. I guess the problem was something about asynchronous issue. The "expect function" seemed to called before finishing read files. So I changed my code and get the result I expected. By the way timer function seems that it doesn't work properly. Please review my changed code and give some advice if I did something wrong.

const findPattern = require('./findPatterns');
const expect = require('chai').expect;
const sinon = require('sinon');

describe('findPattern', function() {
  const sampleFiles = ['./sample/sample1.txt', './sample/sample2.txt', './sample/sample3.txt'];
  const regEx = /[0-9]+/g;
  
  const readFun = (file) => console.log('Read from ' + file);
  const o = {
    f: readFun
  };

  const spy = sinon.spy(o, "f");

  beforeEach(function(done) {
    findPattern(sampleFiles, regEx, done)
      .on('error', (err) => console.log('error: ' + err))
      .on('read', spy)
      .on('found', (file, match) => console.log('Matched ' + match + ' in file' + file));
  });

  it('findPattern', function() {
    expect(spy.called).to.be.true;
  });
});
const EventEmitter = require('events');
const fs = require('fs');

function readFile(file, regex, emitter, callback) {
  fs.readFile(file, "utf-8", (err, content) => {
    if (err) {
      return emitter.emit('error', err);
    }
    
    emitter.emit('read', file);
    
    const matches = content.match(regex);
    if (matches) {
      matches.forEach(i => {
        emitter.emit('found', file, i);
      });
    }

    callback();
  }); 
}

function findPattern(files, regex, done) {
  const emitter = new EventEmitter();

  let completed = 0;

  function finish() {
    if (++completed == files.length) {
      return done();
    } 
  }

  files.forEach(function(file) {
    readFile(file, regex, emitter, finish);
  });

  return emitter;
}

module.exports = findPattern;
Related