CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sinon

JavaScript test spies, stubs and mocks for framework-agnostic unit testing.

Pending
Overview
Eval results
Files

matchers.mddocs/

Argument Matching

Sinon's matcher system provides flexible argument matching for creating sophisticated test assertions and stub behaviors. Matchers allow you to specify patterns instead of exact values, making tests more robust and expressive.

Capabilities

Basic Type Matchers

Match arguments based on their JavaScript types.

declare namespace match {
  /** Matches any value (always returns true) */
  const any: SinonMatcher;
  
  /** Matches any defined value (not null or undefined) */
  const defined: SinonMatcher;
  
  /** Matches truthy values */
  const truthy: SinonMatcher;
  
  /** Matches falsy values */
  const falsy: SinonMatcher;
  
  /** Matches boolean values */
  const bool: SinonMatcher;
  
  /** Matches number values (including NaN) */
  const number: SinonMatcher;
  
  /** Matches string values */
  const string: SinonMatcher;
  
  /** Matches object values (including arrays, functions, etc.) */
  const object: SinonMatcher;
  
  /** Matches function values */
  const func: SinonMatcher;
  
  /** Matches array values */
  const array: SinonMatcher;
  
  /** Matches regular expression values */
  const regexp: SinonMatcher;
  
  /** Matches Date objects */
  const date: SinonMatcher;
  
  /** Matches Symbol values */
  const symbol: SinonMatcher;
  
  /** Matches Map objects */
  const map: SinonMatcher;
  
  /** Matches Set objects */
  const set: SinonMatcher;
}

Usage Examples:

import { match } from "sinon";

const spy = sinon.spy();

spy("hello", 42, true, {}, []);

// Use type matchers in assertions
sinon.assert.calledWith(spy, match.string, match.number, match.bool, match.object, match.array);

// Use in stub configurations
const stub = sinon.stub();
stub.withArgs(match.string).returns("string argument");
stub.withArgs(match.number).returns("number argument");

console.log(stub("test")); // "string argument"
console.log(stub(123)); // "number argument"

Value Matchers

Match arguments based on specific values or references.

declare namespace match {
  /**
   * Matches the exact same reference (using ===)
   * @param value - Value to match by reference
   * @returns Matcher for the exact reference
   */
  function same(value: any): SinonMatcher;
  
  /**
   * Matches values with specific typeof result
   * @param type - Expected typeof string
   * @returns Matcher for the typeof result
   */
  function typeOf(type: string): SinonMatcher;
  
  /**
   * Matches instances of a specific constructor
   * @param constructor - Constructor function to match against
   * @returns Matcher for instanceof check
   */
  function instanceOf(constructor: Function): SinonMatcher;
}

Usage Examples:

const obj = { name: "test" };
const spy = sinon.spy();

spy(obj, new Date(), "hello");

// Match by reference
sinon.assert.calledWith(spy, match.same(obj));

// Match by typeof
sinon.assert.calledWith(spy, match.object, match.typeOf("object"), match.typeOf("string"));

// Match by instanceof
sinon.assert.calledWith(spy, match.object, match.instanceOf(Date), match.string);

Property Matchers

Match objects based on their properties and property values.

declare namespace match {
  /**
   * Matches objects that have a specific property
   * @param property - Property name to check for
   * @param value - Optional expected property value
   * @returns Matcher for property existence and value
   */
  function has(property: string, value?: any): SinonMatcher;
  
  /**
   * Matches objects that have a specific own property (not inherited)
   * @param property - Property name that must be own property
   * @param value - Optional expected property value
   * @returns Matcher for own property existence and value
   */
  function hasOwn(property: string, value?: any): SinonMatcher;
  
  /**
   * Matches objects that have nested property paths
   * @param path - Dot-separated property path (e.g., "user.profile.name")
   * @param value - Optional expected nested property value
   * @returns Matcher for nested property existence and value
   */
  function hasNested(path: string, value?: any): SinonMatcher;
}

Usage Examples:

const spy = sinon.spy();

const user = {
  id: 1,
  name: "John",
  profile: {
    email: "john@example.com",
    settings: { theme: "dark" }
  }
};

spy(user);

// Match by property existence
sinon.assert.calledWith(spy, match.has("name"));
sinon.assert.calledWith(spy, match.has("id", 1));

// Match by own property (not inherited)
sinon.assert.calledWith(spy, match.hasOwn("name"));

// Match nested properties
sinon.assert.calledWith(spy, match.hasNested("profile.email"));
sinon.assert.calledWith(spy, match.hasNested("profile.settings.theme", "dark"));

Numeric Matchers

Match numbers based on ranges and comparisons.

declare namespace match {
  /**
   * Matches numbers greater than specified value
   * @param value - Minimum value (exclusive)
   * @returns Matcher for numbers greater than value
   */
  function greaterThan(value: number): SinonMatcher;
  
  /**
   * Matches numbers greater than or equal to specified value
   * @param value - Minimum value (inclusive)
   * @returns Matcher for numbers >= value
   */
  function atLeast(value: number): SinonMatcher;
  
  /**
   * Matches numbers less than specified value
   * @param value - Maximum value (exclusive)
   * @returns Matcher for numbers less than value
   */
  function lessThan(value: number): SinonMatcher;
  
  /**
   * Matches numbers less than or equal to specified value
   * @param value - Maximum value (inclusive)
   * @returns Matcher for numbers <= value
   */
  function atMost(value: number): SinonMatcher;
}

Usage Examples:

const spy = sinon.spy();

spy(25, 100, 5);

// Numeric comparisons
sinon.assert.calledWith(spy, match.greaterThan(18)); // 25 > 18
sinon.assert.calledWith(spy, match.atLeast(25));     // 25 >= 25
sinon.assert.calledWith(spy, match.lessThan(200));   // 100 < 200
sinon.assert.calledWith(spy, match.atMost(10));      // 5 <= 10

// Use in stubs
const stub = sinon.stub();
stub.withArgs(match.greaterThan(50)).returns("large number");
stub.withArgs(match.atMost(50)).returns("small number");

console.log(stub(100)); // "large number"
console.log(stub(25));  // "small number"

String Matchers

Match strings based on patterns and content.

declare namespace match {
  /**
   * Matches strings that start with specified prefix
   * @param prefix - Required string prefix
   * @returns Matcher for strings starting with prefix
   */
  function startsWith(prefix: string): SinonMatcher;
  
  /**
   * Matches strings that end with specified suffix
   * @param suffix - Required string suffix
   * @returns Matcher for strings ending with suffix
   */
  function endsWith(suffix: string): SinonMatcher;
  
  /**
   * Matches strings that contain specified substring
   * @param substring - Required substring
   * @returns Matcher for strings containing substring
   */
  function includes(substring: string): SinonMatcher;
}

Usage Examples:

const spy = sinon.spy();

spy("hello world", "testing123", "world hello");

// String pattern matching
sinon.assert.calledWith(spy, match.startsWith("hello"));
sinon.assert.calledWith(spy, match.endsWith("123"));
sinon.assert.calledWith(spy, match.includes("world"));

// Combine multiple string patterns
sinon.assert.calledWith(spy, 
  match.startsWith("hello").and(match.includes("world"))
);

Array and Collection Matchers

Match arrays and collections based on content and structure.

declare namespace match {
  /**
   * Matches arrays where every element matches the provided matcher
   * @param matcher - Matcher that all elements must satisfy
   * @returns Matcher for arrays where all elements match
   */
  function every(matcher: SinonMatcher): SinonMatcher;
  
  /**
   * Matches arrays where at least one element matches the provided matcher
   * @param matcher - Matcher that at least one element must satisfy
   * @returns Matcher for arrays where some elements match
   */
  function some(matcher: SinonMatcher): SinonMatcher;
  
  /**
   * Matches arrays that contain all specified elements (order doesn't matter)
   * @param elements - Elements that must be present in array
   * @returns Matcher for arrays containing all elements
   */
  function arrayContaining(elements: any[]): SinonMatcher;
  
  /**
   * Matches arrays or objects by deep equality
   * @param value - Value to match by deep comparison
   * @returns Matcher for deep equality
   */
  function deepEquals(value: any): SinonMatcher;
  
  /**
   * Matches arrays with specific length
   * @param length - Expected array length
   * @returns Matcher for arrays with exact length
   */
  function arrayWithLength(length: number): SinonMatcher;
}

Usage Examples:

const spy = sinon.spy();

spy([1, 2, 3], ["a", "b", "c"], [5, 10, 15]);

// Array content matching
sinon.assert.calledWith(spy, match.every(match.number));
sinon.assert.calledWith(spy, match.some(match.string));
sinon.assert.calledWith(spy, match.arrayContaining([1, 3])); // Contains 1 and 3

// Array structure matching
sinon.assert.calledWith(spy, match.arrayWithLength(3));

// Deep equality
const expectedData = { items: [1, 2, 3], total: 3 };
spy(expectedData);
sinon.assert.calledWith(spy, match.deepEquals(expectedData));

Custom Matchers

Create custom matchers with predicate functions.

declare namespace match {
  /**
   * Creates a custom matcher using a predicate function
   * @param predicate - Function that returns true for matching values
   * @param message - Optional description for the matcher
   * @returns Custom matcher based on predicate
   */
  function (predicate: (value: any) => boolean, message?: string): SinonMatcher;
}

Usage Examples:

const spy = sinon.spy();

// Custom matchers with predicates
const isEven = match((n) => n % 2 === 0, "even number");
const isValidEmail = match((email) => email.includes("@"), "valid email");
const isPositive = match((n) => n > 0, "positive number");

spy(4, "test@example.com", -5);

sinon.assert.calledWith(spy, isEven);        // 4 is even
sinon.assert.calledWith(spy, isValidEmail);  // has @
sinon.assert.neverCalledWith(spy, isPositive); // -5 is not positive

// Use in stubs
const stub = sinon.stub();
stub.withArgs(isEven).returns("even");
stub.withArgs(isPositive).returns("positive");

console.log(stub(4)); // "even"
console.log(stub(3)); // undefined (no match)

Matcher Combinations

Combine multiple matchers using logical operators.

interface SinonMatcher {
  /**
   * Combine matchers with logical AND
   * @param matcher - Matcher to combine with AND logic
   * @returns Combined matcher (both must match)
   */
  and(matcher: SinonMatcher): SinonMatcher;
  
  /**
   * Combine matchers with logical OR
   * @param matcher - Matcher to combine with OR logic
   * @returns Combined matcher (either can match)
   */
  or(matcher: SinonMatcher): SinonMatcher;
}

Usage Examples:

const spy = sinon.spy();

spy("hello123", 42, "world");

// Combine matchers with AND
const stringWithNumbers = match.string.and(match.includes("123"));
sinon.assert.calledWith(spy, stringWithNumbers);

// Combine matchers with OR
const stringOrNumber = match.string.or(match.number);
sinon.assert.calledWith(spy, stringOrNumber); // Matches first and second args

// Complex combinations
const validId = match.number.and(match.greaterThan(0));
const validName = match.string.and(match.startsWith("user_"));
const validIdentifier = validId.or(validName);

const stub = sinon.stub();
stub.withArgs(validIdentifier).returns("valid");

console.log(stub(42));        // "valid" (positive number)
console.log(stub("user_123")); // "valid" (starts with user_)
console.log(stub(-1));        // undefined (negative number)

Matcher Usage in Different Contexts

Using matchers across various Sinon features.

Usage Examples:

// In spy assertions
const spy = sinon.spy();
spy({ id: 1, name: "test" });
sinon.assert.calledWith(spy, match.has("id", 1));

// In stub behaviors
const stub = sinon.stub();
stub.withArgs(match.string, match.number).returns("string and number");
stub.withArgs(match.object).callsFake((obj) => `Object with ${Object.keys(obj).length} keys`);

// In mock expectations
const obj = { process: () => {} };
const mock = sinon.mock(obj);
mock.expects("process").withArgs(match.array, match.func);

// In fake verification
const fake = sinon.fake();
fake([1, 2, 3], () => {});
console.log(fake.calledWith(match.every(match.number), match.func)); // true

Built-in Matcher Utilities

Additional utility matchers for common patterns.

declare namespace match {
  /** Matches null values */
  const nullValue: SinonMatcher;
  
  /** Matches undefined values */
  const undef: SinonMatcher;
  
  /** Matches NaN values */
  const nan: SinonMatcher;
  
  /** Matches positive numbers (> 0) */
  const positive: SinonMatcher;
  
  /** Matches negative numbers (< 0) */
  const negative: SinonMatcher;
  
  /** Matches integer numbers */
  const integer: SinonMatcher;
  
  /** Matches float numbers */
  const float: SinonMatcher;
}

Usage Examples:

const spy = sinon.spy();

spy(null, undefined, NaN, 3.14, -5, 42);

// Use built-in utility matchers
sinon.assert.calledWith(spy, match.nullValue);
sinon.assert.calledWith(spy, match.undef);
sinon.assert.calledWith(spy, match.nan);
sinon.assert.calledWith(spy, match.float);      // 3.14
sinon.assert.calledWith(spy, match.negative);   // -5
sinon.assert.calledWith(spy, match.integer);    // 42

Types

interface SinonMatcher {
  /** Test if a value matches this matcher */
  test(value: any): boolean;
  
  /** Combine with another matcher using AND logic */
  and(matcher: SinonMatcher): SinonMatcher;
  
  /** Combine with another matcher using OR logic */
  or(matcher: SinonMatcher): SinonMatcher;
  
  /** String representation of the matcher */
  toString(): string;
}

interface SinonMatch {
  // Basic matchers
  any: SinonMatcher;
  defined: SinonMatcher;
  truthy: SinonMatcher;
  falsy: SinonMatcher;
  bool: SinonMatcher;
  number: SinonMatcher;
  string: SinonMatcher;
  object: SinonMatcher;
  func: SinonMatcher;
  array: SinonMatcher;
  regexp: SinonMatcher;
  date: SinonMatcher;
  
  // Value matchers
  same(value: any): SinonMatcher;
  typeOf(type: string): SinonMatcher;
  instanceOf(constructor: Function): SinonMatcher;
  
  // Property matchers
  has(property: string, value?: any): SinonMatcher;
  hasOwn(property: string, value?: any): SinonMatcher;
  hasNested(path: string, value?: any): SinonMatcher;
  
  // Numeric matchers
  greaterThan(value: number): SinonMatcher;
  lessThan(value: number): SinonMatcher;
  atLeast(value: number): SinonMatcher;
  atMost(value: number): SinonMatcher;
  
  // String matchers
  startsWith(prefix: string): SinonMatcher;
  endsWith(suffix: string): SinonMatcher;
  includes(substring: string): SinonMatcher;
  
  // Collection matchers
  every(matcher: SinonMatcher): SinonMatcher;
  some(matcher: SinonMatcher): SinonMatcher;
  arrayContaining(elements: any[]): SinonMatcher;
  deepEquals(value: any): SinonMatcher;
  
  // Custom matcher
  (predicate: (value: any) => boolean, message?: string): SinonMatcher;
}

Install with Tessl CLI

npx tessl i tessl/npm-sinon

docs

assertions.md

fakes.md

index.md

matchers.md

mocks.md

promises.md

sandbox.md

spies.md

stubs.md

timers.md

tile.json