@bupkis/sinon
v0.2.0
Published
Sinon spy/stub/mock assertions for Bupkis
Maintainers
Readme
@bupkis/sinon
Sinon spy/stub/mock assertions for Bupkis.
Installation
npm install @bupkis/sinon bupkis sinonUsage
import { use } from 'bupkis';
import sinonAssertions from '@bupkis/sinon';
import sinon from 'sinon';
const { expect } = use(sinonAssertions);
// Basic spy assertions
const spy = sinon.spy();
spy(42);
expect(spy, 'was called');
expect(spy, 'was called once');
expect(spy, 'was called with', [42]);
// Call count
spy();
spy();
expect(spy, 'was called times', 3);
// Stub return values
const stub = sinon.stub().returns(100);
stub();
expect(stub.firstCall, 'to have returned', 100);
// Call order
const first = sinon.spy();
const second = sinon.spy();
first();
second();
expect(first, 'was called before', second);
expect([first, second], 'given call order');
// Complex call specifications
const logger = sinon.spy();
logger('info', 'started');
logger('debug', 'processing');
logger('info', 'done');
expect(logger, 'to have calls satisfying', [
['info', 'started'],
['debug', 'processing'],
['info', 'done'],
]);Assertions
{Spy} was called
✏️ Aliases:
{Spy} was called {Spy} to have been called
Asserts that a spy was called at least once.
Success:
const spy = sinon.spy();
spy();
expect(spy, 'was called');
expect(spy, 'to have been called');Failure:
const spy = sinon.spy();
expect(spy, 'was called');
// AssertionError: Expected spy to have been called, but it was never calledNegation:
const spy = sinon.spy();
expect(spy, 'not to have been called');{Spy} was not called
✏️ Aliases:
{Spy} was not called {Spy} to not have been called
Asserts that a spy was never called.
Success:
const spy = sinon.spy();
expect(spy, 'was not called');
expect(spy, 'to not have been called');Failure:
const spy = sinon.spy();
spy();
expect(spy, 'was not called');
// AssertionError: Expected spy to not have been called, but it was called 1 time(s)Negation:
const spy = sinon.spy();
spy();
expect(spy, 'not was not called'); // awkward but valid{Spy} was called once
✏️ Aliases:
{Spy} was called once {Spy} to have been called once
Asserts that a spy was called exactly once.
Success:
const spy = sinon.spy();
spy();
expect(spy, 'was called once');
expect(spy, 'to have been called once');Failure:
const spy = sinon.spy();
spy();
spy();
expect(spy, 'was called once');
// AssertionError: Expected spy to have been called exactly onceNegation:
const spy = sinon.spy();
expect(spy, 'not to have been called once');{Spy} was called twice
Asserts that a spy was called exactly twice.
Success:
const spy = sinon.spy();
spy();
spy();
expect(spy, 'was called twice');Failure:
const spy = sinon.spy();
spy();
expect(spy, 'was called twice');
// AssertionError: Expected spy to have been called exactly twiceNegation:
const spy = sinon.spy();
expect(spy, 'not was called twice');{Spy} was called thrice
Asserts that a spy was called exactly three times.
Success:
const spy = sinon.spy();
spy();
spy();
spy();
expect(spy, 'was called thrice');Failure:
const spy = sinon.spy();
spy();
spy();
expect(spy, 'was called thrice');
// AssertionError: Expected spy to have been called exactly three timesNegation:
const spy = sinon.spy();
expect(spy, 'not was called thrice');{Spy} was called times {number}
Asserts that a spy was called exactly the specified number of times.
Success:
const spy = sinon.spy();
spy();
spy();
spy();
spy();
spy();
expect(spy, 'was called times', 5);Failure:
const spy = sinon.spy();
spy();
spy();
expect(spy, 'was called times', 5);
// AssertionError: Expected spy to have been called 5 time(s)Negation:
const spy = sinon.spy();
spy();
expect(spy, 'not was called times', 5);{Spy} to have returned
✏️ Aliases:
{Spy} to have returned {Spy} returned
Asserts that a spy returned successfully (without throwing) at least once.
Success:
const spy = sinon.spy(() => 42);
spy();
expect(spy, 'to have returned');
expect(spy, 'returned');Failure:
const spy = sinon.spy(() => {
throw new Error('boom');
});
try {
spy();
} catch {}
expect(spy, 'to have returned');
// AssertionError: Expected spy to have returned at least onceNegation:
const spy = sinon.spy(() => {
throw new Error('boom');
});
try {
spy();
} catch {}
expect(spy, 'not to have returned');{Spy} to have returned times {number}
Asserts that a spy returned successfully exactly the specified number of times.
Success:
const spy = sinon.spy(() => 42);
spy();
spy();
spy();
expect(spy, 'to have returned times', 3);Failure:
const spy = sinon.spy(() => 42);
spy();
spy();
expect(spy, 'to have returned times', 3);
// AssertionError: Expected spy to have returned 3 time(s), but it returned 2 time(s)Negation:
const spy = sinon.spy(() => 42);
spy();
expect(spy, 'not to have returned times', 3);{Spy} to have returned with {unknown}
Asserts that a spy returned the specified value on at least one call. Uses Sinon's spy.returned() method for comparison (deep equality via samsam).
Success:
const spy = sinon.spy((x) => x * 2);
spy(5);
spy(10);
expect(spy, 'to have returned with', 10);
expect(spy, 'to have returned with', 20);Failure:
const spy = sinon.spy((x) => x * 2);
spy(5);
expect(spy, 'to have returned with', 100);
// AssertionError: Expected spy to have returned specified valueNegation:
const spy = sinon.spy((x) => x * 2);
spy(5);
expect(spy, 'not to have returned with', 100);{Spy} was called with {array}
✏️ Aliases:
{Spy} was called with {array} {Spy} to have been called with {array}
Asserts that at least one call to the spy included the specified arguments. Uses prefix matching: the spy may have been called with additional arguments beyond those specified.
Success:
const spy = sinon.spy();
spy('foo', 42, 'extra');
expect(spy, 'was called with', ['foo', 42]); // prefix match - 'extra' ignored
expect(spy, 'to have been called with', ['foo', 42, 'extra']); // exact matchFailure:
const spy = sinon.spy();
spy('bar');
expect(spy, 'was called with', ['foo']);
// AssertionError: Expected spy to have been called with specified argumentsNegation:
const spy = sinon.spy();
spy('bar');
expect(spy, 'not to have been called with', ['foo']);{Spy} was always called with {array}
Asserts that all calls to the spy included the specified arguments (prefix match).
Success:
const spy = sinon.spy();
spy('foo', 1);
spy('foo', 2);
spy('foo', 3);
expect(spy, 'was always called with', ['foo']);Failure:
const spy = sinon.spy();
spy('foo');
spy('bar');
expect(spy, 'was always called with', ['foo']);
// AssertionError: Expected spy to always have been called with specified argumentsNegation:
const spy = sinon.spy();
spy('foo');
spy('bar');
expect(spy, 'not was always called with', ['foo']);{Spy} was called with exactly {array}
Asserts that at least one call to the spy had exactly the specified arguments (no additional arguments).
Success:
const spy = sinon.spy();
spy('foo', 42);
expect(spy, 'was called with exactly', ['foo', 42]);Failure:
const spy = sinon.spy();
spy('foo', 42, 'extra');
expect(spy, 'was called with exactly', ['foo', 42]);
// AssertionError: Expected spy to have been called with exactly the specified argumentsNegation:
const spy = sinon.spy();
spy('foo', 42, 'extra');
expect(spy, 'not was called with exactly', ['foo', 42]);{Spy} was never called with {array}
Asserts that the spy was never called with the specified arguments.
Success:
const spy = sinon.spy();
spy('foo');
spy('bar');
expect(spy, 'was never called with', ['baz']);Failure:
const spy = sinon.spy();
spy('foo');
expect(spy, 'was never called with', ['foo']);
// AssertionError: Expected spy to never have been called with specified argumentsNegation:
const spy = sinon.spy();
spy('foo');
expect(spy, 'not was never called with', ['foo']);{Spy} was called on {unknown}
✏️ Aliases:
{Spy} was called on {unknown} {Spy} to have been called on {unknown}
Asserts that at least one call to the spy used the specified this context.
Success:
const obj = { name: 'test' };
const spy = sinon.spy();
spy.call(obj);
expect(spy, 'was called on', obj);
expect(spy, 'to have been called on', obj);Failure:
const obj1 = { name: 'one' };
const obj2 = { name: 'two' };
const spy = sinon.spy();
spy.call(obj1);
expect(spy, 'was called on', obj2);
// AssertionError: Expected spy to have been called with specified this contextNegation:
const obj1 = { name: 'one' };
const obj2 = { name: 'two' };
const spy = sinon.spy();
spy.call(obj1);
expect(spy, 'not to have been called on', obj2);{Spy} was always called on {unknown}
Asserts that all calls to the spy used the specified this context.
Success:
const obj = { name: 'test' };
const spy = sinon.spy();
spy.call(obj);
spy.call(obj);
expect(spy, 'was always called on', obj);Failure:
const obj1 = { name: 'one' };
const obj2 = { name: 'two' };
const spy = sinon.spy();
spy.call(obj1);
spy.call(obj2);
expect(spy, 'was always called on', obj1);
// AssertionError: Expected spy to always have been called with specified this contextNegation:
const obj1 = { name: 'one' };
const obj2 = { name: 'two' };
const spy = sinon.spy();
spy.call(obj1);
spy.call(obj2);
expect(spy, 'not was always called on', obj1);{Spy} threw
✏️ Aliases:
{Spy} threw {Spy} to have thrown
Asserts that the spy threw an exception on at least one call.
Success:
const spy = sinon.spy(() => {
throw new Error('boom');
});
try {
spy();
} catch {}
expect(spy, 'threw');
expect(spy, 'to have thrown');Failure:
const spy = sinon.spy();
spy();
expect(spy, 'threw');
// AssertionError: Expected spy to have thrown an exceptionNegation:
const spy = sinon.spy();
spy();
expect(spy, 'not to have thrown');{Spy} threw {Error | string}
Asserts that the spy threw a specific error. The parameter can be an Error instance or a string representing the error type name.
Success:
const spy = sinon.spy(() => {
throw new TypeError('bad type');
});
try {
spy();
} catch {}
expect(spy, 'threw', 'TypeError'); // match by type name
expect(spy, 'threw', new TypeError('bad type')); // match by instanceFailure:
const spy = sinon.spy(() => {
throw new Error('boom');
});
try {
spy();
} catch {}
expect(spy, 'threw', 'TypeError');
// AssertionError: Expected spy to have thrown specified exceptionNegation:
const spy = sinon.spy(() => {
throw new Error('boom');
});
try {
spy();
} catch {}
expect(spy, 'not threw', 'TypeError');{Spy} always threw
Asserts that the spy threw an exception on every call.
Success:
const spy = sinon.spy(() => {
throw new Error('boom');
});
try {
spy();
} catch {}
try {
spy();
} catch {}
expect(spy, 'always threw');Failure:
let shouldThrow = true;
const spy = sinon.spy(() => {
if (shouldThrow) {
shouldThrow = false;
throw new Error('boom');
}
});
try {
spy();
} catch {}
spy();
expect(spy, 'always threw');
// AssertionError: Expected spy to always have thrown an exceptionNegation:
const spy = sinon.spy();
spy();
expect(spy, 'not always threw');{Spy} was called before {Spy}
Asserts that the first spy was called before the second spy.
Success:
const first = sinon.spy();
const second = sinon.spy();
first();
second();
expect(first, 'was called before', second);Failure:
const first = sinon.spy();
const second = sinon.spy();
second();
first();
expect(first, 'was called before', second);
// AssertionError: Expected first spy to have been called before second spyNegation:
const first = sinon.spy();
const second = sinon.spy();
second();
first();
expect(first, 'not was called before', second);{Spy} was called after {Spy}
Asserts that the first spy was called after the second spy.
Success:
const first = sinon.spy();
const second = sinon.spy();
second();
first();
expect(first, 'was called after', second);Failure:
const first = sinon.spy();
const second = sinon.spy();
first();
second();
expect(first, 'was called after', second);
// AssertionError: Expected first spy to have been called after second spyNegation:
const first = sinon.spy();
const second = sinon.spy();
first();
second();
expect(first, 'not was called after', second);{SpyCall} to have args {array}
Asserts that a specific spy call had exactly the specified arguments.
Access individual calls via spy.firstCall, spy.secondCall, spy.thirdCall, spy.lastCall, or spy.getCall(n).
Success:
const spy = sinon.spy();
spy('foo', 42);
expect(spy.firstCall, 'to have args', ['foo', 42]);Failure:
const spy = sinon.spy();
spy('foo', 42);
expect(spy.firstCall, 'to have args', ['bar', 42]);
// AssertionError: Expected spy call to have specified argumentsNegation:
const spy = sinon.spy();
spy('foo', 42);
expect(spy.firstCall, 'not to have args', ['bar', 42]);{SpyCall} to have returned {unknown}
Asserts that a specific spy call returned the specified value.
Success:
const stub = sinon.stub().returns(100);
stub();
expect(stub.firstCall, 'to have returned', 100);Failure:
const stub = sinon.stub().returns(100);
stub();
expect(stub.firstCall, 'to have returned', 200);
// AssertionError: Expected spy call to have returned specified valueNegation:
const stub = sinon.stub().returns(100);
stub();
expect(stub.firstCall, 'not to have returned', 200);{SpyCall} to have thrown
Asserts that a specific spy call threw an exception.
Success:
const spy = sinon.spy(() => {
throw new Error('boom');
});
try {
spy();
} catch {}
expect(spy.firstCall, 'to have thrown');Failure:
const spy = sinon.spy();
spy();
expect(spy.firstCall, 'to have thrown');
// AssertionError: Expected spy call to have thrown an exceptionNegation:
const spy = sinon.spy();
spy();
expect(spy.firstCall, 'not to have thrown');{SpyCall} to have this {unknown}
Asserts that a specific spy call used the specified this context.
Success:
const obj = { name: 'test' };
const spy = sinon.spy();
spy.call(obj);
expect(spy.firstCall, 'to have this', obj);Failure:
const obj1 = { name: 'one' };
const obj2 = { name: 'two' };
const spy = sinon.spy();
spy.call(obj1);
expect(spy.firstCall, 'to have this', obj2);
// AssertionError: Expected spy call to have specified this contextNegation:
const obj1 = { name: 'one' };
const obj2 = { name: 'two' };
const spy = sinon.spy();
spy.call(obj1);
expect(spy.firstCall, 'not to have this', obj2);{Spy[]} given call order
Asserts that an array of spies were called in the specified order.
Success:
const first = sinon.spy();
const second = sinon.spy();
const third = sinon.spy();
first();
second();
third();
expect([first, second, third], 'given call order');Failure:
const first = sinon.spy();
const second = sinon.spy();
const third = sinon.spy();
third();
first();
second();
expect([first, second, third], 'given call order');
// AssertionError: Expected spies to have been called in order, but spy 0 was not called before spy 1Negation:
const first = sinon.spy();
const second = sinon.spy();
const third = sinon.spy();
third();
first();
second();
expect([first, second, third], 'not given call order');{Spy} to have calls satisfying {array}
Asserts that all calls to a spy match a specification array. Each element in the array corresponds to one call and can be either:
- An object with optional
args,returned,threw,thisValueproperties - An array (shorthand for
{ args: [...] })
The number of specifications must match the number of calls exactly.
Success:
const spy = sinon.spy();
spy('a', 1);
spy('b', 2);
spy('c', 3);
// Using object specifications
expect(spy, 'to have calls satisfying', [
{ args: ['a', 1] },
{ args: ['b', 2] },
{ args: ['c', 3] },
]);
// Using array shorthand
expect(spy, 'to have calls satisfying', [
['a', 1],
['b', 2],
['c', 3],
]);With return values and this context:
const obj = { multiplier: 2 };
const stub = sinon.stub().callsFake(function (x) {
return x * this.multiplier;
});
stub.call(obj, 5);
stub.call(obj, 10);
expect(stub, 'to have calls satisfying', [
{ args: [5], returned: 10, thisValue: obj },
{ args: [10], returned: 20, thisValue: obj },
]);Failure:
const spy = sinon.spy();
spy('a');
spy('b');
expect(spy, 'to have calls satisfying', [['a'], ['c']]);
// AssertionError: Call 1: argument 0 did not match
const spy2 = sinon.spy();
spy2('a');
expect(spy2, 'to have calls satisfying', [['a'], ['b']]);
// AssertionError: Expected spy to have 2 call(s), but it had 1Negation:
const spy = sinon.spy();
spy('a');
spy('b');
expect(spy, 'not to have calls satisfying', [['x'], ['y']]);License
Copyright © 2026 Christopher "boneskull" Hiller. Licensed under BlueOak-1.0.0.
