How to mock streams in NodeJS

flacnut picture flacnut · Oct 15, 2015 · Viewed 21.1k times · Source

I'm attempting to unit test one of my node-js modules which deals heavily in streams. I'm trying to mock a stream (that I will write to), as within my module I have ".on('data/end)" listeners that I would like to trigger. Essentially I want to be able to do something like this:

var mockedStream = new require('stream').readable();

mockedStream.on('data', function withData('data') {
  console.dir(data);
});

mockedStream.on('end', function() { 
  console.dir('goodbye');
});

mockedStream.push('hello world');
mockedStream.close();

This executes, but the 'on' event never gets fired after I do the push (and .close() is invalid).

All the guidance I can find on streams uses the 'fs' or 'net' library as a basis for creating a new stream (https://github.com/substack/stream-handbook), or they mock it out with sinon but the mocking gets very lengthy very quicky.

Is there a nice way to provide a dummy stream like this?

Answer

Taitu-lism picture Taitu-lism · Oct 1, 2019

There's a simpler way: stream.PassThrough

I've just found Node's very easy to miss stream.PassThrough class, which I believe is what you're looking for.

From Node docs:

The stream.PassThrough class is a trivial implementation of a Transform stream that simply passes the input bytes across to the output. Its purpose is primarily for examples and testing...

link to docs

The code from the question, modified:

const { PassThrough } = require('stream');
const mockedStream = new PassThrough(); // <----

mockedStream.on('data', (d) => {
    console.dir(d);
});

mockedStream.on('end', function() {
    console.dir('goodbye');
});

mockedStream.emit('data', 'hello world');
mockedStream.end();   //   <-- end. not close.
mockedStream.destroy();

mockedStream.push() works too but as a Buffer so you'll might want to do: console.dir(d.toString());