CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jest-snapshot

Jest snapshot testing utilities that enable capturing component output, API responses, or any serializable values as snapshots for regression testing and change detection

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

serialization.mddocs/

Serialization and Plugins

Pluggable serialization system for customizing how values are converted to snapshot strings. Supports built-in serializers for common data types and custom serializers for domain-specific objects.

Capabilities

Plugin Management

Functions for managing snapshot serialization plugins that control how different types of values are converted to string representations.

/**
 * Adds a custom serializer plugin to the beginning of the plugin list
 * Plugins added later take precedence over earlier ones
 * @param plugin - PrettyFormat plugin for custom serialization
 */
function addSerializer(plugin: PrettyFormatPlugin): void;

/**
 * Gets all registered serializer plugins in priority order
 * @returns Array of all registered plugins, with custom plugins first
 */
function getSerializers(): PrettyFormatPlugins;

type PrettyFormatPlugin = {
  test: (val: unknown) => boolean;
  serialize: (
    val: unknown, 
    config: Config, 
    indentation: string, 
    depth: number, 
    refs: Refs, 
    printer: Printer
  ) => string;
};

type PrettyFormatPlugins = Array<PrettyFormatPlugin>;

Usage Examples:

import { addSerializer, getSerializers } from "jest-snapshot";

// Custom serializer for Date objects
const dateSerializer = {
  test: (val) => val instanceof Date,
  serialize: (val) => `Date("${val.toISOString()}")`
};

addSerializer(dateSerializer);

// Custom serializer for database models
const modelSerializer = {
  test: (val) => val && typeof val === 'object' && val.constructor.name === 'User',
  serialize: (val, config, indentation, depth, refs, printer) => {
    return `User(${printer(val.id, config, indentation, depth, refs)})`;
  }
};

addSerializer(modelSerializer);

// Get all serializers (custom ones first)
const allSerializers = getSerializers();
console.log(allSerializers.length); // Built-in + custom serializers

Built-in Serializers

Jest Snapshot includes several built-in serializers that handle common data types:

React Components:

  • ReactElement - Serializes React elements and JSX
  • ReactTestComponent - Handles React test renderer components

DOM Elements:

  • DOMElement - Serializes DOM nodes and HTML elements
  • DOMCollection - Handles NodeLists, HTMLCollections, etc.

Data Structures:

  • Immutable - Serializes Immutable.js data structures
  • AsymmetricMatcher - Handles Jest's expect.any(), expect.objectContaining(), etc.

Jest Specific:

  • jestMockSerializer - Serializes Jest mock functions with call information

Custom Serializer Implementation

Create custom serializers for domain-specific objects or to customize existing type serialization:

// Custom serializer for URL objects
const urlSerializer = {
  test: (val) => val instanceof URL,
  serialize: (val) => `URL("${val.href}")`
};

addSerializer(urlSerializer);

// Before: URL { href: "https://example.com", protocol: "https:", ... }
// After:  URL("https://example.com")

// Custom serializer for Error objects with stack traces
const errorSerializer = {
  test: (val) => val instanceof Error,
  serialize: (val, config, indentation, depth, refs, printer) => {
    const name = val.constructor.name;
    const message = val.message;
    const stack = val.stack ? `\n${val.stack}` : '';
    return `${name}: ${message}${stack}`;
  }
};

addSerializer(errorSerializer);

// Complex custom serializer with nested printing
const apiResponseSerializer = {
  test: (val) => val && typeof val === 'object' && val.type === 'api-response',
  serialize: (val, config, indentation, depth, refs, printer) => {
    const status = val.status;
    const data = printer(val.data, config, indentation, depth, refs);
    return `ApiResponse(${status}) ${data}`;
  }
};

addSerializer(apiResponseSerializer);

Serializer Priority

Serializers are tested in order, with the first matching serializer being used:

// Order matters - first matching test() wins
addSerializer(specificSerializer);  // Added last, tested first
addSerializer(generalSerializer);   // Added earlier, tested later

// Built-in serializers are tested after all custom serializers
// Default object/primitive serialization happens last

Serializer Testing

Serializers include a test function that determines whether they should handle a specific value:

const customSerializer = {
  // Test function - return true to handle this value
  test: (val) => {
    return val && 
           typeof val === 'object' && 
           val.constructor.name === 'CustomClass' &&
           typeof val.serialize === 'function';
  },
  
  // Serialize function - convert value to string
  serialize: (val, config, indentation, depth, refs, printer) => {
    // Use the object's own serialize method
    return val.serialize();
  }
};

Advanced Serialization Features

Nested Object Printing: Use the printer function to serialize nested values:

const wrapperSerializer = {
  test: (val) => val && val.type === 'wrapper',
  serialize: (val, config, indentation, depth, refs, printer) => {
    // Use printer for nested values to maintain formatting
    const content = printer(val.content, config, indentation, depth, refs);
    return `Wrapper(${content})`;
  }
};

Depth and Reference Handling: Handle circular references and depth limits:

const circularSafeSerializer = {
  test: (val) => val && val.type === 'node',
  serialize: (val, config, indentation, depth, refs, printer) => {
    if (depth > 5) {
      return '[Deep Object]';
    }
    
    const children = val.children.map(child => 
      printer(child, config, indentation, depth + 1, refs)
    );
    
    return `Node(${children.join(', ')})`;
  }
};

Configuration-aware Serialization: Access pretty-format configuration:

const configAwareSerializer = {
  test: (val) => val instanceof Map,
  serialize: (val, config, indentation, depth, refs, printer) => {
    const entries = Array.from(val.entries());
    
    if (config.min) {
      // Compact format for min config
      return `Map(${entries.length})`;
    }
    
    // Full format
    const items = entries.map(([key, value]) => {
      const k = printer(key, config, indentation, depth, refs);
      const v = printer(value, config, indentation, depth, refs);
      return `${k} => ${v}`;
    });
    
    return `Map {\n${indentation}  ${items.join(`,\n${indentation}  `)}\n${indentation}}`;
  }
};

Serializer Removal

There's currently no built-in way to remove serializers, but you can work around this:

// Get current serializers
const currentSerializers = getSerializers();

// Find built-in serializers (after your custom ones)
const builtInSerializers = currentSerializers.slice(customSerializerCount);

// Clear and re-add only desired serializers
// (This is a workaround - not officially supported)

Integration with Snapshot Formatting

Serializers work with Jest's snapshot formatting options:

// Snapshot format affects serializer output
const snapshotFormat = {
  indent: 2,
  printWidth: 80,
  min: false,
  escapeRegex: false,
  escapeString: true,
  plugins: getSerializers() // Your custom serializers included
};

Types

interface PrettyFormatPlugin {
  test: (val: unknown) => boolean;
  serialize: (
    val: unknown,
    config: Config,
    indentation: string,
    depth: number,
    refs: Refs,
    printer: Printer
  ) => string;
}

type PrettyFormatPlugins = Array<PrettyFormatPlugin>;

type Config = {
  callToJSON: boolean;
  compareKeys: undefined;
  escapeRegex: boolean;
  escapeString: boolean;
  highlight: boolean;
  indent: string;
  maxDepth: number;
  min: boolean;
  plugins: PrettyFormatPlugins;
  printBasicPrototype: boolean;
  printFunctionName: boolean;
  spacingInner: string;
  spacingOuter: string;
  theme: Theme;
};

type Printer = (
  val: unknown,
  config: Config,
  indentation: string,
  depth: number,
  refs: Refs
) => string;

type Refs = Set<unknown>;

interface Theme {
  comment: string;
  content: string;
  prop: string;
  tag: string;
  value: string;
}

docs

cleanup.md

error-snapshots.md

index.md

path-resolution.md

serialization.md

snapshot-matchers.md

state-management.md

tile.json