Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / testing

promise-sync - Synchronous Promise for Making Testing Experience Much Easier

4.24/5 (5 votes)
16 Apr 2016CPOL2 min read 27K  
Synchronous promise for making testing experience much easier

Introduction

  • Did you ever need to use setTimeout just to make sure the async logic happened before you test the result?
  • Do your tests run slowly because of long waits for async results?
  • Have you ever tried to make a race condition test of 2 promises?
  • Do you want to control the exact moment the promise resolves or rejects?

Well, it all happened to me, so I searched for a library to make all of these work as I want. All the results had a few things missing, some were async, some didn't have the chaining, some threw errors if you didn't subscribe to them.

So I decided to write a new one.

Features

  • Support callback subscription: success(), catch(), then(), finally()
  • Chaining callback subscriptions
  • Support state checking: state, isPending(), isRejected(), isFulfilled()
  • Support resolving and rejecting: resolve(data?), reject(reason?)
  • Make it possible to ignore assertion errors inside the success/failure/finally callbacks
  • Create a resolved/rejected promise with one simple line
  • Wait for all promises to resolve using PromiseMock.all() method
  • Wait for one of the promises to resolve using PromiseMock.race() method
  • Written in Typescript so its type-safe
  • Resolving or rejecting not pending promise will throw error
  • Subscribing to resolved promise will raise proper callbacks
  • Subscribing to rejected promise will raise proper callbacks
  • Synchronous!

Using the Code

Installation

BAT
 npm install promise-sync --save-dev

Typescript

JavaScript
import { PromiseMock, PromiseState } from 'promise-sync';

var promiseMock = new PromiseMock<number>();

var onSuccessCallback = () => console.log('success');
var onFailureCallback = () => console.log('failure');
var finallyCallback = () => console.log('finally');

promiseMock.then(onSuccessCallback, onFailureCallback)
           .success(onSuccessCallback)
           .catch(onFailureCallback)
           .finally(finallyCallback);

var dataToResolve = 123;
promiseMock.resolve(dataToResolve);

var errorToReject = 'some error';
promiseMock.reject(errorToReject);

var isPending = promiseMock.isPending();
var isFulfilled = promiseMock.isFulfilled();
var isRejected = promiseMock.isRejected();

var state: PromiseState = promiseMock.state;

var rejectedPromise: PromiseMock<string> = PromiseMock.reject('some error');
var resolvedPromise: PromiseMock<string> = PromiseMock.resolve('some data');

var waitForAll: PromiseMock<any[]> = PromoseMock.all(
  [
    rejectedPromise,
    resolvedPromise,
    'random data that will be converted to resolved promise'
  ]);

var waitForFirst: PromiseMock<any> = PromoseMock.race(
  [
    rejectedPromise,
    resolvedPromise,
    'random data that will be converted to resolved promise'
  ]);

JavaScript

JavaScript
var promise_sync = require('promise-sync');
var PromiseMock = promise_sync.PromiseMock;
var PromiseState = promise_sync.PromiseState;

var promiseMock = new PromiseMock();

var onSuccessCallback = function() { console.log('success'); }
var onFailureCallback = function() { console.log('failure'); }
var finallyCallback = function() { console.log('finally'); }

promiseMock.then(onSuccessCallback, onFailureCallback)
           .success(onSuccessCallback)
           .catch(onFailureCallback)
           .finally(finallyCallback);

var dataToResolve = 123;
promiseMock.resolve(dataToResolve);

var errorToReject = 'some error';
promiseMock.reject(errorToReject);

var isPending = promiseMock.isPending();
var isFulfilled = promiseMock.isFulfilled();
var isRejected = promiseMock.isRejected();

var state = promiseMock.state;

var rejectedPromise = PromiseMock.reject('some error');
var resolvedPromise = PromiseMock.resolve('some data');

var waitForAll = PromoseMock.all(
  [
    rejectedPromise,
    resolvedPromise,
    'random data that will be converted to resolved promise'
  ]);

var waitForFirst = PromoseMock.race(
  [
    rejectedPromise,
    resolvedPromise,
    'random data that will be converted to resolved promise'
  ]);

Be Aware!

The methods: 'then/success/catch/finally' catch exceptions thrown in the callbacks. So if you want to do assertions inside of them, you need to tell the PromiseMock to ignore assertion error exceptions, otherwise the tests will pass even though the assertions are failing.

If you are using chai for example:

Typescript

JavaScript
import { AssertionError } from 'chai';
import { PromiseMock } from 'promise-sync';

PromiseMock.setAssertionExceptionTypes([AssertionError]);

Same Example using JavaScript

JavaScript
var chai = require('chai');
var promise_sync = require('promise-sync');
var PromiseMock = promise_sync.PromiseMock;

PromiseMock.setAssertionExceptionTypes([chai.AssertionError]);

Updates

17/02/2016 (version 0.1.7)

  • Updated the npm package to include only the essential files: *.js, *.d.ts files

05/03/2016 (version 0.1.91)

  • Added the PromiseMock.setAssertionExceptionTypes method to allow ignoring asserion errors inside the success/failure/finally callbacks.
  • Also fixed a bug when rejecting and then registering will not pass the rejected error

06/03/2016 (version 1.0.0)

  • Added support for static builder methods: PromiseMock.resolve('data'), PromiseMock.reject('error')
  • Added support to wait for multiple promises to resolve: PromiseMock.all(promises)
  • Added support to wait for first promise to resolve: PromiseMock.race(promises)

21/03/2016 (version 1.1.0)

  • Fixed a bug when returning a promise from success/failure callbacks, should propagate the value of the returned promise and not the value given as an argument to the callback (Issue #5)

11/04/2016 (version 1.1.1)

  • Fixed a bug when chaining then statements with real promises returned from the callbacks. (Issue #7)

14/04/2016 (version 1.1.3)

  • Remove the readonly from the state property to support older versions of typescript
  • Added public License file

16/04/2016 (version 1.1.4)

  • Fix a bug: rejectedPromose.success().catch() was not calling the failure callback in the catch method

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)