proxyquire

repository·master·Indexed 25 days ago

https://github.com/thlorenz/proxyquire

A Node.js tool that proxies the require function to allow overriding dependencies during testing. It enables stubbing modules without changing source code, supporting features like callThru control, module reloading via noPreserveCache(), and global overrides using @global and @runtimeGlobal properties.

Tokens
1.8K
Snippets
8
Records
14
Agent score
33%

What's inside proxyquire

  1. Overview of proxyquire

    master
    proxyquire proxies Node.js's require to make overriding dependencies during testing easy and unobtrusive. It allows you to stub modules without changing your source code. Non-overridden methods of a module behave like the original by default.
  2. Simulate the absence of modules

    master

    To test how your code behaves when a module is missing (e.g., inside a try/catch block), set the stub for that module to null. This works even if the module is actually present on the system.

    var foo = proxyquire('./foo', { cluster: null });
  3. Basic usage of proxyquire to override dependencies

    master

    To override dependencies in your tests, import proxyquire and call it with the path to the module you want to test and an object containing your stubs.

    Note: Module paths in the stubs object must be relative to the tested module, not the test file itself. Specify them exactly as they appear in the require statements inside the module being tested.

    var proxyquire = require('proxyquire');
    
    // Stubbing a dependency named 'path' in the module './foo'
    var foo = proxyquire('./foo', { 'path': pathStub });
  4. Remove compatibility mode for proxyquire v0.3.x

    master
    Compatibility mode for proxyquire v0.3.x has been removed. If your codebase relies on the older API, you must pin your proxyquire version to ~0.6 in your package.json to maintain functionality.
  5. Resolve and override dependencies with proxyquire

    master

    You can use proxyquire to load a module while simultaneously providing stubs for its dependencies. This is typically done by passing an object where keys are the dependency paths and values are the stub objects.

    /*
     * Option a) Resolve and override in one step
     */
    var foo = proxyquire('../foo', {
      './bar': { toAtm: function (val) { return 0; } }
    });
    
    /*
     * 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; };
  6. Manage callThru behavior for proxyquire instances

    master

    You can control whether all future stubs resolved by a proxyquire instance default to calling through or not.

    • Disable callThru for all stubs: Use require('proxyquire').noCallThru().
    • Enable callThru for all stubs: Use proxyquire.callThru() to restore default behavior.

    You can override a global noCallThru() setting for a specific module by passing '@noCallThru': false in that module's stub configuration.

  7. Globally override require during module runtime with @runtimeGlobal

    master

    If a module performs a require call inside a function (at runtime) rather than at the top level (during module initialization), use the @runtimeGlobal property.

    This ensures that the stub is applied every time the module is requested via require at runtime, because the module cache is bypassed. Use this only if you cannot guarantee that your modules have static require behavior, as it can lead to subtle bugs.

    var stubs = {
      'd': {
        method: function(val) {
          console.info('hello world');
        },
        '@runtimeGlobal': true
      }
    };
  8. Force module reloading with noPreserveCache()

    master

    By default, proxyquire behaves like Node.js require and pulls modules from the cache. To ensure a module is loaded fresh every time (to reset state or re-initialize), use noPreserveCache().

    To return to standard Node.js caching behavior, use preserveCache().

  9. Set special properties on function stubs

    master

    If you are overriding a module that exports a function directly, you can still attach special properties like @global by using Object.assign or by assigning properties to a named function variable.

    function foo () {}
    proxyquire('./bar', {
      foo: Object.assign(foo, {'@global': true})
    });
  10. Use proxyquire() API

    master

    The primary API for proxyquire is proxyquire({string} request, {Object} stubs).

    • request: The path to the module you want to test (e.g., '../lib/foo').
    • stubs: An object where keys are module paths (relative to the tested module) and values are the stubs. Stubs can be functions, objects, or key/value pairs of functions/properties representing the override.
    proxyquire('./foo', { 'path': pathStub });
  11. Globally override require with @global

    master

    Use the @global property to override every require of a module, even transitively. This is useful when a dependency is required deep within a dependency tree and you cannot reach it via standard stubbing.

    Warning: This is highly intrusive. It bypasses the Node.js require cache, meaning module initialization code will be re-executed for each require. This can cause unexpected side effects if modules perform actions like opening files or setting up listeners during initialization.

    To use it, add '@global': true to your stub object.

    var bazStub = {
      method: function() {
        console.info('goodbye');
      }
    };
      
    var stubs = {
      './baz': Object.assign(bazStub, {'@global': true}) 
    };
    
    var proxyquire = require('proxyquire');
    var foo = proxyquire('./foo', stubs);
  12. Prevent call thru to original dependency

    master

    By default, if a method is not found on a stub, proxyquire calls the original dependency (this is called callThru). You can disable this behavior to ensure stubs are used strictly or to handle classes/instances correctly.

    Per-module via class property

    If your stub is a class, you can set a static property:

    class MockClass {
      static '@noCallThru' = true;
    }

    If your stub is a class instance, use a getter:

    class MockClass {
      get '@noCallThru'() {
        return true;
      }
    }

    Per-module via stub configuration

    You can add the '@noCallThru': true key to the stub object for a specific module:

    var foo = proxyquire('./foo', {
      path: {
        extname: function (file) { /* stub */ },
        '@noCallThru': true
      }
    });
    var foo = proxyquire('./foo', {
      path: {
        extname: function (file) { ... }
      , '@noCallThru': true
      }
    });