Search code examples
node.jsnpmnyc

npm run coverage fails with "require(...).internalModuleStat is not a function"


When we run our tests with npm run test, they pass. When we run with npm run coverage, though, some fail with this error:

'internal/modules/cjs/loader.js:58\n' +
    "const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };\n" +
    '                                                               ^\n' +
    '\n' +
    'TypeError: require(...).internalModuleStat is not a function\n' +
    '    at internalModuleStat (internal/modules/cjs/loader.js:58:64)\n' +
    '    at stat (internal/modules/cjs/loader.js:137:18)\n' +
    '    at Function.Module._findPath (internal/modules/cjs/loader.js:667:16)\n' +
    '    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:967:27)\n' +
    '    at Function.Module._load (internal/modules/cjs/loader.js:862:27)\n' +
    '    at Module.require (internal/modules/cjs/loader.js:1042:19)\n' +
    '    at Module._preloadModules (internal/modules/cjs/loader.js:1296:12)\n' +
    '    at loadPreloadModules (internal/bootstrap/pre_execution.js:449:5)\n' +
    '    at prepareMainThreadExecution (internal/bootstrap/pre_execution.js:73:3)\n' +
    '    at internal/bootstrap/pkg.js:7:1\n'

What can be going on here?


Solution

  • This can happen for many reasons. Here is a common root cause of similar problems:

    Something may be messing up with the values of the NODE_OPTIONS variable.

    The problem can be something else, but I would check the value NODE_OPTIONS as a possible culprit.

    To understand why here is a...

    Case study

    Here, we use both nyc (the test coverage tool) and pkg.

    nyc sets an environment variable called NODE_OPTIONS; pkg, also, checks the value of this variable. So when we run coverage, the variable is changed by nyc. The value nyc sets, though, does not make sense to pkg. pkg gets lost then.

    How we solve it

    Our solution was to reset the variable before running the tests.

    In our case, we use Mocha, so we had a line like this in our package.json:

    "scripts": {
      "coverage": "nyc --reporter=lcov --include='src/**/*.js' npm test",
      "test": "./node_modules/.bin/mocha --require @babel/register --recursive --exit",
    }
    

    We just added NODE_OPTIONS='' before calling mocha:

    "scripts": {
      "coverage": "nyc --reporter=lcov --include='src/**/*.js' npm test",
      "test": "NODE_OPTIONS='' ./node_modules/.bin/mocha --require @babel/register --recursive --exit",
    }
    

    Now, npm run coverage runs nyc, which sets the variable as needed. nyc then calls npm run test, whose script cleans up the variable.

    Your mileage may vary

    Maybe your problem is not the same as the one above, or NODE_OPTIONS is messed up somewhere else. I hope, though, this answer can help you to figure out what is going on then.