Claude Code Plugins

Community-maintained marketplace

Feedback

Use syrupy for pytest snapshot testing to ensure the immutability of computed results, manage snapshots, customize serialization, and handle complex data structures with built-in matchers and filters.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name syrupy
description Use syrupy for pytest snapshot testing to ensure the immutability of computed results, manage snapshots, customize serialization, and handle complex data structures with built-in matchers and filters.

Syrupy - Pytest Snapshot Testing

Syrupy is a zero-dependency pytest snapshot testing plugin that enables asserting the immutability of computed results through simple, idiomatic assertions.

Docs: https://syrupy-project.github.io/syrupy/

What is Syrupy?

Syrupy is a snapshot testing library that:

  • Captures the output/state of code at a point in time
  • Compares future test runs against saved snapshots
  • Automatically manages snapshot files in __snapshots__ directories
  • Integrates naturally with pytest's assertion syntax

Core Philosophy

Three Design Principles:

  1. Extensible: Easy to add support for custom/unsupported data types
  2. Idiomatic: Natural pytest-style assertions (assert x == snapshot)
  3. Sound: Fails tests if snapshots are missing or different

Target Use Case: Testing complex data structures, API responses, UI components, or any computed results that should remain stable over time.

Snapshot Fixture API

Core Methods

The snapshot fixture accepts several options per assertion:

  • matcher: Control how objects are serialized
  • exclude: Filter out properties from snapshots
  • include: Include only specific properties
  • extension_class: Use a different serialization format
  • diff: Capture only differences from a base
  • name: Custom name for the snapshot

Usage with Options

assert data == snapshot(matcher=my_matcher, exclude=my_filter, name="custom_name")

Built-in Extensions

Syrupy provides several snapshot extensions for different use cases:

AmberSnapshotExtension (Default)

  • Human-readable format
  • Stores all snapshots in .ambr files
  • Supports all Python built-in types
  • Custom object representation via __repr__

JSONSnapshotExtension

  • Stores snapshots as JSON files
  • Useful for API responses
  • Machine-readable format

SingleFileSnapshotExtension

  • One file per snapshot
  • Configurable file extensions
  • Useful for binary data or large snapshots

PNGSnapshotExtension

  • For image snapshot testing
  • Compares PNG image data

SVGSnapshotExtension

  • For SVG vector graphics
  • Text-based comparison of SVG content

Matchers

Matchers control how specific values are serialized during snapshot creation.

path_type

Match specific paths in data structures to types:

from syrupy.matchers import path_type
import datetime

matcher = path_type(
    {"date_created": (datetime,), "user.id": (int,), "nested.*.timestamp": (datetime,)}
)

path_value

Match paths and replace with specific values:

from syrupy.matchers import path_value

matcher = path_value({"id": "REDACTED_ID", "token": "***"})

Filters

Filters control which properties are included/excluded from snapshots.

props

Filter by property names (shallow):

from syrupy.filters import props

# Exclude specific properties
exclude = props("id", "timestamp", "random_value")

# Include only specific properties
include = props("name", "type", "data")

paths

Filter by full property paths:

from syrupy.filters import paths

# Exclude nested paths
exclude = paths("user.password", "response.headers.authorization", "items.*.id")

CLI Options

Syrupy adds several pytest command-line options:

  • --snapshot-update: Update snapshots with current values
  • --snapshot-warn-unused: Warn about unused snapshots
  • --snapshot-details: Show detailed snapshot information
  • --snapshot-default-extension: Change default extension class
  • --snapshot-no-colors: Disable colored output

Advanced Configuration

Custom Snapshot Names

def test_multiple_cases(snapshot):
    assert case_1 == snapshot(name="case_1")
    assert case_2 == snapshot(name="case_2")

Note: Custom names must be unique within a test function.

Persistent Configuration

Create a snapshot instance with default values:

def test_api_responses(snapshot):
    api_snapshot = snapshot.with_defaults(
        extension_class=JSONSnapshotExtension, exclude=props("timestamp", "request_id")
    )

    assert response1 == api_snapshot
    assert response2 == api_snapshot  # Uses same defaults

Custom Extensions

Create custom snapshot serializers by extending AbstractSnapshotExtension:

from syrupy.extensions.base import AbstractSnapshotExtension


class MyExtension(AbstractSnapshotExtension):
    def serialize(self, data, **kwargs):
        # Custom serialization logic
        return str(data)

    def matches(self, *, serialized_data, snapshot_data):
        # Custom comparison logic
        return serialized_data == snapshot_data

Snapshot Lifecycle

Creation Flow

  1. Run test without existing snapshot
  2. Test fails with "snapshot does not exist"
  3. Run with --snapshot-update to create
  4. Snapshot file created in __snapshots__/
  5. Commit snapshot to version control

Update Flow

  1. Code changes cause snapshot mismatch
  2. Test fails showing difference
  3. Review changes to ensure correctness
  4. Run with --snapshot-update if changes are expected
  5. Commit updated snapshot

Cleanup

Remove unused snapshots:

pytest --snapshot-update --snapshot-warn-unused

Data Type Support

Built-in Types

All Python built-in types are supported:

  • Primitives: int, float, str, bool, None
  • Collections: list, tuple, set, dict
  • Complex: datetime, bytes, custom objects (via __repr__)

Custom Objects

Options for custom object snapshots:

  1. Override __repr__ method
  2. Use custom matcher
  3. Create custom extension
  4. Use exclude/include filters

Best Practices

DO

  1. Commit snapshots to version control: They're part of your test suite
  2. Review snapshot changes carefully: Ensure changes are intentional
  3. Use meaningful test names: Helps identify snapshot purpose
  4. Keep snapshots focused: Test one thing per snapshot
  5. Use matchers for non-deterministic data: Dates, IDs, timestamps

DON'T

  1. Don't snapshot entire responses blindly: Filter out volatile data
  2. Don't ignore snapshot changes: They indicate behavior changes
  3. Don't use generic test names: Makes debugging harder
  4. Don't snapshot huge data structures: Use filters or separate tests
  5. Don't update snapshots without review: Verify changes are correct

Common Patterns

API Response Testing

Use JSON extension with filters:

@pytest.fixture
def api_snapshot(snapshot):
    return snapshot.use_extension(JSONSnapshotExtension).with_defaults(
        exclude=props("timestamp", "request_id", "session")
    )

Dynamic Data Handling

Use matchers for non-deterministic values:

from syrupy.matchers import path_type
import uuid
import datetime

assert response == snapshot(
    matcher=path_type(
        {
            "id": (uuid.UUID,),
            "created_at": (datetime.datetime,),
            "*.timestamp": (datetime.datetime,),
        }
    )
)

Diff-Based Snapshots

Capture only changes from a baseline:

def test_incremental_changes(snapshot):
    baseline = {"config": {...}}
    modified = apply_changes(baseline)

    assert modified == snapshot(diff=baseline)

Important Constraints

  1. Python/pytest versions: Requires Python 3.10+ and pytest 8+
  2. Snapshot immutability: Never edit snapshot files manually
  3. Name uniqueness: Custom snapshot names must be unique per test
  4. Path separators: Use dots for nested paths in filters/matchers
  5. Zero dependencies: Syrupy has no external dependencies

Troubleshooting

Common Issues

  1. Snapshot not found: Run with --snapshot-update
  2. Unexpected differences: Check for non-deterministic data
  3. Large diffs: Use filters to focus on relevant data
  4. Flaky tests: Use matchers for dynamic values
  5. Merge conflicts: Update snapshots after resolving

Debug Options

  • Use --snapshot-details for verbose output
  • Check __snapshots__/ directory for actual files
  • Use exclude to isolate problematic fields
  • Test with smaller data sets first

Migration from Other Libraries

From pytest-snapshot

  • Similar API, minimal changes needed
  • Update import statements
  • Regenerate snapshots

From snapshottest

  • Change snapshot.assert_match() to assert x == snapshot
  • Update fixture name if customized
  • Regenerate all snapshots