Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Implemented resolving of relative module names to absolute paths #9

Open
wants to merge 1 commit into from

3 participants

@ichernev

Specifying files to mock by a relative name is not enough if you require the same file multiple times from different directories. So I added an option to mockery to convert all relative filenames to absolute ones, based on the test file for example. There are two advantages of doing so:

  1. You can specify the filenames to mock, relative to the test file -- i.e the same way requires work, so its a no-brainer
  2. Requiring the same file from multiple locations would return the given mock, because all filenames are converted to absolute ones when requiring
@benbuckman

I wonder, couldn't this be done more simply, with path.resolve or require.resolve on all entries to registeredMocks? (Probably as an option in registerMock)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 20, 2012
  1. Implemented resolving of relative module names

    Iskren Chernev authored
This page is out of date. Refresh to see the latest.
Showing with 46 additions and 12 deletions.
  1. +43 −11 mockery.js
  2. +3 −1 package.json
View
54 mockery.js
@@ -33,11 +33,14 @@
*/
var m = require('module'),
+ requireLike = require('require-like'),
registeredMocks = {},
registeredSubstitutes = {},
registeredAllowables = {},
originalLoader = null,
- warnIfUnregistered = true;
+ resolve = null,
+ warnIfUnregistered = true,
+ resolveLikeFile = false;
/*
* The perils of using internal functions. The Node-internal _resolveFilename
@@ -62,41 +65,63 @@ function resolveFilename(request, parent) {
* since it will replace that when mockery is enabled.
*/
function hookedLoader(request, parent, isMain) {
- var subst, allow, file;
+ var subst, allow, file, cachedEntry;
if (!originalLoader) {
throw new Error("Loader has not been hooked");
}
- if (registeredMocks.hasOwnProperty(request)) {
- return registeredMocks[request];
- } else if (registeredSubstitutes.hasOwnProperty(request)) {
- subst = registeredSubstitutes[request];
+ if (resolveLikeFile) {
+ cachedEntry = file = resolveFilename(request, parent);
+ } else {
+ cachedEntry = request;
+ }
+ if (registeredMocks.hasOwnProperty(cachedEntry)) {
+ return registeredMocks[cachedEntry];
+ } else if (registeredSubstitutes.hasOwnProperty(cachedEntry)) {
+ subst = registeredSubstitutes[cachedEntry];
if (!subst.module && subst.name) {
subst.module = originalLoader(subst.name, parent, isMain);
}
if (!subst.module) {
- throw new Error("Misconfigured substitute for '" + request + "'");
+ throw new Error("Misconfigured substitute for '" + cachedEntry + "'");
}
return subst.module;
} else {
- if (registeredAllowables.hasOwnProperty(request)) {
- allow = registeredAllowables[request];
+ if (registeredAllowables.hasOwnProperty(cachedEntry)) {
+ allow = registeredAllowables[cachedEntry];
if (allow.unhook) {
- file = resolveFilename(request, parent);
+ if (!file) {
+ file = resolveFilename(request, parent);
+ }
if (file.indexOf('/') !== -1 && allow.paths.indexOf(file) === -1) {
allow.paths.push(file);
}
}
} else {
if (warnIfUnregistered) {
- console.warn("WARNING: loading non-allowed module: " + request);
+ console.warn("WARNING: loading non-allowed module: " + cachedEntry);
}
}
return originalLoader(request, parent, isMain);
}
}
+function resolveLike(file) {
+ var resolver;
+ resolveLikeFile = file;
+ if (resolveLikeFile) {
+ resolver = requireLike(resolveLikeFile);
+ resolve = function(mod) {
+ return resolver.resolve(mod);
+ }
+ } else {
+ resolve = function(mod) {
+ return mod;
+ }
+ }
+}
+
/*
* Enables mockery by hooking subsequent 'require' invocations. Note that *all*
* 'require' invocations will be hooked until 'disable' is called. Calling this
@@ -142,6 +167,7 @@ function warnOnUnregistered(enable) {
* for anything not mocked and subsequently invoked.
*/
function registerMock(mod, mock) {
+ mod = resolve(mod);
if (registeredMocks.hasOwnProperty(mod)) {
console.warn("WARNING: Replacing existing mock for module: " + mod);
}
@@ -154,6 +180,7 @@ function registerMock(mod, mock) {
* falling back to the original 'require' behaviour).
*/
function deregisterMock(mod) {
+ mod = resolve(mod);
if (registeredMocks.hasOwnProperty(mod)) {
delete registeredMocks[mod];
}
@@ -166,6 +193,7 @@ function deregisterMock(mod) {
* a mock implementation is itself implemented as a module.
*/
function registerSubstitute(mod, subst) {
+ mod = resolve(mod);
if (registeredSubstitutes.hasOwnProperty(mod)) {
console.warn("WARNING: Replacing existing substitute for module: " + mod);
}
@@ -180,6 +208,7 @@ function registerSubstitute(mod, subst) {
* default, means falling back to the original 'require' behaviour).
*/
function deregisterSubstitute(mod) {
+ mod = resolve(mod);
if (registeredSubstitutes.hasOwnProperty(mod)) {
delete registeredSubstitutes[mod];
}
@@ -195,6 +224,7 @@ function deregisterSubstitute(mod) {
* it is deregistered.
*/
function registerAllowable(mod, unhook) {
+ mod = resolve(mod);
registeredAllowables[mod] = {
unhook: !!unhook,
paths: []
@@ -207,6 +237,7 @@ function registerAllowable(mod, unhook) {
* mock or substitute is registered for that module.
*/
function deregisterAllowable(mod) {
+ mod = resolve(mod);
if (registeredAllowables.hasOwnProperty(mod)) {
var allow = registeredAllowables[mod];
if (allow.unhook) {
@@ -249,3 +280,4 @@ exports.deregisterMock = deregisterMock;
exports.deregisterSubstitute = deregisterSubstitute;
exports.deregisterAllowable = deregisterAllowable;
exports.deregisterAll = deregisterAll;
+exports.resolveLike = resolveLike;
View
4 package.json
@@ -20,7 +20,9 @@
"engines": {
"node": ">=0.4.5"
},
- "dependencies": {},
+ "dependencies": {
+ "require-like": "0.1.x"
+ },
"devDependencies": {
"nodeunit" : "0.6.x",
"sinon" : "1.2.x"
Something went wrong with that request. Please try again.