dce-stub

1.0.9 • Public • Published

dce-stub

A simple way to stub default-only dependencies. This project currently only works for stubbing the default export of a module.

We utilize dependency injection, so stubbed modules cannot be used until time of test (not at import time). For more info, see step 4 in the instructions below.

Usage

1. Import dce-stub

import runStubbed from 'dce-stub';

2. Import the dependencies you wish to stub using * syntax

In your spec:

import * as myDependency from '...';
...

In the module you are testing:

import * as myDependency from '...';
 
...
 
// When using the dependency, use the .default property:
myDependency.default...
...

3. Run your tests within the runStubbed function

Call runStubbed with two arguments:

  • replacements object|object[] – either one or many stub replacements, each of the form { dep, stub } where dep is the dependency and stub is the stubbed version of the dependency
  • test function – tests to run while the dependency is stubbed (dependencies are restored once the function finishes). Function may be asynchronous or synchronous
describe('My Feature', () => {
    it('Does Something', async () => {
        ...
 
        // Define stub replacement
        const replacement = {
            dep: myDependency,
            stub: <stub of myDependency>,
        };
 
        // Run the
        await runStubbed(replacement, async () => {
            ...
        });
    });
});

If you have more than one dependency to stub, just use a list:

...
// Define stub replacements
const replacements = [
    {
        dep: myDependency,
        stub: <stub of myDependency>,
    },
    {
        dep: secondDepencency,
        stub: <stub of secondDependency>,
    },
    ...
];
 
// Run the
await runStubbed(replacements, async () => {
    ...
});

4. Configure/use dependencies at time of use

We use dependency injection, which means that the stubbed version of the dependency is not injected at import time. Instead, it is injected when the test runs.

Don't configure/initialize/use stubbed libraries until time of test:

Example: we are using a library lms that must be initialized before being used.

Wrong way:

import * as lms from 'my-lms';
 
const api = lms.default.getAPI();
 
class Course {
  constructor(id) {
    this.id = id;
  }
 
  listStudents() {
    return api.course.listStudents(this,id);
  }
  
  ...
}

Right way:

import * as lms from 'my-lms';
 
class Course {
  constructor(id) {
    this.id = id;
 
    this.api = lms.getAPI();
  }
 
  listStudents() {
    return this.api.course.listStudents(this,id);
  }
  
  ...
}

Another right way:
(if there is no cost to re-initializing over and over)

import * as lms from 'my-lms';
 
class Course {
  constructor(id) {
    this.id = id;
  }
 
  listStudents() {
    const api = lms.getAPI();
    return this.api.course.listStudents(this,id);
  }
  
  ...
}

Note: One concrete example of such a library that can be re-initialized with no cost, is caccl/client/cached

Example

We have two helpers:

  • getNameFromServer – pulls the current user's first name from the server
  • genIntro – a script that calls getNameFromServer and generates a welcome message

Our goal is to write a unit test for genIntro, isolating it from getNameFromServer. Thus, we want to import genIntro while replacing getNameFromServer with a fake stubbed version of that module.

getNameFromServer.js

export default async () => {
    return sendRequest({
        method: 'GET',
        url: 'https://host.com/user/profile/name',
    });
};

genIntro.js

import getNameFromServer from './getNameFromServer';
 
export default async () => {
    // Get the current user's name
    const name = await getNameFromServer();
 
    // Create the message
    return `Hi ${name}! It is a pleasure to meet you.`;
};

genIntro.spec.js

import runStubbed from 'dce-stub';
 
// Import module to test
import genIntro from './genIntro';
 
// Import dependencies we want to stub
import * as getNameFromServer from './getNameFromServer';
 
// Create the getNameFromServer stub
const getNameFromServerStub = () => {
    return 'Divardo';
};
 
// Tests
describe('genIntro', () => {
    it('Generates a valid introduction', async () => {
        // Create stub replacements
        const replacement = {
            dep: getNameFromServer,
            stub: getNameFromServerStub,
        };
 
        // Run tests with stub replacements
        await runStubbed(replacement, async () => {
            // Generate an intro message
            const intro = await genIntro();
 
            // Test the intro
            assert.equal(
                intro,
                'Hi Divardo! It is a pleasure to meet you.',
                'Invalid intro produced'
            );
        });
    });
});

Package Sidebar

Install

npm i dce-stub

Weekly Downloads

0

Version

1.0.9

License

MIT

Unpacked Size

8.97 kB

Total Files

5

Last publish

Collaborators

  • gabeabrams