Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock require.main in Node?

I have a module which is not supposed to be called directly from the command line with Node. For this purpose, I'm checking the main module as indicated in the documentation:

if (require.main === module) {
    console.error('This module cannot be run from the command line.');
} else {
    // Here the module logic...
}

Now I'm writing unit tests for this module (using Mocha/Chai if that matters) and I would like to simulate the case where the module is called directly from the command line, when an error should be printed to stderr.

The rest of the logic is already under test, but I can't get the require.main === module branch covered by my unit tests. I imaging the cleanest way to solve this would be mocking require.main inside the module but I have no idea how to do this. We already use proxyquire to mock dependencies but it doesn't help in this situation.

Any suggestions how to deal with this problem?

like image 298
iman00b Avatar asked Nov 08 '22 07:11

iman00b


1 Answers

It has been 3 years, but I able to simulate the condition.

Concept: stub/mock the compare function which compare between require.main and module.

For this example below: I use modules: rewire, sinon, chai, mocha, and nyc.

There is this index.js

// File: index.js (original)
if (require.main === module)) {
  console.log('Run directly');
} else {
  console.log('Run NOT directly');
}

I create helper which contains function to compare 2 input.

// File: helper.js
function runDirectly(a, b) {
  // Suppose:
  // a: require.main
  // b: module
  return (a === b);
}

module.exports = { runDirectly };

And I modify the index to something like this.

// File: index.js (modified)
const helper = require('./helper.js');

if (helper.runDirectly(require.main, module)) {
  console.log('Run directly');
} else {
  console.log('Run NOT directly');
}

When I try directly from command line, It still run correctly.

$ node index.js
Run directly
$

I create this spec file.

// File: index.spec.js
const rewire = require('rewire');
const sinon = require('sinon');
const { expect } = require('chai');
const helper = require('./helper.js');

describe('Index', function () {
  let sandbox;
  before(function () {
    sandbox = sinon.createSandbox();
  });

  afterEach(function () {
    sandbox.restore();
  });

  it('simulate run directly', function () {
    const stubHelperRunDirectly = sandbox.stub(helper, 'runDirectly');
    // Simulate require.main === module.
    stubHelperRunDirectly.returns(true);
    const stubConsoleLog = sandbox.stub(console, 'log');

    rewire('./index.js');

    expect(stubHelperRunDirectly.calledOnce).to.equal(true);
    expect(stubConsoleLog.calledOnce).to.equal(true);
    expect(stubConsoleLog.args[0][0]).to.equal('Run directly');
  });

  it('simulate run NOT directly', function () {
    const stubHelperRunDirectly = sandbox.stub(helper, 'runDirectly');
    // Simulate: require.main !== module.
    stubHelperRunDirectly.returns(false);
    const stubConsoleLog = sandbox.stub(console, 'log');

    rewire('./index.js');

    expect(stubHelperRunDirectly.calledOnce).to.equal(true);
    expect(stubConsoleLog.calledOnce).to.equal(true);
    expect(stubConsoleLog.args[0][0]).to.equal('Run NOT directly');
  });
});

Then when I run test and coverage, here the result.

$ npx nyc mocha index.spec.js 


  Index
    ✓ simulate run directly
    ✓ simulate run NOT directly


  2 passing (45ms)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   96.77 |      100 |   83.33 |   96.77 |                   
 helper.js     |      50 |      100 |       0 |      50 | 10                
 index.js      |     100 |      100 |     100 |     100 |                   
 index.spec.js |     100 |      100 |     100 |     100 |                   
---------------|---------|----------|---------|---------|-------------------
$

Now index.js has 100% coverage and helper.js is easy to test. :)

like image 173
andreyunugro Avatar answered Nov 14 '22 22:11

andreyunugro