Proxyquire
🔮 Proxies nodejs require in order to allow overriding dependencies during testing.
Install / Use
/learn @thlorenz/ProxyquireREADME
proxyquire 
Proxies nodejs's require in order to make overriding dependencies during testing easy while staying totally unobtrusive.
If you want to stub dependencies for your client side modules, try proxyquireify, a proxyquire for browserify v2 or proxyquire-universal to test in both Node and the browser.
Features
- no changes to your code are necessary
- non overridden methods of a module behave like the original
- mocking framework agnostic, if it can stub a function then it works with proxyquire
- "use strict" compliant
Example
foo.js:
var path = require('path');
module.exports.extnameAllCaps = function (file) {
return path.extname(file).toUpperCase();
};
module.exports.basenameAllCaps = function (file) {
return path.basename(file).toUpperCase();
};
foo.test.js:
var proxyquire = require('proxyquire')
, assert = require('assert')
, pathStub = { };
// when no overrides are specified, path.extname behaves normally
var foo = proxyquire('./foo', { 'path': pathStub });
assert.strictEqual(foo.extnameAllCaps('file.txt'), '.TXT');
// override path.extname
pathStub.extname = function (file) { return 'Exterminate, exterminate the ' + file; };
// path.extname now behaves as we told it to
assert.strictEqual(foo.extnameAllCaps('file.txt'), 'EXTERMINATE, EXTERMINATE THE FILE.TXT');
// path.basename and all other path module methods still function as before
assert.strictEqual(foo.basenameAllCaps('/a/b/file.txt'), 'FILE.TXT');
You can also replace functions directly:
get.js:
var get = require('simple-get');
var assert = require('assert');
module.exports = function fetch (callback) {
get('https://api/users', callback);
};
get.test.js:
var proxyquire = require('proxyquire').noCallThru();
var assert = require('assert');
var fetch = proxyquire('./get', {
'simple-get': function (url, callback) {
process.nextTick(function () {
callback(null, { statusCode: 200 })
})
}
});
fetch(function (err, res) {
assert(res.statusCode, 200)
});
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
Table of Contents generated with DocToc
- Usage
- API
- Backwards Compatibility for proxyquire v0.3.x
- Examples
- More Examples
Usage
Two simple steps to override require in your tests:
- add
var proxyquire = require('proxyquire');to top level of your test file proxyquire(...)the module you want to test and pass along stubs for modules you want to override
API
proxyquire({string} request, {Object} stubs)
- request: path to the module to be tested e.g.,
../lib/foo - stubs: key/value pairs of the form
{ modulePath: stub, ... }- module paths are relative to the tested module not the test file
- therefore specify it exactly as in the require statement inside the tested file
- values themselves are key/value pairs of functions/properties and the appropriate override
Preventing call thru to original dependency
By default proxyquire calls the function defined on the original dependency whenever it is not found on the stub.
If you prefer a more strict behavior you can prevent callThru on a per module or contextual basis. If your stub is a class or class instance rather than a plain object, you should disable callThru to ensure that it is passed through with the correct prototype.
class MockClass {
static '@noCallThru' = true;
}
var foo = proxyquire('./foo', {
'./my-class': MockClass
});
class MockClass {
get '@noCallThru'() {
return true;
}
}
var foo = proxyquire('./foo', {
'./my-class-instance': new MockClass()
});
If callThru is disabled, you can stub out modules that don't even exist on the machine that your tests are running on. While I wouldn't recommend this in general, I have seen cases where it is legitimately useful (e.g., when requiring global environment configs in json format that may not be available on all machines).
Prevent call thru on path stub:
var foo = proxyquire('./foo', {
path: {
extname: function (file) { ... }
, '@noCallThru': true
}
});
Prevent call thru for all future stubs resolved by a proxyquire instance
// all stubs resolved by proxyquireStrict will not call through by default
var proxyquireStrict = require('proxyquire').noCallThru();
// all stubs resolved by proxyquireNonStrict will call through by default
var proxyquireNonStrict = require('proxyquire');
Re-enable call thru for all future stubs resolved by a proxyquire instance
proxyquire.callThru();
Call thru configurations per module override callThru():
Passing @noCallThru: false when configuring modules will override noCallThru():
var foo = proxyquire
.noCallThru()
.load('./foo', {
// no calls to original './bar' methods will be made
'./bar' : { toAtm: function (val) { ... } }
// for 'path' module they will be made
, path: {
extname: function (file) { ... }
, '@noCallThru': false
}
});
All together, now
var proxyquire = require('proxyquire').noCallThru();
// all methods for foo's dependencies will have to be stubbed out since proxyquire will not call through
var foo = proxyquire('./foo', stubs);
proxyquire.callThru();
// only some methods for foo's dependencies will have to be stubbed out here since proxyquire will now call through
var foo2 = proxyquire('./foo', stubs);
Using proxyquire to simulate the absence of Modules
Some libraries may behave differently in the presence or absence of a package, for example:
var cluster;
try {
cluster = require('cluster');
} catch(e) {
// cluster module is not present.
cluster = null
}
if (cluster) {
// Then provide some functionality for a cluster-aware version of Node.js
} else {
// and some alternative for a cluster-unaware version.
}
To exercise the second branch of the if statement, you can make proxyquire pretend the package isn't present by
setting the stub for it to null. This works even if a cluster module is actually present.
var foo = proxyquire('./foo', { cluster: null });
Forcing proxyquire to reload modules
In most situations it is fine to have proxyquire behave exactly like nodejs require, i.e. modules that are loaded once
get pulled from the cache the next time.
For some tests however you need to ensure that the module gets loaded fresh everytime, i.e. if that causes initializing some dependency or some module state.
For this purpose proxyquire exposes the noPreserveCache function.
// ensure we don't get any module from the cache, but to load it fresh every time
var proxyquire = require('proxyquire').noPreserveCache();
var foo1 = proxyquire('./foo', stubs);
var foo2 = proxyquire('./foo', stubs);
var foo3 = require('./foo');
// foo1, foo2 and foo3 are different instances of the same module
assert.notStrictEqual(foo1, foo2);
assert.notStrictEqual(foo1, foo3);
proxyquire.preserveCache allows you to restore the behavior to match nodejs's require again.
proxyquire.preserveCache();
var foo1 = proxyquire('./foo', stubs);
var foo2 = proxyquire('./foo', stubs);
var foo3 = require('./foo');
// foo1, foo2 and foo3 are the same instance
assert.strictEqual(foo1, foo2);
assert.strictEqual(foo1, foo3);
Globally override require
Use the @global property to override every require of a module, even transitively.
Caveat
You should think very hard about alternatives before using this feature. Why, because it's intrusive and as you'll see if you read on it changes the default behavior of module initialization which means that code runs differently during testing than it does normally.
Additionally it makes it harder to reason about how your tests work.
Yeah, we are mocking
fsthree levels down inbar, so that's why we have to set it up when testingfoo
WAAAT???
If you write proper unit tests you should never have a need for this. So here are some techniques to consider:
- test each module in isolatio
Related Skills
node-connect
349.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
