Skip to content
This repository has been archived by the owner on Apr 30, 2024. It is now read-only.

Register allowed modules via regexp #38

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ and similarly to deregister several modules at once, as you would expect:

mockery.deregisterAllowables(['async', 'path', 'util']);

Sometimes it's useful to allow bunch of modules without a warnings.
For example, when your code transpiled via babel. In that case you can allow them

mockery.registerAllowableRegExp(/.+\$\.object-assign/ig);

and similarly to deregister module, as you would expect:

mockery.deregisterAllowableRegExp(/.+\$\.object-assign/ig);

### Unhooking

By default, the Node module loader will load a given module only once, caching
Expand Down
67 changes: 65 additions & 2 deletions mockery.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var m = require('module'),
registeredMocks = {},
registeredSubstitutes = {},
registeredAllowables = {},
registeredAllowableRegExps = {},
originalLoader = null,
originalCache = null,
defaultOptions = {
Expand Down Expand Up @@ -96,6 +97,10 @@ function hookedLoader(request, parent, isMain) {

if (registeredAllowables.hasOwnProperty(request)) {
allow = registeredAllowables[request];
} else {
allow = isRequesRegisteredAsRegexp(request);
}
if (allow) {
if (allow.unhook) {
file = m._resolveFilename(request, parent);
if (file.indexOf('/') !== -1 && allow.paths.indexOf(file) === -1) {
Expand Down Expand Up @@ -257,6 +262,42 @@ function registerAllowables(mods, unhook) {
});
}

/**
* Register a module as 'allowed' using regular expression as a module name,
* even if a mock or substitute for it has not been registered, mockery will
* not complain when it is loaded via 'require'.
*/
function registerAllowableRegExp(regExp, unhook) {
registeredAllowableRegExps[regExp] = {
unhook: !!unhook,
paths: [],
regExp: regExp
};
}

/**
* check if request is 'allowed'
* @param request {String}
*/
function isRequesRegisteredAsRegexp(request) {

var
regExps = Object.keys(registeredAllowableRegExps),
regExpsLen = regExps.length,
allow;

if (!regExpsLen) {
return false;
}
while(regExpsLen--) {
allow = registeredAllowableRegExps[regExps[regExpsLen]];
if (request.match(allow.regExp)) {
return allow;
}
}
return false;
}

/*
* Deregister a module as 'allowed'. A subsequent 'require' for that module
* will generate a warning that the module is not allowed, unless or until a
Expand Down Expand Up @@ -285,14 +326,33 @@ function deregisterAllowables(mods) {
});
}

/*
* Deregister a module as 'allowed' which has been registered as regexp.
* A subsequent 'require' for that module will generate a warning that
* the module is not allowed, unless or until a mock or substitute is
* registered for that module.
*/
function deregisterAllowableRegExp(regExp) {
if (registeredAllowableRegExps.hasOwnProperty(regExp)) {
var allow = registeredAllowableRegExps[regExp];
if (allow.unhook) {
allow.paths.forEach(function (p) {
delete m._cache[p];
});
}
delete registeredAllowableRegExps[regExp];
}
}

/*
* Deregister all mocks, substitutes, and allowed modules, resetting the state
* to a clean slate. This does not affect the enabled / disabled state of
* mockery, though.
*/
function deregisterAll() {
Object.keys(registeredAllowables).forEach(function (mod) {
var allow = registeredAllowables[mod];
Object.keys(registeredAllowables).concat(Object.keys(registeredAllowableRegExps))
.forEach(function (mod) {
var allow = registeredAllowables[mod] || registeredAllowableRegExps[mod];
if (allow.unhook) {
allow.paths.forEach(function (p) {
delete m._cache[p];
Expand All @@ -303,6 +363,7 @@ function deregisterAll() {
registeredMocks = {};
registeredSubstitutes = {};
registeredAllowables = {};
registeredAllowableRegExps = {};
}

// Exported functions
Expand All @@ -315,8 +376,10 @@ exports.registerMock = registerMock;
exports.registerSubstitute = registerSubstitute;
exports.registerAllowable = registerAllowable;
exports.registerAllowables = registerAllowables;
exports.registerAllowableRegExp = registerAllowableRegExp;
exports.deregisterMock = deregisterMock;
exports.deregisterSubstitute = deregisterSubstitute;
exports.deregisterAllowable = deregisterAllowable;
exports.deregisterAllowables = deregisterAllowables;
exports.deregisterAllowableRegExp = deregisterAllowableRegExp;
exports.deregisterAll = deregisterAll;
3 changes: 3 additions & 0 deletions test/fixtures/$.object-assign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exports.foo = function () {
return 'object assign';
};
27 changes: 27 additions & 0 deletions test/logging-allowable.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ var tests = {
mock_console.verify();
mock_console.restore();
},
"requiring the module which is allowed via regexp causes no warning to be logged": function () {
var mock_console, fake_module;

mock_console = sinon.mock(console);
mock_console.expects('warn').never();

mockery.registerAllowableRegExp(/.+\$\.object-assign/ig);
fake_module = require('./fixtures/$.object-assign');
assert.equal(fake_module.foo(), 'object assign');

mock_console.verify();
mock_console.restore();
},
"and the allowable is deregistered": {
topic: function () {
mockery.deregisterAllowable('./fixtures/fake_module');
Expand All @@ -41,6 +54,20 @@ var tests = {
fake_module = require('./fixtures/fake_module');
assert.equal(fake_module.foo(), 'real foo');

mock_console.verify();
mock_console.restore();
},
"requiring the module which is allowed via regexp causes a warning to be logged": function () {
var mock_console, fake_module;

mockery.deregisterAllowableRegExp(/.+\$\.object-assign/ig);

mock_console = sinon.mock(console);
mock_console.expects('warn').once();

fake_module = require('./fixtures/$.object-assign');
assert.equal(fake_module.foo(), 'object assign');

mock_console.verify();
mock_console.restore();
}
Expand Down
5 changes: 5 additions & 0 deletions test/registered.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ var tests = {
mockery.registerAllowable('./fixtures/fake_module');
var fake_module = require('./fixtures/fake_module');
assert.equal(fake_module.foo(), 'real foo');

mockery.registerAllowableRegExp(/.+\$\.object-assign/ig);
//require without a warning
var objectAssign = require('./fixtures/$.object-assign');
assert.equal(objectAssign.foo(), 'object assign');
},
"and mockery is then disabled requiring the module returns the original module": function () {
mockery.disable();
Expand Down