felixge/node-sandboxed-module

nyc builtin source transformer

Opened this issue · 4 comments

Related to #25.

It'd be nice if the istanbul transformer also supported nyc, which in turn supports subprocesses. I got this working with the following voodoo, but I wasn't sure whether this was the supported mechanism per https://github.com/istanbuljs/nyc. Thoughts? Is this in scope?

function maybeCoverage() {
  return Object.keys(require.cache).some((path) => /node_modules\/nyc/.test(path));
}

SandboxedModule.require('.../index.js', {
  // Voodoo magic to support nyc.
  sourceTransformers: maybeCoverage() ? {
    nyc(source) {
      const Instrumenter = require('nyc/lib/instrumenters/istanbul'),
        instrumenter = Instrumenter(process.cwd(), {}),
        instrumentMethod = instrumenter.instrumentSync.bind(instrumenter);
      return instrumentMethod(source, this.filename);
    }
  } : {}
});

Where should I put this snippet?

In a test fixture or mock where you have access to SandboxedModule.

The way I use the above snippet is the following:

nycTransformer.js (placed at the root of my test folder)

'use strict';

function maybeCoverage() {
  return Object.keys(require.cache).some((path) => (/node_modules\/nyc/).test(path));
}

module.exports = maybeCoverage() ? {
  nyc(source) {
    const Instrumenter = require('nyc/lib/instrumenters/istanbul');
    const instrumenter = Instrumenter(process.cwd(), {});
    const instrumentMethod = instrumenter.instrumentSync.bind(instrumenter);
    return instrumentMethod(source, this.filename);
  },
} : {};

Then in test.js

'use strict';

const assert = require('assert');
const nycTransformer = require('../nycTransformer');
const sandbox = require('sandboxed-module');

it('should do something', function onTest() {
  const sandboxedFile = sandbox.require('path', {
     singleOnly: true,
     requires: { /* */},
     sourceTransformers: nycTransformer,
  });
  assert('something');
});

I hope that helps!