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

es2015-deferred

v4.0.2

Published

A tiny constructor for deferred objects. Useful for stubbing promises in tests.

Downloads

46

Readme

ES2015 Deferred

This library contains a small constructor which produces deferred objects. These are useful for testing purposes, and their use in production JS is discouraged (it's usually better to use the promise constructor directly).

This module has no production dependencies.

installation

npm i es2015-deferred

ES2015

ES2015 module loaders can directly consume index.js. If you're using rollup or another ES2015 compatible module loader configured to look for the module field and in a package.json file, then you can import with:

import Deferred from 'es2015-deferred';

The @rollup/plugin-node-resolve package may be useful to you.

If you want to try this module out directly without installation, it can be used via unpkg:

import Deferred from 'https://unpkg.com/es2015-deferred?module';

API

With Deferred in your environment you can create deferred objects.

var deferred = new Deferred();

// new is optional...

var deferred = Deferred();

A promise is managed by the deferred object.

var promise = deferred.promise;

Resolve deferred.promise with a given value.

deferred.resolve('a-resolution');

Reject deferred.promise with an error.

deferred.reject(new Error('Oh noes!'));

Resolve and reject return the promise for easy chaining, e.g.

deferred.resolve('a-resolution').then(/* ... */);

example

This module is intended for use with unit test runners like mocha. Let's say you want to test a module which makes a request using fetch and parses the response as JSON:

export default function fetchAndParse(url) {
  return self.fetch(url).then(response => {
    if (!response.ok) {
      throw new Error(`Unexpected response: ${response.status}`);
    }

    return response.json();
  });
}

Fetch uses promises, so testing it can be tricky! Here's a set of tests for this module written in mocha and sinon. What follows is bulky, but exhaustive. It can be surprising how much branching promises hide!

import assert from 'assert';
import sinon from 'sinon';
import fetchAndParse from './fetchAndParse';

// For failing tests on promises which should reject but do not.
function failResolve() {
  throw new Error('Promise should reject.');
}

describe('fetchAndParse', () => {
  const sandbox = sinon.sandbox.create();

  let fetchDeferred;
  let promise;

  beforeEach(() => {
    fetchDeferred = new Deferred();

    // Stub fetch with a function which returns a promise we control.
    sandbox.stub(self, 'fetch').returns(fetchDeferred.promise);

    // Using a deferred above means we can use this promise throughout
    // the tests, resolve or rejecting steps as we go along. A deferred
    // allows test cases to be built progressively as describe nest.
    promise = fetchAndParse('some-url');
  });

  afterEach(() => {
    sandbox.reset();
  });

  it('calls fetch with the given url', () => {
    assert.equal(self.fetch.callCount, 1);
    assert.ok(self.fetch.calledWithExactly('some-url'));
  });

  describe('when the call to fetch rejects', () => {
    let error;

    beforeEach(() => {
      error = new Error();

      // By rejecting here, the promise set up above gets is rejected.
      fetchDeferred.reject(error);
    });

    it('rejects the promise returned from fetchAndParse with the same error', () => {
      // Mocha treats a resolved promise as a success. This line
      // converts and checks rejected promises to resolved, and turns
      // resolve promises to rejections before returning for mocha.
      return promise.then(
        failResolve,
        err => assert.equal(err, error)
      );
    });
  });

  describe('when the call to fetch resolves with an unsuccessful status', () => {
    beforeEach(() => {
      // Fetch resolves to a response object. Instruct the deferred
      // object to follow that behaviour.
      fetchDeferred.resolve({
        ok: false,
        status: 404
      });
    });

    it('rejects with an unexpected response error', () => {
      return promise.then(failResolve, err => {
        assert.ok(err instanceof Error);
        assert.equal(err.message, 'Unexpected response: 404');
      });
    });
  });

  describe('when the call to fetch resolves with a successful status', () => {
    let jsonDeferred;
    let response;

    beforeEach(() => {
      // The json method of the response returns a promise. Use a deferred
      // object to manage that.
      jsonDeferred = new Deferred();

      response = {
        ok: true,
        json: sansbox.stub().returns(jsonDeferred.promise);
      };

      fetchDeferred.resolve(response);
    });

    it('calls the json method of the response object', () => {
      return fetchDeferred.promise.then(() => assert.equal(response.json.callCount, 1));
    });

    describe('when response.json rejects', () => {
      let error;

      beforeEach(() => {
        error = new Error();

        jsonDeferred.reject(error);
      });

      it('rejects the promise returned from fetchAndParse with the same error', () => {
        return promise.then(
          failResolve,
          err => assert.equal(err, error)
        );
      });
    });

    describe('when response.json resolves', () => {
      beforeEach(() => {
        jsonDeferred.resolve('parsed-response-body')
      });

      it('resolves the promise returned from fetchAndParse with the result', () => {
        return promise.then(result => assert.equal(result, 'parsed-response-body'));
      });
    });
  });
});