npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

dce-stub

v1.0.9

Published

A simple way to stub default-only dependencies.

Downloads

24

Readme

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'
            );
        });
    });
});