Search code examples
node.jssinonstub

nodejs sinonjs stub on class construcor


I'm using nodejs exif library to retrieve metadata from JPEG files.

this lib is used this way :

import * as exif from 'exif'

new exif.ExifImage('path_to_file.jpg', function(err, metadata){ ... })

I've found everywhere how to stub a class method using sinon, pretty simple.

But I don't get how to stub this class constructor so that metadata (or err if I want to test failing case) will be the stubbed value I need to perform my test.


Solution

  • We can still use Sinon with callsFake function. Here is the example:

    // src.js
    
    const exif = require("exif");
    
    function readImage() {
      // convert to promise for easier testing
      return new Promise((resolve, reject) => {
        new exif.ExifImage("path_to_file.jpg", function(err, metadata) {
          if (err) {
            reject(err);
          }
    
          resolve(metadata);
        });
      });
    }
    
    module.exports = { readImage };
    
    

    meanwhile for test

    // test.js
    
    const sinon = require('sinon');
    const src = require('./src');
    const exif = require('exif');
    const expect = require('chai').expect;
    
    describe('test exifimage', () => {
      let exifStub;
    
      beforeEach(function() {
        exifStub = sinon.stub(exif, 'ExifImage')
      })
    
      afterEach(function() {
        sinon.restore();
      })
    
      it('test when success', async () => {
        const metadata = 'cinta';
    
        // mock ExifImage as similar as its function signature
        exifStub.callsFake((filename, callback) => {
          callback(null, metadata); // error is set as null then we set metadata
        });
    
        const response = await src.readImage();
    
        expect(response).to.equal(metadata);
      });
    
      it('test when error', async () => {
        const errorMessage = 'this is error';
    
        exifStub.callsFake((filename, callback) => {      
          callback(errorMessage); // specify error, error is defined as first param
        });
    
        try {
          await src.readImage();
        } catch (error) {
          expect(error).to.equal(errorMessage);
        }
      });
    });
    

    Hope it helps