CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jest-matcher-utils

A set of utility functions for expect and related packages

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

diff-generation.mddocs/

Diff Generation

Functions for comparing values and generating visual diffs for test output, helping developers understand exactly how expected and received values differ.

Capabilities

Diff Function

Generates diff output between two values when appropriate, with automatic detection of diffable types.

/**
 * Generate diff between two values
 * @param a - First value to compare
 * @param b - Second value to compare
 * @param options - Diff generation options
 * @returns Diff output string or null if not diffable
 */
function diff(
  a: unknown,
  b: unknown,
  options?: DiffOptions
): string | null;

type DiffOptions = {
  aAnnotation?: string;
  bAnnotation?: string;
  changeColor?: (arg: string) => string;
  changeLineTrailingSpaceColor?: (arg: string) => string;
  commonColor?: (arg: string) => string;
  commonLineTrailingSpaceColor?: (arg: string) => string;
  contextLines?: number;
  expand?: boolean;
  includeChangeCounts?: boolean;
  omitAnnotationLines?: boolean;
  patchColor?: (arg: string) => string;
};

Usage Examples:

import { diff } from "jest-matcher-utils";

// Basic object diff
const expected = { name: "Alice", age: 25, city: "NYC" };
const received = { name: "Alice", age: 30, city: "LA" };
const diffResult = diff(expected, received);
// Result: Colorized diff showing changed properties

// Array diff
const expectedArray = [1, 2, 3, 4];
const receivedArray = [1, 2, 5, 4];
const arrayDiff = diff(expectedArray, receivedArray);
// Result: Shows element differences

// String diff
const expectedText = "Hello world";
const receivedText = "Hello earth"; 
const textDiff = diff(expectedText, receivedText);
// Result: Character-level diff highlighting changes

// Returns null for non-diffable types
const numDiff = diff(5, 10);
// Result: null (numbers don't generate useful diffs)

// With options
const customDiff = diff(expected, received, {
  expand: true,
  includeChangeCounts: true
});

Print Diff Or Stringify

Generates comprehensive diff output or falls back to stringified comparison when diff is not useful.

/**
 * Generate diff output or stringify values for comparison
 * @param expected - Expected value
 * @param received - Received value  
 * @param expectedLabel - Label for expected value
 * @param receivedLabel - Label for received value
 * @param expand - Whether to expand diff output
 * @returns Formatted diff or comparison string
 */
function printDiffOrStringify(
  expected: unknown,
  received: unknown,
  expectedLabel: string,
  receivedLabel: string,
  expand: boolean
): string;

Usage Examples:

import { printDiffOrStringify } from "jest-matcher-utils";

// Object comparison with labels
const expected = { user: "Alice", role: "admin" };
const received = { user: "Alice", role: "user" };
const comparison = printDiffOrStringify(
  expected,
  received,
  "Expected",
  "Received", 
  false
);
// Result: Labeled diff output showing role change

// String comparison with multiline
const expectedText = `Line 1
Line 2
Line 3`;
const receivedText = `Line 1
Modified Line 2
Line 3`;
const textComparison = printDiffOrStringify(
  expectedText,
  receivedText,
  "Expected",
  "Received",
  true // expanded output
);
// Result: Unified diff format with line numbers

// Falls back to stringify for incomparable types
const numComparison = printDiffOrStringify(
  42,
  43,
  "Expected",
  "Received",
  false
);
// Result: 'Expected: 42\nReceived: 43'

// Handles identical values that serialize differently
const date1 = new Date('2024-01-01');
const date2 = new Date('2024-01-01');
const sameComparison = printDiffOrStringify(
  date1,
  date2,
  "Expected", 
  "Received",
  false
);
// Result: 'Expected: ...\nReceived: serializes to the same string'

Replace Matched To Asymmetric Matcher

Advanced function for replacing matched values with asymmetric matchers during comparison, handling Jest's expect.any(), expect.objectContaining(), etc.

/**
 * Replace matched values with asymmetric matchers for comparison
 * @param replacedExpected - Expected value to process
 * @param replacedReceived - Received value to process
 * @param expectedCycles - Cycle detection for expected value
 * @param receivedCycles - Cycle detection for received value
 * @returns Object with processed expected and received values
 */
function replaceMatchedToAsymmetricMatcher(
  replacedExpected: unknown,
  replacedReceived: unknown,
  expectedCycles: Array<unknown>,
  receivedCycles: Array<unknown>
): {replacedExpected: unknown; replacedReceived: unknown};

Usage Examples:

import { replaceMatchedToAsymmetricMatcher } from "jest-matcher-utils";

// Handle asymmetric matchers in expected values
const expected = {
  id: expect.any(Number),
  name: "Alice",
  metadata: expect.objectContaining({ version: "1.0" })
};

const received = {
  id: 123,
  name: "Alice", 
  metadata: { version: "1.0", extra: "data" }
};

const {replacedExpected, replacedReceived} = replaceMatchedToAsymmetricMatcher(
  expected,
  received,
  [], // expectedCycles
  []  // receivedCycles
);

// Result: Asymmetric matchers that match are replaced in received,
// making diff output cleaner by showing what actually differs

// Handles circular references
const circular = { prop: null };
circular.prop = circular;

const processed = replaceMatchedToAsymmetricMatcher(
  circular,
  { prop: { prop: "different" } },
  [circular], // Track circular reference
  []
);
// Prevents infinite recursion during processing

// Used internally by Jest matchers
function customMatcher(received: unknown, expected: unknown) {
  const {replacedExpected, replacedReceived} = replaceMatchedToAsymmetricMatcher(
    expected,
    received,
    [],
    []
  );
  
  // Generate cleaner diff with processed values
  const diffOutput = diff(replacedExpected, replacedReceived);
  return diffOutput;
}

Diff Strategy

The diff generation system uses intelligent strategies:

  1. String Diffs: Character-level and line-level diffs for strings

    • Short strings: Character highlighting
    • Multi-line strings: Unified diff format
    • Trailing whitespace visualization
  2. Object/Array Diffs: Structured comparison

    • Property-level changes highlighted
    • Nested object traversal
    • Array element comparison
  3. Type-Based Logic: Different approaches per type

    • Primitives: Simple before/after display
    • Complex objects: Recursive property comparison
    • Functions/Dates/RegExp: String representation fallback
  4. Asymmetric Matcher Support:

    • Replaces matching asymmetric matchers
    • Cleaner diff output focusing on actual differences
    • Circular reference handling
  5. Performance Limits:

    • Maximum string length limits (20,000 chars)
    • Automatic fallback to stringify for large objects
    • Cycle detection prevents infinite recursion

The system automatically chooses the most informative representation for any value comparison, ensuring developers get the clearest possible view of test failures.

docs

diff-generation.md

index.md

matcher-display.md

value-formatting.md

value-validation.md

tile.json