Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
proxyquire
Advanced tools
Proxies nodejs require in order to allow overriding dependencies during testing.
Proxyquire is a powerful tool for stubbing and mocking dependencies in Node.js unit tests. It allows you to override dependencies during testing without modifying the actual code, making it easier to isolate and test individual modules.
Basic Dependency Override
This feature allows you to override a dependency with a mock implementation. In this example, the './dependency' module's 'myFunction' is replaced with a mock function that returns 'mocked value'.
const proxyquire = require('proxyquire');
const myModule = proxyquire('./myModule', {
'./dependency': { myFunction: () => 'mocked value' }
});
console.log(myModule.useDependency()); // Outputs: 'mocked value'
Override Multiple Dependencies
This feature allows you to override multiple dependencies at once. In this example, both './dependency1' and './dependency2' are replaced with mock implementations.
const proxyquire = require('proxyquire');
const myModule = proxyquire('./myModule', {
'./dependency1': { myFunction1: () => 'mocked value 1' },
'./dependency2': { myFunction2: () => 'mocked value 2' }
});
console.log(myModule.useDependencies()); // Outputs: 'mocked value 1 and mocked value 2'
Conditional Overrides
This feature allows you to conditionally override dependencies based on certain conditions, such as environment variables. In this example, the './dependency' module is only mocked if the TEST_ENV environment variable is set.
const proxyquire = require('proxyquire');
const myModule = proxyquire('./myModule', {
'./dependency': process.env.TEST_ENV ? { myFunction: () => 'mocked value' } : require('./dependency')
});
console.log(myModule.useDependency()); // Outputs: 'mocked value' if TEST_ENV is set, otherwise the real value
Sinon is a popular library for creating spies, stubs, and mocks in JavaScript. Unlike Proxyquire, which focuses on overriding dependencies, Sinon provides a more comprehensive set of tools for creating test doubles and verifying interactions.
Rewire is another library that allows you to modify the behavior of modules during testing. It provides a similar functionality to Proxyquire but with a different API. Rewire allows you to access private variables and functions within a module, which can be useful for more fine-grained control.
Mock-require is a simpler alternative to Proxyquire that allows you to mock Node.js modules. It provides a straightforward API for replacing modules with mock implementations, but it lacks some of the advanced features of Proxyquire.
Proxies nodejs's require in order to make overriding dependencies during testing easy while staying totally unobstrusive.
If you want to stub dependencies for your client side modules, try proxyquireify, a proxyquire for browserify v2.
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.equal(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.equal(foo.extnameAllCaps('file.txt'), 'EXTERMINATE, EXTERMINATE THE FILE.TXT');
// path.basename and all other path module methods still function as before
assert.equal(foo.basenameAllCaps('/a/b/file.txt'), 'FILE.TXT');
Table of Contents generated with DocToc
Two simple steps to override require in your tests:
var proxyquire = require('proxyquire');
to top level of your test fileproxyquire(...)
the module you want to test and pass along stubs for modules you want to overrideproxyquire({string} request, {Object} stubs)
../lib/foo
{ modulePath: stub, ... }
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 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
}
});
// 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');
proxyquire.callThru();
Call thru config per module wins:
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
}
});
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);
We are testing foo which depends on bar:
// bar.js module
module.exports = {
toAtm: function (val) { return 0.986923267 * val; }
};
// foo.js module
// requires bar which we will stub out in tests
var bar = require('./bar');
[ ... ]
Tests:
// foo-test.js module which is one folder below foo.js (e.g., in ./tests/)
/*
* Option a) Resolve and override in one step:
*/
var foo = proxyquire('../foo', {
'./bar': { toAtm: function (val) { return 0; /* wonder what happens now */ } }
});
// [ .. run some tests .. ]
/*
* Option b) Resolve with empty stub and add overrides later
*/
var barStub = { };
var foo = proxyquire('../foo', { './bar': barStub });
// Add override
barStub.toAtm = function (val) { return 0; /* wonder what happens now */ };
[ .. run some tests .. ]
// Change override
barStub.toAtm = function (val) { return -1 * val; /* or now */ };
[ .. run some tests .. ]
// Resolve foo and override multiple of its dependencies in one step - oh my!
var foo = proxyquire('./foo', {
'./bar' : {
toAtm: function (val) { return 0; /* wonder what happens now */ }
}
, path : {
extname: function (file) { return 'exterminate the name of ' + file; }
}
});
To upgrade your project from v0.3.x to v0.4.x, a nifty compat function has been included.
Simply do a global find and replace for require('proxyquire')
and change them to require('proxyquire').compat()
.
This returns an object that wraps the result of proxyquire()
that provides exactly the same API as v0.3.x.
If your test scripts relied on the fact that v0.3.x stored noCallThru
in the module scope, you can use
require('proxyquire').compat(true)
to use a global compat object, instead.
For more examples look inside the examples folder or look through the tests
Specific Examples:
FAQs
Proxies nodejs require in order to allow overriding dependencies during testing.
The npm package proxyquire receives a total of 416,888 weekly downloads. As such, proxyquire popularity was classified as popular.
We found that proxyquire demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.