rewiremock

repository·master·Indexed 19 days ago

https://github.com/thekashey/rewiremock

An advanced dependency mocking library for JavaScript and TypeScript (version 3.14.6) that intercepts module imports to provide stubs. It supports CommonJS and ESM environments, offering features such as hoisted mocking via a Babel plugin, type-safe mocking for TypeScript/Flow, and integration with Node.js and Webpack. The library provides various APIs for dynamic mock modification, scoped mocking with .around(), and isolation control to ensure all dependencies are properly mocked.

Tokens
10.1K
Snippets
48
Records
50
Agent score
18%

What's inside rewiremock

  1. Automocking with __mocks__

    master

    Rewiremock supports automatic mocking inspired by Jest. If you create a file at __mocks__/fileName.js, rewiremock will automatically replace fileName.js with that mock.

    To prevent a specific file from being replaced by its automatic mock, use .disable() on the module.

    // Disable an automatic mock
    rewiremock('fileName.js').disable();
  2. How to choose the right mocking API

    master

    Rewiremock provides several ways to activate a mock depending on your needs:

    MethodBest Use Case
    rewiremock.proxySimple mocking (proxyquire-like).
    rewiremock.moduleWhen you have name resolution issues; allows manual resolution via a loader.
    rewiremock.aroundWhen you need scope isolation or advanced syntax/type checking.
    rewiremock.enable/disableLow-level, global interceptor control (mockery-like).
    inScopeWhen you need to place a synchronous callback inside a sandbox.
  3. Use Guided Mocking with imports/requires

    master

    Guided mocking allows you to use standard import or require statements to resolve filenames, letting Rewiremock handle the transformation behind the scenes.

    Important constraints:

    1. Synchronous API: Resolution happens during .enable(). If you use a synchronous rewiremock(() => require(...)) call, it must happen before rewiremock.enable().
    2. Async API: Using import() inside a synchronous rewiremock() call will throw an error.
    3. Async Requirements: If you need to mock an async import, you must use the async APIs: rewiremock.module() or rewiremock.around().
    // Correct: Synchronous require inside guided mock
    rewiremock(() => require('./fileToMock1'));
    rewiremock.enable();
    
    // Correct: Using async API for async imports
    rewiremock.module(() => import('file'));
    
    // Correct: Using around for complex async setups
    rewiremock.around(..., rw => rw.mock(() => import('file2')));
  4. Manage Mock Lifecycle with enable() and disable()

    master

    To run tests with mocks, you must manually enable and disable Rewiremock.

    • rewiremock.enable(): Wipes all mocked modules from the cache and all modules that require them (including your test). This ensures the mocks are applied fresh.
    • rewiremock.disable(): Restores the original modules.

    Best Practice (Mocha/Jest): Use beforeEach and afterEach hooks to manage the lifecycle.

    Note: Unrelated dependencies (Node modules, React, etc.) are kept in cache to ensure tests run faster.

    // In mocha tests
    beforeEach( () => rewiremock.enable() );
    
    // ... run tests ...
    
    afterEach( () => rewiremock.disable() );
  5. Setup rewiremock for different environments

    master

    To preconfigure rewiremock for all tests, it is recommended to create a central configuration file (e.g., rewiremock.js) rather than importing it directly in every test. The setup depends on your runtime/module system:

    TS/ES6/ESM

    Use import. You must call rewiremock.overrideEntryPoint(module) to transfer the module parent to rewiremock.

    CommonJS/Node.js

    Use require('rewiremock/node'). You must call rewiremock.overrideEntryPoint(module).

    Webpack

    Use import rewiremock from 'rewiremock/webpack'. You must call rewiremock.overrideEntryPoint(module) and add necessary plugins to your webpack test configuration.

    // rewiremock.es6.js (TS/ES6/ESM)
    import rewiremock from 'rewiremock';
    // settings...
    rewiremock.overrideEntryPoint(module); 
    export { rewiremock }
    // rewiremock.cjs.js (CommonJS/Node.js)
    const rewiremock = require('rewiremock/node'); 
    // settings...
    rewiremock.overrideEntryPoint(module);
    module.exports = rewiremock;
    // rewiremock.es6.js (Webpack)
    import rewiremock from 'rewiremock/webpack';
    // settings...
    rewiremock.overrideEntryPoint(module);
    export { rewiremock }
  6. Setup Rewiremock for Node.js

    master

    To use Rewiremock in a Node.js environment, you can use the standard entry point or a specialized Node.js entry point that has the Node.js plugin activated and exports as ES5.

    Standard usage:

    const rewiremock = require('rewiremock').default;

    Node-optimized usage:

    const rewiremock = require('rewiremock/node');
  7. Enable Type Safety for Mocks

    master

    Rewiremock supports type-safe mocking (for TypeScript or Flow) by validating that your mocks match the original module's exports and types.

    Requirements for Type Safety:

    1. Use TypeScript or Flow.
    2. Use dynamic import() syntax.
    3. Use rewiremock.around or rewiremock.module.
    4. Use the async form of mock declaration.

    If a default export is missing, a named export is missing, or types do not match, the type system will throw an error. Use .nonStrict() to temporarily disable the type system for specific mocks.

    // @flow
    import rewiremock from 'rewiremock';
    
    rewiremock.around(
      () => import('./a.js'), 
      mock => {
      mock(() => import('./b.js'))
        .withDefault(() => "4")
        .with({testB: () => 10})
        .nonStrict() // turn off type system
        .with({ absolutely: "anything" })
      }
    );
  8. Integrate rewiremock with Jest

    master

    Rewiremock and Jest are generally incompatible because Jest has its own mocking system. If you must use them together, follow these steps at the beginning of your test file:

    1. Disable Jest's auto-mocking.
    2. Restore module nesting using rewiremock.overrideEntryPoint(module).
    3. Override the global require with rewiremock.requireActual to bypass Jest's sandboxing/transformation (Note: this may disable Jest magics).
    4. If using ES6/imports, you must manually apply Babel (e.g., via babel-register) inside describe or it blocks, as Jest's sandboxing will reset settings to default at the top level.
    // better to disable auto mock
    jest.disableAutomock();
    
    // Jest breaks the rules, and you have to restore nesting of modules.
    rewiremock.overrideEntryPoint(module);
    
    // There is no way to use overload by Jest require or requireActual.
    // use the version provided by rewiremock.
    require = rewiremock.requireActual;
    
    // To use ES6/imports, apply Babel inside the test block
    describe('block of tests', () => {
      require("babel-register");
    })
  9. Setup Rewiremock for Webpack

    master

    Rewiremock can run inside a webpack environment (client-side mocking). To enable this, you must include three specific plugins in your webpack configuration:

    1. webpack.NamedModulesPlugin(): Ensures modules use real names instead of numeric IDs.
    2. webpack.HotModuleReplacementPlugin(): Provides module connection information.
    3. rewiremock.webpackPlugin: The core plugin for Rewiremock magic.

    Webpack Configuration:

    plugins: [
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new (require("rewiremock/webpack/plugin"))()
    ]

    Developer Experience Tip: Import rewiremock/webpack for a better development experience.

    Troubleshooting:

    • If you see TypeError: Cannot read property 'webpackHotUpdate' of undefined, avoid using babel-register when running webpack bundles; use babel to create bundles instead.
    • If you see TypeError: Cannot read property 'call' of undefined, import rewiremock/webpack/interceptor in your scaffolding to ensure the interceptor is included in the bundle.
  10. Configure Hoisted Mocking via Babel

    master

    Hoisted mocking allows you to define mocks at the top level of a file, similar to Jest. This is achieved via a Babel plugin that moves mock definitions to the top of the transpiled output, ensuring they are executed before the modules they intend to mock are required.

    Limitations:

    • Other Babel plugins (like JSX) may not work inside __hoisted__ code.
    • Only functions are hoisted; other variables defined in the file are not visible to the hoisted code if they are not yet defined.

    Setup: Add rewiremock/babel to your .babelrc or babel.config.js plugins array.

    // .babelrc
    {
      "presets": [
        //.....
      ],
      "plugins": [
        "rewiremock/babel"
      ]
    }
  11. Configure rewiremock via __rewiremock.config.js__

    master

    Instead of configuring rewiremock in every test, you can create a global configuration file. Place a __rewiremock.config.js__ file in your project root (next to package.json). The file must export a default function that receives the rewiremock instance.

    // __rewiremock.config.js
    import wrongrewiremock, {plugins} from 'rewiremock';
    
    export default rewiremock => {
      // do everything with "right" rewiremock
      rewiremock.addPlugin(plugins.nodejs)
    }