简体   繁体   中英

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?

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. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM