Stub a standalone module.exports function using rewire

I am trying to stub a module.exports function. But I have some trouble. I will give you a sudo code of the situation.

MyController.js

const sendOTPOnPhone = rewire('../../src/services/OtpService/sendOTPOnPhone')

module.exports = async function(req, res) {
         const { error, data } = await sendOTPOnPhone(req.query.phone) //this is I want to stub
         if(error)
           return return res.send(error)
         return res.send(data)
}

sendOTPService.js

module.exports = async function(phone) {
               const result = await fetch(`external-api-call`)
               if(result.status !== 'success')
                  return {
                          error: "Failed to send OTP!",
                          data: null
                  }
               return {
                      error: null,
                      data: result
               }
}

sendOTPTest.js

const expect = require('chai').expect
const request = require('supertest')
const sinon = require('sinon')
const rewire = require('rewire')
const sendOTPOnPhone = rewire('../../src/services/OtpService/sendOTPOnPhone')

const app = require('../../src/app')

describe('GET /api/v1/auth/otp/generate', function () {
    it('should generate OTP', async () => {
        let stub = sinon.stub().returns({
            error: null,
            data: "OTP sent"
        })
        sendOTPOnPhone.__set__('sendOTPOnPhone', stub)
        const result = await request(app)
            .get('/api/v1/auth/otp/generate?phone=8576863491')
            .set('Accept', 'application/json')
            .expect('Content-Type', /json/)
            .expect(200)
        expect(stub.calledOnce).to.be.true
        console.log(result.body)
        // expect(result).to.equal('promise resolved'); 
    })
})

Above test is failing, stub is not being called. I don't know what am I missing? If I do this in my sendOTPService:

const sendOTP = async function() {}
module.exports = {
  sendOTP
}

and this in the controller.

const { error, data } = sendOTPOnPhone.sendOTPOnPhone(req.query.phone)

It works.

But I import it like const {sendOTPOnPhone } = require('../sendOTPService') It doesn't work.

I am aware that destructing changes the reference of the object.
Can someone suggest a workaround?
Is it possible to achieve this using rewire? OR It can be done with proxyquire.
Please can someone suggest?

Answers:

Answer

Here is the integration testing solution using proxyquire, you should use Globally override require.

app.js:

const express = require('express');
const controller = require('./controller');

const app = express();
app.get('/api/v1/auth/otp/generate', controller);

module.exports = app;

controller.js:

let sendOTPOnPhone = require('./sendOTPOnPhone');

module.exports = async function(req, res) {
  const { error, data } = await sendOTPOnPhone(req.query.phone);
  if (error) return res.send(error);
  return res.send(data);
};

sendOTPOnPhone.js:

module.exports = async function(phone) {
  const result = await fetch(`external-api-call`);
  if (result.status !== 'success')
    return {
      error: 'Failed to send OTP!',
      data: null,
    };
  return {
    error: null,
    data: result,
  };
};

sendOTP.test.js:

const request = require('supertest');
const sinon = require('sinon');
const proxyquire = require('proxyquire');

describe('GET /api/v1/auth/otp/generate', function() {
  it('should generate OTP', async () => {
    let stub = sinon.stub().resolves({
      error: null,
      data: { message: 'OTP sent' },
    });
    stub['@global'] = true;
    const app = proxyquire('./app', {
      './sendOTPOnPhone': stub,
    });
    const result = await request(app)
      .get('/api/v1/auth/otp/generate?phone=8576863491')
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200);
    sinon.assert.calledOnce(stub);
    console.log(result.body);
  });
});

Integration test results with coverage report:

  GET /api/v1/auth/otp/generate
{ message: 'OTP sent' }
    ? should generate OTP (2373ms)


  1 passing (2s)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   68.75 |       25 |      50 |   73.33 |                   
 app.js            |     100 |      100 |     100 |     100 |                   
 controller.js     |   83.33 |       50 |     100 |     100 | 5                 
 sendOTPOnPhone.js |      20 |        0 |       0 |      20 | 2-4,8             
-------------------|---------|----------|---------|---------|-------------------

source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/60599945

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.