or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-integration.mdcore-assertions.mdextensions.mdfilters.mdindex.mdmatchers.md

index.mddocs/

0

# Syrupy

1

2

A zero-dependency pytest snapshot testing library that enables developers to write tests asserting immutability of computed results. Syrupy provides an extensible and idiomatic approach to snapshot testing with the syntax `assert x == snapshot`, offering comprehensive filtering, matching, and custom serialization capabilities.

3

4

## Package Information

5

6

- **Package Name**: syrupy

7

- **Language**: Python

8

- **Installation**: `pip install syrupy`

9

- **Requirements**: Python >=3.8.1, pytest >=7.0.0,<9.0.0

10

11

## Core Imports

12

13

```python

14

import syrupy

15

```

16

17

Standard usage in tests:

18

19

```python

20

def test_example(snapshot):

21

assert result == snapshot

22

```

23

24

Extension imports:

25

26

```python

27

from syrupy.extensions.amber import AmberSnapshotExtension

28

from syrupy.extensions.json import JSONSnapshotExtension

29

from syrupy.extensions.image import PNGImageSnapshotExtension, SVGImageSnapshotExtension

30

from syrupy.extensions.single_file import SingleFileSnapshotExtension, SingleFileAmberSnapshotExtension, WriteMode

31

```

32

33

Matcher and filter imports:

34

35

```python

36

from syrupy.matchers import path_type, path_value, compose_matchers

37

from syrupy.filters import props, paths, paths_include

38

```

39

40

Exception imports:

41

42

```python

43

from syrupy.exceptions import SnapshotDoesNotExist, FailedToLoadModuleMember, TaintedSnapshotError

44

from syrupy.matchers import PathTypeError, StrictPathTypeError

45

```

46

47

## Basic Usage

48

49

```python

50

def test_basic_snapshot(snapshot):

51

"""Basic snapshot testing - creates .ambr file in __snapshots__ directory"""

52

actual = {"name": "Alice", "age": 30, "scores": [85, 92, 78]}

53

assert actual == snapshot

54

55

def test_with_index(snapshot):

56

"""Multiple snapshots in one test"""

57

assert "first result" == snapshot

58

assert "second result" == snapshot

59

60

def test_custom_extension(snapshot):

61

"""Using JSON extension for dictionary data"""

62

from syrupy.extensions.json import JSONSnapshotExtension

63

64

data = {"users": [{"id": 1, "name": "Alice"}]}

65

assert data == snapshot.use_extension(JSONSnapshotExtension)

66

67

def test_with_matchers(snapshot):

68

"""Using matchers to handle dynamic data"""

69

from syrupy.matchers import path_type

70

71

result = {

72

"timestamp": "2023-12-01T10:30:00Z", # Dynamic value

73

"user_id": 12345, # Dynamic value

74

"message": "Hello world" # Static value

75

}

76

77

# Replace dynamic values with placeholders

78

assert result == snapshot(matcher=path_type({

79

"timestamp": (str, "<timestamp>"),

80

"user_id": (int, "<user_id>")

81

}))

82

83

def test_with_filters(snapshot):

84

"""Using filters to include/exclude properties"""

85

from syrupy.filters import props

86

87

data = {

88

"public_field": "visible",

89

"private_field": "hidden",

90

"internal_field": "secret"

91

}

92

93

# Only include public fields

94

assert data == snapshot(include=props("public_field"))

95

```

96

97

## Architecture

98

99

Syrupy uses an extensible architecture built around several key components:

100

101

- **SnapshotAssertion**: Main assertion class providing fluent interface for configuration

102

- **Extensions**: Pluggable serialization and storage backends (Amber, JSON, PNG, SVG, etc.)

103

- **Matchers**: Value transformation system for handling dynamic data

104

- **Filters**: Property inclusion/exclusion system for controlling serialization scope

105

- **Session Management**: pytest integration handling snapshot lifecycle and reporting

106

107

The pytest plugin automatically registers hooks and provides the `snapshot` fixture, making snapshot testing seamlessly integrate with existing test suites.

108

109

## Capabilities

110

111

### Core Snapshot Assertions

112

113

Primary snapshot assertion functionality with fluent interface for configuration, including basic assertions, indexed snapshots, and method chaining for custom behavior.

114

115

```python { .api }

116

class SnapshotAssertion:

117

def __call__(self, *, matcher=None, include=None, exclude=None, extension_class=None): ...

118

def __eq__(self, other): ...

119

def use_extension(self, extension_class): ...

120

def with_defaults(self, **kwargs): ...

121

```

122

123

[Core Assertions](./core-assertions.md)

124

125

### Extensions System

126

127

Pluggable serialization and storage system supporting multiple output formats including Amber (default multi-snapshot), JSON, PNG, SVG, and raw file formats with extensible base classes.

128

129

```python { .api }

130

class AbstractSyrupyExtension: ...

131

class AmberSnapshotExtension(AbstractSyrupyExtension): ...

132

class JSONSnapshotExtension(AbstractSyrupyExtension): ...

133

class PNGImageSnapshotExtension(AbstractSyrupyExtension): ...

134

class SVGImageSnapshotExtension(AbstractSyrupyExtension): ...

135

```

136

137

[Extensions](./extensions.md)

138

139

### Matchers

140

141

Value transformation system for handling dynamic data in snapshots, providing path-based matching with type replacement and regex-based value substitution.

142

143

```python { .api }

144

def path_type(mapping: Dict[str, Tuple[type, Any]], *, strict: bool = True): ...

145

def path_value(mapping: Dict[str, Any]): ...

146

def compose_matchers(*matchers): ...

147

```

148

149

[Matchers](./matchers.md)

150

151

### Filters

152

153

Property inclusion and exclusion system for controlling serialization scope, supporting path-based and property-based filtering with nested path handling.

154

155

```python { .api }

156

def props(*included: str): ...

157

def paths(*included: str): ...

158

def paths_include(*nested_paths: str): ...

159

```

160

161

[Filters](./filters.md)

162

163

### CLI Integration

164

165

Command-line options and pytest integration providing snapshot update modes, reporting configuration, and extension selection.

166

167

```python { .api }

168

def pytest_addoption(parser): ...

169

@pytest.fixture

170

def snapshot(request): ...

171

```

172

173

[CLI Integration](./cli-integration.md)

174

175

## Types

176

177

```python { .api }

178

from typing import Union, Any, Callable, Tuple, Hashable, Type, List, Optional

179

import re

180

181

# Core types

182

SnapshotIndex = Union[int, str]

183

SerializableData = Any

184

SerializedData = Union[str, bytes]

185

186

# Property system types

187

PropertyName = Hashable

188

PropertyValueType = Type[SerializableData]

189

PropertyPathEntry = Tuple[PropertyName, PropertyValueType]

190

PropertyPath = Tuple[PropertyPathEntry, ...]

191

PropertyMatcher = Callable[[SerializableData, PropertyPath], Optional[SerializableData]]

192

PropertyFilter = Callable[[PropertyName, PropertyPath], bool]

193

194

# Matcher helper types

195

try:

196

MatchResult = Optional[re.Match[str]]

197

except TypeError:

198

MatchResult = Optional[re.Match]

199

Replacer = Callable[[SerializableData, MatchResult], SerializableData]

200

201

# Assertion result

202

@dataclass

203

class AssertionResult:

204

snapshot_location: str

205

snapshot_name: str

206

asserted_data: Optional[SerializedData]

207

recalled_data: Optional[SerializedData]

208

created: bool

209

updated: bool

210

success: bool

211

exception: Optional[Exception]

212

test_location: "PyTestLocation"

213

214

@property

215

def final_data(self) -> Optional[SerializedData]: ...

216

217

# Diff mode

218

class DiffMode(Enum):

219

DETAILED = "detailed"

220

DISABLED = "disabled"

221

```

222

223

## Exceptions

224

225

```python { .api }

226

class SnapshotDoesNotExist(Exception):

227

"""Raised when a snapshot file or entry doesn't exist"""

228

229

class FailedToLoadModuleMember(Exception):

230

"""Raised when unable to load a module member"""

231

232

class TaintedSnapshotError(Exception):

233

"""Raised when snapshot is corrupted and needs regeneration"""

234

235

class PathTypeError(TypeError):

236

"""Raised when path type matching encounters an error"""

237

238

class StrictPathTypeError(PathTypeError):

239

"""Raised when strict path type matching fails due to type mismatch"""

240

```