CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jest-mock-extended

Type safe mocking extensions for jest

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

matchers.mddocs/

Matchers

Extensive built-in matcher system with type-safe argument validation and support for custom matcher creation.

Capabilities

Matcher Base Class

Foundation class for creating custom matchers that integrate with Jest's asymmetric matcher system.

/**
 * Base class for creating custom matchers
 */
class Matcher<T> implements MatcherLike<T> {
  $$typeof: symbol;
  inverse?: boolean;

  /**
   * Creates a new matcher instance
   * @param asymmetricMatch - Function that performs the actual matching logic
   * @param description - Human-readable description of the matcher
   */
  constructor(
    readonly asymmetricMatch: MatcherFn<T>, 
    private readonly description: string
  );

  /** Returns string representation of the matcher */
  toString(): string;
  
  /** Returns asymmetric matcher representation */
  toAsymmetricMatcher(): string;
  
  /** Returns expected type for Jest error messages */
  getExpectedType(): string;
}

/**
 * Function type for matcher predicate functions
 */
type MatcherFn<T> = (actualValue: T) => boolean;

Built-in Type Matchers

Matchers for validating basic JavaScript types with full type safety.

/** Matches any value of any type */
const any: MatcherCreator<any>;

/** Matches any boolean value (true or false) */
const anyBoolean: MatcherCreator<boolean>;

/** Matches any string value including empty strings */
const anyString: MatcherCreator<string>;

/** Matches any number that is not NaN */
const anyNumber: MatcherCreator<number>;

/** Matches any function */
const anyFunction: MatcherCreator<Function>;

/** Matches any symbol */
const anySymbol: MatcherCreator<Symbol>;

/** Matches any non-null object */
const anyObject: MatcherCreator<any>;

Usage Examples:

import { mock, any, anyString, anyNumber, anyBoolean } from "jest-mock-extended";

interface Calculator {
  add: (a: number, b: number) => number;
  concat: (str1: string, str2: string) => string;
  compare: (val1: any, val2: any) => boolean;
}

const calc = mock<Calculator>();

// Type-specific matching
calc.add.calledWith(anyNumber(), anyNumber()).mockReturnValue(42);
calc.concat.calledWith(anyString(), anyString()).mockReturnValue("result");
calc.compare.calledWith(any(), any()).mockReturnValue(anyBoolean());

// Test calls
expect(calc.add(5, 10)).toBe(42);
expect(calc.concat("hello", "world")).toBe("result");
expect(typeof calc.compare("a", 1)).toBe("boolean");

Collection Matchers

Matchers for validating arrays, maps, sets, and other collection types.

/** Matches any array */
const anyArray: MatcherCreator<any[]>;

/** Matches any Map instance */
const anyMap: MatcherCreator<Map<any, any>>;

/** Matches any Set instance */
const anySet: MatcherCreator<Set<any>>;

/** 
 * Matches instances of a specific class
 * @param clazz - Constructor function to match against
 */
const isA: MatcherCreator<any>;

Usage Examples:

import { mock, anyArray, anyMap, anySet, isA } from "jest-mock-extended";

class UserModel {
  constructor(public id: string, public name: string) {}
}

interface DataService {
  processArray: (items: any[]) => void;
  processMap: (data: Map<string, any>) => void;
  processSet: (unique: Set<string>) => void;
  processUser: (user: UserModel) => void;
}

const service = mock<DataService>();

// Collection type matching
service.processArray.calledWith(anyArray()).mockReturnValue(undefined);
service.processMap.calledWith(anyMap()).mockReturnValue(undefined);
service.processSet.calledWith(anySet()).mockReturnValue(undefined);

// Class instance matching
service.processUser.calledWith(isA(UserModel)).mockReturnValue(undefined);

// Test with actual instances
service.processArray([1, 2, 3]);
service.processMap(new Map([["key", "value"]]));
service.processSet(new Set(["a", "b", "c"]));
service.processUser(new UserModel("123", "John"));

Content Matchers

Matchers for validating the contents of collections and objects.

/**
 * Checks if array includes the specified value
 * @param arrayVal - Value that should be present in the array
 */
const arrayIncludes: MatcherCreator<any[], any>;

/**
 * Checks if Set contains the specified value  
 * @param setVal - Value that should be present in the Set
 */
const setHas: MatcherCreator<Set<any>, any>;

/**
 * Checks if Map contains the specified key
 * @param mapKey - Key that should be present in the Map
 */
const mapHas: MatcherCreator<Map<any, any>, any>;

/**
 * Checks if object contains the specified key
 * @param key - Property name that should exist on the object
 */
const objectContainsKey: MatcherCreator<any, string>;

/**
 * Checks if object contains the specified value
 * @param value - Value that should be present in object's values
 */
const objectContainsValue: MatcherCreator<any>;

Usage Examples:

import { 
  mock, 
  arrayIncludes, 
  setHas, 
  mapHas, 
  objectContainsKey, 
  objectContainsValue 
} from "jest-mock-extended";

interface SearchService {
  searchInArray: (items: string[], query: string) => boolean;
  searchInSet: (items: Set<string>, query: string) => boolean;
  searchInMap: (data: Map<string, any>, key: string) => boolean;
  searchInObject: (obj: any, criteria: any) => boolean;
}

const search = mock<SearchService>();

// Content validation
search.searchInArray
  .calledWith(arrayIncludes("target"), "target")
  .mockReturnValue(true);

search.searchInSet
  .calledWith(setHas("item"), "item")
  .mockReturnValue(true);

search.searchInMap
  .calledWith(mapHas("key"), "key")
  .mockReturnValue(true);

search.searchInObject
  .calledWith(objectContainsKey("name"), "name")
  .mockReturnValue(true);

search.searchInObject
  .calledWith(objectContainsValue("John"), "John")
  .mockReturnValue(true);

// Test with matching content
expect(search.searchInArray(["a", "target", "c"], "target")).toBe(true);
expect(search.searchInSet(new Set(["a", "item", "c"]), "item")).toBe(true);
expect(search.searchInMap(new Map([["key", "value"]]), "key")).toBe(true);
expect(search.searchInObject({ name: "John", age: 25 }, "name")).toBe(true);
expect(search.searchInObject({ name: "John", age: 25 }, "John")).toBe(true);

Null/Undefined Matchers

Matchers for validating null, undefined, and empty values.

/** Matches values that are not null */
const notNull: MatcherCreator<any>;

/** Matches values that are not undefined */
const notUndefined: MatcherCreator<any>;

/** Matches values that are not null, undefined, or empty string */
const notEmpty: MatcherCreator<any>;

Usage Examples:

import { mock, notNull, notUndefined, notEmpty } from "jest-mock-extended";

interface ValidationService {
  validateRequired: (value: any) => boolean;
  validateOptional: (value: any) => boolean;
  validateNonEmpty: (value: any) => boolean;
}

const validator = mock<ValidationService>();

// Null/undefined validation
validator.validateRequired.calledWith(notNull()).mockReturnValue(true);
validator.validateOptional.calledWith(notUndefined()).mockReturnValue(true);
validator.validateNonEmpty.calledWith(notEmpty()).mockReturnValue(true);

// Test validation
expect(validator.validateRequired("value")).toBe(true);
expect(validator.validateOptional(0)).toBe(true);
expect(validator.validateNonEmpty("text")).toBe(true);

// These would not match the expectations
// validator.validateRequired(null); // Would not match notNull()
// validator.validateOptional(undefined); // Would not match notUndefined()
// validator.validateNonEmpty(""); // Would not match notEmpty()

Argument Captor

Special matcher for capturing argument values during mock function calls.

/**
 * Captor matcher for capturing argument values
 */
class CaptorMatcher<T> {
  $$typeof: symbol;
  readonly asymmetricMatch: MatcherFn<T>;
  /** Last captured value */
  readonly value: T;
  /** All captured values in order */
  readonly values: T[];
  
  constructor();
  getExpectedType(): string;
  toString(): string;
  toAsymmetricMatcher(): string;
}

/**
 * Creates an argument captor for capturing call arguments
 * @returns Captor matcher instance
 */
const captor: <T = any>() => CaptorMatcher<T>;

Usage Examples:

import { mock, captor } from "jest-mock-extended";

interface EventLogger {
  logEvent: (event: string, data: any, timestamp: number) => void;
  logError: (error: Error, context: string) => void;
}

const logger = mock<EventLogger>();

// Create captors for different argument types
const eventCaptor = captor<string>();
const dataCaptor = captor<any>();
const timestampCaptor = captor<number>();

// Set up captor expectations
logger.logEvent
  .calledWith(eventCaptor, dataCaptor, timestampCaptor)
  .mockReturnValue(undefined);

// Make calls that will be captured
logger.logEvent("user:login", { userId: "123" }, Date.now());
logger.logEvent("user:logout", { userId: "123", reason: "timeout" }, Date.now());

// Access captured values
expect(eventCaptor.value).toBe("user:logout"); // Last captured value
expect(eventCaptor.values).toEqual(["user:login", "user:logout"]); // All values

expect(dataCaptor.values[0]).toEqual({ userId: "123" });
expect(dataCaptor.values[1]).toEqual({ userId: "123", reason: "timeout" });

expect(typeof timestampCaptor.value).toBe("number");

Custom Matcher Creation

Create custom matchers with specific validation logic.

/**
 * Creates a custom matcher from a predicate function
 * @param matcher - Function that returns true for matching values
 * @returns Custom matcher instance
 */
const matches: <T = any>(matcher: MatcherFn<T>) => Matcher<T>;

/**
 * Interface for creating reusable matcher functions
 */
interface MatcherCreator<T, E = T> {
  (expectedValue?: E): Matcher<T>;
}

Usage Examples:

import { mock, matches, MatcherCreator, Matcher } from "jest-mock-extended";

interface StringValidator {
  validateEmail: (email: string) => boolean;
  validatePhone: (phone: string) => boolean;
  validateLength: (text: string, min: number, max: number) => boolean;
}

const validator = mock<StringValidator>();

// Simple custom matcher
const isValidEmail = matches<string>((email) => 
  /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
);

validator.validateEmail.calledWith(isValidEmail).mockReturnValue(true);

// Reusable custom matcher creator
const hasLength: MatcherCreator<string, number> = (expectedLength) => 
  new Matcher(
    (actualValue) => actualValue.length === expectedLength,
    `hasLength(${expectedLength})`
  );

const isLongerThan: MatcherCreator<string, number> = (minLength) =>
  new Matcher(
    (actualValue) => actualValue.length > minLength,
    `isLongerThan(${minLength})`
  );

// Use custom matchers
validator.validateLength
  .calledWith(hasLength(10), 5, 15)
  .mockReturnValue(true);

validator.validatePhone
  .calledWith(isLongerThan(9))
  .mockReturnValue(true);

// Test with custom matchers
expect(validator.validateEmail("user@example.com")).toBe(true);
expect(validator.validateLength("1234567890", 5, 15)).toBe(true);
expect(validator.validatePhone("1234567890")).toBe(true);

docs

argument-matching.md

basic-mocking.md

deep-mocking.md

index.md

matchers.md

utilities.md

tile.json