sinon-chai vs chai-as-promised
JavaScript Testing Libraries
sinon-chaichai-as-promisedSimilar Packages:

JavaScript Testing Libraries

Chai-as-promised and Sinon-Chai are both extensions of the Chai assertion library, each serving distinct purposes in the realm of JavaScript testing. Chai-as-promised is specifically designed to facilitate assertions on promises, allowing developers to write cleaner and more readable tests for asynchronous code. It enhances the expressiveness of tests by providing a fluent interface for handling promise resolutions and rejections. On the other hand, Sinon-Chai integrates Sinon.js with Chai, providing a set of assertions that work seamlessly with Sinon’s spies, mocks, and stubs. This combination allows developers to easily verify that functions were called as expected, enhancing the testing of side effects in code. Together, these libraries enrich the testing experience by offering specialized tools for different aspects of testing, particularly in asynchronous and behavior-driven development.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
sinon-chai1,231,1221,08915.2 kB19a year ago(BSD-2-Clause OR WTFPL)
chai-as-promised01,41927.9 kB35a year agoMIT

Feature Comparison: sinon-chai vs chai-as-promised

Promise Assertions

  • sinon-chai:

    Sinon-Chai does not provide promise-specific assertions but can be used in conjunction with other libraries to verify that promise-returning functions are called correctly. It focuses more on the behavior of functions rather than their promise states.

  • chai-as-promised:

    Chai-as-promised provides a rich set of assertions specifically tailored for promises, allowing developers to assert on the eventual value or error of a promise. This includes methods like 'eventually' and 'finally', which enable chaining assertions that can handle both resolved and rejected states of promises in a clean and readable manner.

Integration with Sinon.js

  • sinon-chai:

    Sinon-Chai is designed to work seamlessly with Sinon.js, providing assertions that enhance the capabilities of Sinon. This includes assertions like 'to.have.been.called' or 'to.have.been.calledWith', which allow developers to easily verify that mocked functions were called with the expected arguments.

  • chai-as-promised:

    Chai-as-promised does not integrate directly with Sinon.js, but it can be used alongside it for testing asynchronous code that involves spies or mocks. However, it does not provide specific assertions for Sinon’s features.

Readability and Expressiveness

  • sinon-chai:

    Sinon-Chai also promotes readability by allowing developers to write assertions that clearly express the expected behavior of functions. Its integration with Sinon.js means that tests can be more descriptive about how and when functions are called.

  • chai-as-promised:

    Chai-as-promised enhances the readability of tests involving promises by allowing developers to write assertions in a fluent, natural language style. This can make tests easier to understand and maintain, especially for those new to asynchronous programming.

Error Handling

  • sinon-chai:

    Sinon-Chai does not focus on error handling related to promises, as its primary purpose is to verify function calls and interactions. It is more suited for testing synchronous behavior and side effects.

  • chai-as-promised:

    Chai-as-promised provides built-in support for asserting that promises reject with specific errors, making it easier to test error handling in asynchronous code. This is crucial for ensuring that applications behave correctly under failure conditions.

Community and Ecosystem

  • sinon-chai:

    Sinon-Chai benefits from the strong community around Sinon.js, which is a well-established library for creating spies, mocks, and stubs. This integration allows developers to leverage a robust ecosystem for testing JavaScript applications.

  • chai-as-promised:

    Chai-as-promised is widely used within the JavaScript community, especially in projects that utilize Chai for assertions. Its popularity ensures good documentation and community support, making it easier to find resources and examples.

How to Choose: sinon-chai vs chai-as-promised

  • sinon-chai:

    Choose sinon-chai if you are utilizing Sinon.js for mocking and spying in your tests. It is ideal for projects that require detailed verification of function calls and interactions, allowing you to write more expressive assertions that complement Sinon’s capabilities.

  • chai-as-promised:

    Choose chai-as-promised if your project heavily relies on promises and you need a straightforward way to assert their outcomes in your tests. It is particularly useful for asynchronous testing scenarios where you want to ensure that promises resolve or reject as expected.

README for sinon-chai

Sinon.JS Assertions for Chai

Sinon–Chai provides a set of custom assertions for using the Sinon.JS spy, stub, and mocking framework with the Chai assertion library. You get all the benefits of Chai with all the powerful tools of Sinon.JS.

Instead of using Sinon.JS's assertions:

sinon.assert.calledWith(mySpy, "foo");

or awkwardly trying to use Chai's should or expect interfaces on spy properties:

mySpy.calledWith("foo").should.be.ok;
expect(mySpy.calledWith("foo")).to.be.ok;

you can say

mySpy.should.have.been.calledWith("foo");
expect(mySpy).to.have.been.calledWith("foo");

Assertions

All of your favorite Sinon.JS assertions made their way into Sinon–Chai. We show the should syntax here; the expect equivalent is also available.

Sinon.JS property/methodSinon–Chai assertion
calledspy.should.have.been.called
callCountspy.should.have.callCount(n)
calledOncespy.should.have.been.calledOnce
calledTwicespy.should.have.been.calledTwice
calledThricespy.should.have.been.calledThrice
calledBeforespy1.should.have.been.calledBefore(spy2)
calledAfterspy1.should.have.been.calledAfter(spy2)
calledImmediatelyBeforespy.should.have.been.calledImmediatelyBefore(spy2)
calledImmediatelyAfterspy.should.have.been.calledImmediatelyAfter(spy2)
calledWithNewspy.should.have.been.calledWithNew
alwaysCalledWithNewspy.should.always.have.been.calledWithNew
calledOnspy.should.have.been.calledOn(context)
alwaysCalledOnspy.should.always.have.been.calledOn(context)
calledWithspy.should.have.been.calledWith(...args)
alwaysCalledWithspy.should.always.have.been.calledWith(...args)
calledOnceWithspy.should.always.have.been.calledOnceWith(...args)
calledWithExactlyspy.should.have.been.calledWithExactly(...args)
alwaysCalledWithExactlyspy.should.always.have.been.calledWithExactly(...args)
calledOnceWithExactlyspy.should.always.have.been.calledOnceWithExactly(...args)
calledWithMatchspy.should.have.been.calledWithMatch(...args)
alwaysCalledWithMatchspy.should.always.have.been.calledWithMatch(...args)
returnedspy.should.have.returned(returnVal)
alwaysReturnedspy.should.have.always.returned(returnVal)
threwspy.should.have.thrown(errorObjOrErrorTypeStringOrNothing)
alwaysThrewspy.should.have.always.thrown(errorObjOrErrorTypeStringOrNothing)

For more information on the behavior of each assertion, see the documentation for the corresponding spy methods. These of course work on not only spies, but individual spy calls, stubs, and mocks as well.

Note that you can negate any assertion with Chai's .not. E. g. for notCalled use spy.should.have.not.been.called. Similarly, note that the always methods are accessed with Chai's .always prefix; should.have.been.alwaysCalledWith will not work - instead, use should.always.have.been.calledWith.

For simplicity, this library intentionally only implements Sinon's spy methods, and does not add an interface for Sinon.assert.match. Sinon's matchers are implemented by the samsam library, so if you want a should/expect interface to assert.match you may be interested in chai-samsam, which adds a .deep.match verb that will work with Sinon matchers.

For assert interface there is no need for sinon-chai or chai-samsam. You can install Sinon.JS assertions right into Chai's assert object with expose:

import * as chai from "chai";
import sinon from "sinon";

sinon.assert.expose(chai.assert, { prefix: "" });

Examples

Using Chai's should:

"use strict";
import * as chai from "chai";
import sinon from "sinon";
import sinonChai from "sinon-chai";
chai.should();
chai.use(sinonChai);

function hello(name, cb) {
    cb("hello " + name);
}

describe("hello", function () {
    it("should call callback with correct greeting", function () {
        var cb = sinon.spy();

        hello("foo", cb);

        cb.should.have.been.calledWith("hello foo");
    });
});

Using Chai's expect:

"use strict";
import * as chai from "chai";
import sinon from "sinon";
import sinonChai from "sinon-chai";
const expect = chai.expect;
chai.use(sinonChai);

function hello(name, cb) {
    cb("hello " + name);
}

describe("hello", function () {
    it("should call callback with correct greeting", function () {
        var cb = sinon.spy();

        hello("foo", cb);

        expect(cb).to.have.been.calledWith("hello foo");
    });
});

Installation and Usage

Node

Do an npm install --save-dev sinon-chai to get up and running. Then:

import * as chai from "chai";
import sinonChai from "sinon-chai";

chai.use(sinonChai);

You can of course put this code in a common test fixture file; for an example using Mocha, see the Sinon–Chai tests themselves.

Ruby on Rails

Thanks to Cymen Vig, there's now a Ruby gem of Sinon–Chai that integrates it with the Rails asset pipeline!