Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add vm.runInThisContext hook and automatically call it on run-with-cover for RequireJS support #26

Merged
merged 2 commits into from
Jan 3, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/command/common/run-with-cover.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ function run(args, commandName, enableHooks, callback) {
if (opts['self-test']) {
hook.unloadRequireCache(matchFn);
}
// runInThisContext is used by RequireJS [issue #23]
hook.hookRunInThisContext(matchFn, transformer, hookOpts);
hook.hookRequire(matchFn, transformer, hookOpts);
process.once('exit', function () {
var file = path.resolve(reportingDir, 'coverage.json'),
Expand Down
36 changes: 35 additions & 1 deletion lib/hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ var fs = require('fs'),
Module = require('module'),
vm = require('vm'),
originalLoader = Module._extensions['.js'],
originalCreateScript = vm.createScript;
originalCreateScript = vm.createScript,
originalRunInThisContext = vm.runInThisContext;

function transformFn(matcher, transformer, verbose) {

Expand Down Expand Up @@ -139,11 +140,44 @@ function unhookCreateScript() {
vm.createScript = originalCreateScript;
}


/**
* hooks `vm.runInThisContext` to return transformed code.
* @method hookRunInThisContext
* @static
* @param matcher {Function(filePath)} a function that is called with the filename passed to `vm.createScript`
* Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise
* @param transformer {Function(code, filePath)} a function called with the original code and the filename passed to
* `vm.createScript`. Should return the transformed code.
* @param options {Object} options Optional.
* @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called
*/
function hookRunInThisContext(matcher, transformer, opts) {
opts = opts || {};
var fn = transformFn(matcher, transformer, opts.verbose);
vm.runInThisContext = function (code, file) {
var ret = fn(code, file);
return originalRunInThisContext(ret.code, file);
};
}

/**
* unhooks vm.runInThisContext, restoring it to its original state.
* @method unhookRunInThisContext
* @static
*/
function unhookRunInThisContext() {
vm.runInThisContext = originalRunInThisContext;
}


module.exports = {
hookRequire: hookRequire,
unhookRequire: unhookRequire,
hookCreateScript: hookCreateScript,
unhookCreateScript: unhookCreateScript,
hookRunInThisContext : hookRunInThisContext,
unhookRunInThisContext : unhookRunInThisContext,
unloadRequireCache: unloadRequireCache
};

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"rimraf": "*",
"nodeunit": "*",
"jshint": "*",
"yui-lint": "*"
"yui-lint": "*",
"requirejs": "2.x"
},
"TODO": [
"Need a legend for the HTML report + some explanation on how branch coverage is shown",
Expand Down
11 changes: 11 additions & 0 deletions test/cli/sample-project/amd/ipsum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
define(function(){

function sum(a, b) {
return a + b;
}

return {
sum : sum
};

});
7 changes: 7 additions & 0 deletions test/cli/sample-project/amd/lorem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
define(['./ipsum'], function (ipsum) {

return function exec(a, b, c){
return ipsum.sum(a, b) * c;
};

});
16 changes: 16 additions & 0 deletions test/cli/sample-project/test/amd-run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RequireJS uses `vm.runInThisContext` see issue #23
// make sure we add hooks for it as well

var rjs = require('requirejs'),
assert = require('assert');

rjs.config({
baseUrl : __dirname,
nodeRequire : require
});

rjs(['../amd/lorem'], function(lorem){
var result = lorem(1, 2, 3);
assert.equal(9, result);
});

18 changes: 17 additions & 1 deletion test/cli/test-cover-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,21 @@ module.exports = {
test.ok(results.grepError(/Unable to resolve file/));
test.done();
});
},
"should work with RequireJS and AMD modules": function (test) {
helper.setOpts({ lazyHook : true });
run([ 'test/amd-run.js', '-v' ], function (results) {
test.ok(results.succeeded());
test.ok(results.grepError(/Module load hook:/));
test.ok(existsSync(path.resolve(OUTPUT_DIR, 'lcov.info')));
test.ok(existsSync(path.resolve(OUTPUT_DIR, 'lcov-report')));
test.ok(existsSync(path.resolve(OUTPUT_DIR, 'coverage.json')));
var coverage = JSON.parse(fs.readFileSync(path.resolve(OUTPUT_DIR, 'coverage.json'), 'utf8')),
filtered;
filtered = Object.keys(coverage).filter(function (k) { return k.match(/amd\/lorem/) || k.match(/amd\/ipsum/); });
test.ok(filtered.length === 2);
test.ok(filtered.length === Object.keys(coverage).length);
test.done();
});
}
};
};