lambda
lambda

Reputation: 417

Unit testing streams in node.js, jasmine

I have a promise that calls an HTTP get, to retrieve ana csv file, this HTTP returns me a response that I can use as a stream, I piping the response through a csv parser, and thought another func that is a writable stream, and then I listen toa some events.

But my problem is testing this, my problem is that I am not able to simulate the call to the events, I don't know how to reach the codes inside the finish and error.

Here is the snippet that retrieves a file and pipe the response:

return new Promise((resolve, reject) => {
    https.get(url, async response => {
      response
        .pipe(this.csvParser)
        .pipe(crazyfunc)
        .on("finish", () => {
          logger.info("File process finished")
          resolve()
        })
        .on("error", (err: Error) => {
          if (err) {
            reject(err)
          }
        })
      resolve()
    })
  })

And here my .spec file, I mocking this call as follows:

const response = {
    pipe: () => { },
    on: () => { }
};

beforeEach(async () => {
    spyOn(response, 'pipe').and.returnValue(response)
    spyOn(response, 'on').and.returnValue(response)
});

spyOn(https, 'get').and.callFake((url, func) => func(response))

Upvotes: 2

Views: 1305

Answers (1)

Lin Du
Lin Du

Reputation: 102497

Here is the unit test solution:

index.js:

const https = require('https');

const crazyfunc = (v) => v;
const logger = console;

const obj = {
  csvParser(data) {
    return data;
  },

  fn() {
    const url = 'example.com';
    return new Promise((resolve, reject) => {
      https.get(url, async (response) => {
        response
          .pipe(this.csvParser)
          .pipe(crazyfunc)
          .on('finish', () => {
            logger.info('File process finished');
            resolve();
          })
          .on('error', (err) => {
            if (err) {
              reject(err);
            }
          });
      });
    });
  },
};

module.exports = obj;

index.test.js:

const obj = require('./');
const https = require('https');

describe('61121812', () => {
  it('should process file', async () => {
    const response = {
      pipe: jasmine.createSpy().and.callFake(function (processor) {
        processor();
        return this;
      }),
      on: jasmine.createSpy().and.callFake(function (event, callback) {
        if (event === 'finish') {
          callback();
        }
        return this;
      }),
    };
    const csvParserStub = spyOn(obj, 'csvParser');
    const getStub = spyOn(https, 'get').and.callFake((url, func) => func(response));
    await obj.fn();
    expect(getStub).toHaveBeenCalledWith('example.com', jasmine.any(Function));
    expect(csvParserStub).toHaveBeenCalled();
    expect(response.pipe).toHaveBeenCalledTimes(2);
    expect(response.on).toHaveBeenCalledTimes(2);
    expect(response.on).toHaveBeenCalledWith('finish', jasmine.any(Function));
    expect(response.on).toHaveBeenCalledWith('error', jasmine.any(Function));
  });

  it('should handle error', async () => {
    const response = {
      pipe: jasmine.createSpy().and.callFake(function (processor) {
        processor();
        return this;
      }),
      on: jasmine.createSpy().and.callFake(function (event, callback) {
        if (event === 'error') {
          const mError = new Error('network');
          callback(mError);
        }
        return this;
      }),
    };
    const getStub = spyOn(https, 'get').and.callFake((url, func) => func(response));
    await expectAsync(obj.fn()).toBeRejectedWithError('network');
    expect(getStub).toHaveBeenCalledWith('example.com', jasmine.any(Function));
    expect(response.pipe).toHaveBeenCalledTimes(2);
    expect(response.on).toHaveBeenCalledTimes(2);
    expect(response.on).toHaveBeenCalledWith('finish', jasmine.any(Function));
    expect(response.on).toHaveBeenCalledWith('error', jasmine.any(Function));
  });
});

unit test results with coverage report:

Executing 2 defined specs...
Running in random order... (seed: 16491)

Test Suites & Specs:
(node:86448) ExperimentalWarning: The fs.promises API is experimental

1. 61121812
ā ‹    should process fileFile process finished
   āœ” should process file (17ms)
   āœ” should handle error (9ms)

>> Done!


Summary:

šŸ‘Š  Passed
Suites:  1 of 1
Specs:   2 of 2
Expects: 12 (0 failures)
Finished in 0.046 seconds

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |     100 |    83.33 |     100 |     100 |                   
 index.js      |     100 |       50 |     100 |     100 | 23                
 index.test.js |     100 |      100 |     100 |     100 |                   
---------------|---------|----------|---------|---------|-------------------

source code: https://github.com/mrdulin/jasmine-examples/tree/master/src/stackoverflow/61121812

Upvotes: 1

Related Questions