Sinon is a test library for any framework. Installation npm i mocha chai sinon-chai --save-dev Import libs const chai = require('chai') const assert = require('chai').assert const expect = require('chai').expect const sinon = require('sinon') chai.use(require('sinon-chai')) Assertions native Sinon assertions and their sisters for Sinon-Chai . sinon.assert. fail (message) sinon.assert. failException sinon.assert. pass (assertion) sinon.assert. notCalled (spy) sinon.assert. called (spy) sinon.assert. calledOnce (spy) sinon.assert. calledTwice (spy) sinon.assert. calledThrice (spy) sinon.assert. callCount (spy, num) sinon.assert. callOrder (spy1, spy2, ...) sinon.assert. calledOn (spyOrSpyCall, obj) sinon.assert. alwaysCalledOn (spy, obj) sinon.assert. alwaysCalledOn (spy, obj) sinon.assert. calledWith (spyOrSpyCall, arg1, arg2, ...) sinon.assert. alwaysCalledWith (spy, arg1, arg2, ...) sinon.assert. neverCalledWith (spy, arg1, arg2, ...) sinon.assert. calledWithExactly (spyOrSpyCall, arg1, arg2, ...) sinon.assert. calledOnceWithExactly (spyOrSpyCall, arg1, arg2, ...) sinon.assert. alwaysCalledWithExactly (spy, arg1, arg2, ...) sinon.assert. calledWithMatch (spyOrSpyCall, arg1, arg2, ...) sinon.assert. calledOnceWithMatch (spyOrSpyCall, arg1, arg2, ...) sinon.assert. alwaysCalledWithMatch (spy, arg1, arg2, ...) sinon.assert. calledWithNew (spyOrSpyCall) sinon.assert. neverCalledWithMatch (spy, arg1, arg2, ...) sinon.assert. threw (spyOrSpyCall, exception) sinon.assert. alwaysThrew (spy, exception) sinon.assert. match (actual, expectation) sinon.assert. expose (object, options) it('native sinon assertion vs chai', () => { const myStub = sinon.stub() const myStub2 = sinon.stub() myStub() myStub() myStub('a') myStub2('b') expect(myStub).called sinon.assert.called(myStub) expect(myStub).callCount(3) sinon.assert.callCount(myStub, 3) expect(myStub).calledThrice sinon.assert.calledThrice(myStub) expect(myStub).not.calledOnce expect(myStub).calledBefore(myStub2) expect(myStub2).calledAfter(myStub) expect(myStub2).calledWith('b') sinon.assert.calledWith(myStub2, 'b') sinon.assert.callOrder(myStub, myStub2) }) Matchers Used in assert function arguments. sinon.match(number) number sinon.match(string); string and have the expectation as a substring sinon.match(regexp); string and match the given regular expression sinon.match(object); not null or undefined and have at least the same properties as expectation sinon.match(function) custom matchers sinon.match.any matches anything sinon.match.defined defined sinon.match.truthy truthy sinon.match.falsy falsy sinon.match.bool a Boolean sinon.match.number a Number sinon.match.string a String sinon.match.object an Object sinon.match.func a Function sinon.match.array an Array sinon.match.array.deepEquals(arr) deep equal sinon.match.array.startsWith(arr) start with the same values sinon.match.array.endsWith(arr) end with the same values sinon.match.array.contains(arr) contain each one of the values the given array has sinon.match.map Map sinon.match.map.deepEquals(map) deep equal sinon.match.map.contains(map) contain each one of the items the given map has sinon.match.set be a Set sinon.match.set.deepEquals(set) be deep equal sinon.match.set.contains(set) contain each one of the items the given set has sinon.match.regexp regular expression sinon.match.date Date object sinon.match.symbol Symbol sinon.match.in(array) be in the array sinon.match.same(ref) strictly equal ref sinon.match.typeOf(type) be of the given type sinon.match.instanceOf(type) be an instance of the given type sinon.match.has(property[, expectation]) define the given property sinon.match.hasOwn(property[, expectation]) Same as sinon.match.has but the property must be defined by the value itself. Inherited properties are ignored sinon.match.hasNested(propertyPath[, expectation]) define the given propertyPath. Dot (prop.prop) and bracket (prop[0]) notations are supported as in Lodash.get it('matchers', () => { const book = { pages: 42, author: 'cjno' } const spy = sinon.spy() spy(book) sinon.assert.calledWith(spy, sinon.match({ author: 'cjno' })) sinon.assert.calledWith(spy, sinon.match.has('pages', 42)) }) spy When you spy on a function the function behavior does not change. Spy methods . it('should call the callback', () => { const callMyCallback = cb => cb() const cbSpy = sinon.spy() callMyCallback(cbSpy) expect(cbSpy).to.have.been.calledOnce }) spy on existing method it('spy on existing method', () => { const obj = { say: (str) => console.log(str) } const spyOnSay = sinon.spy(obj, 'say') obj.say('hi') expect(spyOnSay).to.have.been.calledOnce expect(spyOnSay).to.have.been.calledWith('hi') spyOnSay.restore() }) Stub Stub changes function behavior. For ex. return a value, throw an error, invoke a callback, do smth on 3rd call etc... Methods on stubbed functions const stub = sinon.stub(); stub.returns() makes the stub return the provided value. stub.withArgs(arg1[, arg2, ...]) stubs the method only for the provided arguments stub.onCall(n) defines the behavior of the stub on the nth call. stub.onFirstCall() , stub.onSecondCall() , stub.onThirdCall() stub.resetBehavior() , stub.resetHistory() , stub.reset() Resets both behaviour and history of the stub. stub.callsFake(fakeFunction) makes the stub call the provided fakeFunction when invoked. stub.resolves(value) Causes the stub to return a Promise which resolves to the provided value. stub.rejects() , stub.rejects("TypeError") , stub.rejects(value) stub.throws() , stub.throws("msg") , stub.throws(obj) Causes the stub to throw an exception stub.usingPromise(promiseLibrary) Causes the stub to return promises using a specific Promise library stub.callsArg(index) causes the stub to call the first argument as a callback stub.callsArgWith(index, arg1, arg2, ...) same, but with arguments to pass to the callback. stub.callArg(argNum) calls the argument of stub stub.callThrough() causes the original method to be called when none of the conditional stubs are matched. stub.yields([arg1, arg2, ...]) similar to callsArg . There are many other similar yeild methods. stub.callsArgAsync(index) Async version stub.yieldsAsync([arg1, arg2, ...]) As I have understood do not use yield , but use callsArg . it('anonymous stub', async () => { const myStub = sinon.stub() myStub .returns('hi') expect(myStub()).equal('hi') }) it('onCall', () => { const myStub = sinon.stub() myStub.onCall(0).returns(1) myStub.onCall(1).returns(2) myStub.returns(3) expect(myStub()).equal(1) expect(myStub()).equal(2) expect(myStub()).equal(3) }) Stub imported function const create = require('../create') const customer = require('../lib/customer') const dr = require('../lib/d-r') const postings = require('../lib/postings') const mapper = require('../lib/mapper') const { log } = require('lambda-sdk') describe('create', () => { const params = { pathParameters: { id: 'mock company id' } } const administrations = let enableAiPostingsStub, fetchAdministrationsStub, mapAdministrationsSpy, errorSpy beforeEach(() => { enableAiPostingsStub = sinon.stub(customer, 'enableAiPostings').resolves() fetchAdministrationsStub = sinon.stub(dr, 'fetchAdministrations').resolves([{ key: 'mock company' }]) mapAdministrationsSpy = sinon.spy(mapper, 'mapAdministrations') errorSpy = sinon.spy(log, 'error') }) afterEach(() => { sinon.restore() }) it('should enable ai postings with customer', async () => { await create(params) expect(enableAiPostingsStub).to.have.been.calledWith('mock company id') }) it('should fetch accounting company\'s administrations', async () => { await create(params) expect(fetchAdministrationsStub).to.have.been.calledWith('mock company id') }) it('should map all fetched administrations', async () => { await create(params) expect(mapAdministrationsSpy).to.have.callCount(3) }) it('should handle errors correctly', async () => { enableAiPostingsStub.rejects(new Error('mock error')) await expect(create(params)).to.have.been.rejected() expect(errorSpy).to.have.been.called() }) })