JavaScript test spies, stubs and mocks for framework-agnostic unit testing.
—
Sinon's assertion methods provide a comprehensive way to test spy, stub, and mock behavior with clear, descriptive error messages. They integrate well with any testing framework and offer more readable alternatives to manual spy property checking.
Assert whether spies/stubs were called and how many times.
declare namespace assert {
/**
* Assert that spy was called at least once
* @param spy - Spy to check
* @throws AssertionError if spy was never called
*/
function called(spy: SinonSpy): void;
/**
* Assert that spy was never called
* @param spy - Spy to check
* @throws AssertionError if spy was called
*/
function notCalled(spy: SinonSpy): void;
/**
* Assert that spy was called exactly once
* @param spy - Spy to check
* @throws AssertionError if spy was not called exactly once
*/
function calledOnce(spy: SinonSpy): void;
/**
* Assert that spy was called exactly twice
* @param spy - Spy to check
* @throws AssertionError if spy was not called exactly twice
*/
function calledTwice(spy: SinonSpy): void;
/**
* Assert that spy was called exactly three times
* @param spy - Spy to check
* @throws AssertionError if spy was not called exactly three times
*/
function calledThrice(spy: SinonSpy): void;
/**
* Assert that spy was called a specific number of times
* @param spy - Spy to check
* @param count - Expected call count
* @throws AssertionError if call count doesn't match
*/
function callCount(spy: SinonSpy, count: number): void;
}Usage Examples:
import { assert } from "sinon";
const spy = sinon.spy();
// Test that function wasn't called initially
assert.notCalled(spy);
// Call the spy
spy();
// Test that it was called
assert.called(spy);
assert.calledOnce(spy);
// Call again
spy();
// Test specific count
assert.calledTwice(spy);
assert.callCount(spy, 2);Assert that spies/stubs were called with specific arguments.
declare namespace assert {
/**
* Assert that spy was called with specific arguments (partial match)
* @param spy - Spy to check
* @param args - Arguments that should be present
* @throws AssertionError if spy was never called with these arguments
*/
function calledWith(spy: SinonSpy, ...args: any[]): void;
/**
* Assert that spy was called with exact arguments (exact match)
* @param spy - Spy to check
* @param args - Exact arguments expected
* @throws AssertionError if spy was never called with exactly these arguments
*/
function calledWithExactly(spy: SinonSpy, ...args: any[]): void;
/**
* Assert that spy was called with arguments matching patterns
* @param spy - Spy to check
* @param matchers - Matcher patterns for arguments
* @throws AssertionError if spy was never called with matching arguments
*/
function calledWithMatch(spy: SinonSpy, ...matchers: any[]): void;
/**
* Assert that spy was always called with specific arguments
* @param spy - Spy to check
* @param args - Arguments that should be in every call
* @throws AssertionError if any call didn't include these arguments
*/
function alwaysCalledWith(spy: SinonSpy, ...args: any[]): void;
/**
* Assert that spy was always called with exact arguments
* @param spy - Spy to check
* @param args - Exact arguments expected in every call
* @throws AssertionError if any call didn't have exactly these arguments
*/
function alwaysCalledWithExactly(spy: SinonSpy, ...args: any[]): void;
/**
* Assert that spy was always called with matching arguments
* @param spy - Spy to check
* @param matchers - Matcher patterns for every call
* @throws AssertionError if any call didn't match patterns
*/
function alwaysCalledWithMatch(spy: SinonSpy, ...matchers: any[]): void;
/**
* Assert that spy was never called with specific arguments
* @param spy - Spy to check
* @param args - Arguments that should never be present
* @throws AssertionError if spy was ever called with these arguments
*/
function neverCalledWith(spy: SinonSpy, ...args: any[]): void;
/**
* Assert that spy was never called with matching arguments
* @param spy - Spy to check
* @param matchers - Matcher patterns that should never match
* @throws AssertionError if spy was ever called with matching arguments
*/
function neverCalledWithMatch(spy: SinonSpy, ...matchers: any[]): void;
}Usage Examples:
const spy = sinon.spy();
spy("hello", "world");
spy("foo", { bar: "baz" });
// Test specific arguments
assert.calledWith(spy, "hello");
assert.calledWith(spy, "hello", "world");
assert.calledWithExactly(spy, "hello", "world");
// Test with matchers
import { match } from "sinon";
assert.calledWithMatch(spy, "foo", match.object);
assert.calledWithMatch(spy, match.string, { bar: "baz" });
// Test that certain arguments were never used
assert.neverCalledWith(spy, "invalid");Assert the this context and constructor usage of spy calls.
declare namespace assert {
/**
* Assert that spy was called with specific `this` context
* @param spy - Spy to check
* @param thisValue - Expected `this` value
* @throws AssertionError if spy was never called with this context
*/
function calledOn(spy: SinonSpy, thisValue: any): void;
/**
* Assert that spy was always called with specific `this` context
* @param spy - Spy to check
* @param thisValue - Expected `this` value for all calls
* @throws AssertionError if any call didn't use this context
*/
function alwaysCalledOn(spy: SinonSpy, thisValue: any): void;
/**
* Assert that spy was called as a constructor (with `new`)
* @param spy - Spy to check
* @throws AssertionError if spy was never called with `new`
*/
function calledWithNew(spy: SinonSpy): void;
/**
* Assert that spy was always called as a constructor
* @param spy - Spy to check
* @throws AssertionError if any call didn't use `new`
*/
function alwaysCalledWithNew(spy: SinonSpy): void;
}Usage Examples:
const context = { name: "test" };
const spy = sinon.spy();
// Call with specific context
spy.call(context, "arg");
// Assert context
assert.calledOn(spy, context);
// Constructor testing
function TestConstructor() {}
const constructorSpy = sinon.spy(TestConstructor);
new TestConstructor();
assert.calledWithNew(constructorSpy);Assert specific call scenarios like once with exact arguments.
declare namespace assert {
/**
* Assert that spy was called once and with exact arguments
* @param spy - Spy to check
* @param args - Expected exact arguments for the single call
* @throws AssertionError if spy wasn't called exactly once with these exact arguments
*/
function calledOnceWithExactly(spy: SinonSpy, ...args: any[]): void;
/**
* Assert that spy was called once and with matching arguments
* @param spy - Spy to check
* @param matchers - Matcher patterns for the single call
* @throws AssertionError if spy wasn't called exactly once with matching arguments
*/
function calledOnceWithMatch(spy: SinonSpy, ...matchers: any[]): void;
}Usage Examples:
const spy = sinon.spy();
spy("exact", "arguments");
// Assert single call with exact arguments
assert.calledOnceWithExactly(spy, "exact", "arguments");
// With matchers
const spy2 = sinon.spy();
spy2("test", { key: "value" });
assert.calledOnceWithMatch(spy2, match.string, match.object);Assert that spies/stubs threw exceptions.
declare namespace assert {
/**
* Assert that spy threw an exception
* @param spy - Spy to check
* @param error - Optional specific error to check for
* @throws AssertionError if spy never threw (the specified) exception
*/
function threw(spy: SinonSpy, error?: any): void;
/**
* Assert that spy always threw an exception
* @param spy - Spy to check
* @param error - Optional specific error to check for
* @throws AssertionError if spy didn't always throw (the specified) exception
*/
function alwaysThrew(spy: SinonSpy, error?: any): void;
}Usage Examples:
const stub = sinon.stub();
stub.throws(new TypeError("Invalid argument"));
try {
stub();
} catch (e) {
// Exception expected
}
// Assert that exception was thrown
assert.threw(stub);
assert.threw(stub, "TypeError");
assert.threw(stub, new TypeError("Invalid argument"));Assert the order in which multiple spies were called.
declare namespace assert {
/**
* Assert that spies were called in the specified order
* @param spies - Spies in expected call order
* @throws AssertionError if spies were not called in this order
*/
function callOrder(...spies: SinonSpy[]): void;
}Usage Examples:
const spy1 = sinon.spy();
const spy2 = sinon.spy();
const spy3 = sinon.spy();
// Call in specific order
spy1();
spy2();
spy3();
spy1(); // Can be called again
// Assert order
assert.callOrder(spy1, spy2, spy3);Assert values match specific patterns using Sinon's matcher system.
declare namespace assert {
/**
* Assert that actual value matches the expected pattern
* @param actual - Actual value to test
* @param matcher - Matcher pattern or expected value
* @throws AssertionError if value doesn't match pattern
*/
function match(actual: any, matcher: any): void;
}Usage Examples:
import { assert, match } from "sinon";
// Test values against matchers
assert.match("hello", match.string);
assert.match(42, match.number);
assert.match({ name: "test" }, match.object);
assert.match({ name: "test" }, match.has("name"));
// Complex matching
const user = { id: 1, name: "John", age: 25 };
assert.match(user, {
id: match.number,
name: match.string,
age: match.greaterThan(18)
});Utility methods for test success and failure.
declare namespace assert {
/**
* Explicitly fail an assertion with a message
* @param message - Failure message
* @throws AssertionError with the provided message
*/
function fail(message?: string): void;
/**
* Explicitly pass an assertion (for test runners that track passes)
* @param message - Optional pass message
*/
function pass(message?: string): void;
}Usage Examples:
// Conditional assertion
if (someCondition) {
assert.pass("Condition met");
} else {
assert.fail("Expected condition to be true");
}Expose assertion methods on testing framework objects.
declare namespace assert {
/**
* Expose assertion methods on a target object
* @param target - Object to add assertion methods to
* @param options - Configuration for exposed methods
*/
function expose(target: any, options?: {
prefix?: string;
includeFail?: boolean;
}): void;
}Usage Examples:
// Expose on test context (e.g., Mocha's `this`)
beforeEach(function() {
sinon.assert.expose(this, { prefix: "should" });
});
it("should test spy behavior", function() {
const spy = sinon.spy();
spy();
// Now you can use this.shouldHaveBeenCalled instead of assert.called
this.shouldHaveBeenCalled(spy);
this.shouldHaveBeenCalledOnce(spy);
});Examples of using assertions with popular testing frameworks.
Usage Examples:
// Mocha integration
describe("User service", () => {
let userService, apiSpy;
beforeEach(() => {
apiSpy = sinon.spy(api, "fetch");
});
afterEach(() => {
sinon.restore();
});
it("should fetch user data", async () => {
await userService.getUser(1);
sinon.assert.calledOnce(apiSpy);
sinon.assert.calledWith(apiSpy, "/users/1");
});
});
// Jest integration (can also use Jest's expect)
test("should call callback", () => {
const callback = sinon.spy();
const service = new Service(callback);
service.process("data");
sinon.assert.calledOnce(callback);
sinon.assert.calledWith(callback, "data");
});interface SinonAssert {
// Basic call assertions
called(spy: SinonSpy): void;
notCalled(spy: SinonSpy): void;
calledOnce(spy: SinonSpy): void;
calledTwice(spy: SinonSpy): void;
calledThrice(spy: SinonSpy): void;
callCount(spy: SinonSpy, count: number): void;
// Argument assertions
calledWith(spy: SinonSpy, ...args: any[]): void;
calledWithExactly(spy: SinonSpy, ...args: any[]): void;
calledWithMatch(spy: SinonSpy, ...matchers: any[]): void;
alwaysCalledWith(spy: SinonSpy, ...args: any[]): void;
alwaysCalledWithExactly(spy: SinonSpy, ...args: any[]): void;
alwaysCalledWithMatch(spy: SinonSpy, ...matchers: any[]): void;
neverCalledWith(spy: SinonSpy, ...args: any[]): void;
neverCalledWithMatch(spy: SinonSpy, ...matchers: any[]): void;
// Context assertions
calledOn(spy: SinonSpy, thisValue: any): void;
alwaysCalledOn(spy: SinonSpy, thisValue: any): void;
calledWithNew(spy: SinonSpy): void;
alwaysCalledWithNew(spy: SinonSpy): void;
// Special assertions
calledOnceWithExactly(spy: SinonSpy, ...args: any[]): void;
calledOnceWithMatch(spy: SinonSpy, ...matchers: any[]): void;
// Exception assertions
threw(spy: SinonSpy, error?: any): void;
alwaysThrew(spy: SinonSpy, error?: any): void;
// Order assertions
callOrder(...spies: SinonSpy[]): void;
// Matcher assertions
match(actual: any, matcher: any): void;
// Utility
fail(message?: string): void;
pass(message?: string): void;
expose(target: any, options?: { prefix?: string; includeFail?: boolean }): void;
}Install with Tessl CLI
npx tessl i tessl/npm-sinon