import-inject-loader

0.2.4 • Public • Published

Build Status

Overwrite your dependencies with mocks and custom implementations.

Description

import-inject-loader is a webpack loader which allows you to replace imported dependencies and global variables by custom implementations. At build time new exported functions are added to your module which makes it possible to change implementations at run time (e.g. within tests).

Usage

Imagine we have this module and want to mock fetch in our unit test:

export const getUsers = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  return response.json();
};

We can do it like this:

import expect from 'expect';
import {
  getUsers,
  ilOverwriteFetch,
  ilResetAll
} from 'import-inject-loader?fetch!../src/get-users';
 
define('Test getUsers()', () => {
  it('should return users', async () => {
    // mock `fetch`
    ilOverwriteFetch((url) => ({
      json: [
        { name: 'John Doe' }
      ]
    }));
 
    // test `getUsers`
    const users = await getUsers();
    expect(users).toEqual([
      { name: 'John Doe' }
    ]);
  });
 
  afterEach(ilResetAll);
});

Explanation

The getUsers function is hard to test, because it requires a network request. With import-inject-loader we can mock fetch to get rid of the network request.

To do so we simply import our module with the import-inject-loader and specify the names of imported or global variables we'd like to replace in a comma separated list:

import {
  getUsers,
  ilOverwriteFetch,
  ilResetAll
} from 'import-inject-loader?fetch!../src/get-users';

You can see that two new functions are exported from ../src/get-users: ilOverwriteFetch and ilResetAll.

ilOverwriteFetch is exported, because we passed ?fetch to the import-inject-loader. If we would pass ?fetch,Math,localStorage the function ilOverwriteFetch, ilOverwriteMath and ilOverwriteLocalStorage would be exported (assuming all three variables are actually used in the file). If you pass ?fatch - which is a typo - an error is thrown, because no fatch is used inside ../src/get-users. The ilOverwrite{Name} functions allow you to swap out imported or global variables with own implementations.

The ilResetAll is always exported. It is a handy way to reset your custom implementations with the original implementation after your test is done.

Note that you only change the implementation of fetch within this one module. Other modules aren't affect and the global fetch on window isn't changed.

The import-inject-loader basically rewrites your module to something like this (not exactly, but you get the point):

let fetch = window.fetch;
 
export const ilOverwriteFetch = (newFetch) => fetch = newFetch;
export const ilResetAll = () => fetch = window.fetch;
 
export const getUsers = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  return response.json();
};

As explained this functionallity is not limited to global variables. You can also mock imported variables. Say you have another module which uses our getUsers like this:

import { getUsers } from './get-users';
 
export countUsers = async () => {
  const users = await getUsers();
  return users.length;
};

We can test countUsers like this:

import {
  countUsers,
  ilOverwriteGetUsers,
  ilResetAll
} from 'import-inject-loader?getUsers!../src/count-users';
 
define('Test countUsers()', () => {
  it('should return users', async () => {
    // mock `getUsers`
    ilOverwriteGetUsers(() => [
      { name: 'John Doe' }
    ]);
 
    // test `countUsers`
    const count = await countUsers();
    expect(users).toBe(1);
  });
 
  afterEach(ilResetAll);
});

Examples

You can check out a standalone example with all source and test files in our examples/ directory.

Another example which uses React, TypeScript and JSX can be found here.

Package Sidebar

Install

npm i import-inject-loader

Weekly Downloads

14

Version

0.2.4

License

Apache-2.0

Last publish

Collaborators

  • donaldpipowitch
  • floric
  • mercateo