0
# Serialization and Plugins
1
2
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.
3
4
## Capabilities
5
6
### Plugin Management
7
8
Functions for managing snapshot serialization plugins that control how different types of values are converted to string representations.
9
10
```typescript { .api }
11
/**
12
* Adds a custom serializer plugin to the beginning of the plugin list
13
* Plugins added later take precedence over earlier ones
14
* @param plugin - PrettyFormat plugin for custom serialization
15
*/
16
function addSerializer(plugin: PrettyFormatPlugin): void;
17
18
/**
19
* Gets all registered serializer plugins in priority order
20
* @returns Array of all registered plugins, with custom plugins first
21
*/
22
function getSerializers(): PrettyFormatPlugins;
23
24
type PrettyFormatPlugin = {
25
test: (val: unknown) => boolean;
26
serialize: (
27
val: unknown,
28
config: Config,
29
indentation: string,
30
depth: number,
31
refs: Refs,
32
printer: Printer
33
) => string;
34
};
35
36
type PrettyFormatPlugins = Array<PrettyFormatPlugin>;
37
```
38
39
**Usage Examples:**
40
41
```typescript
42
import { addSerializer, getSerializers } from "jest-snapshot";
43
44
// Custom serializer for Date objects
45
const dateSerializer = {
46
test: (val) => val instanceof Date,
47
serialize: (val) => `Date("${val.toISOString()}")`
48
};
49
50
addSerializer(dateSerializer);
51
52
// Custom serializer for database models
53
const modelSerializer = {
54
test: (val) => val && typeof val === 'object' && val.constructor.name === 'User',
55
serialize: (val, config, indentation, depth, refs, printer) => {
56
return `User(${printer(val.id, config, indentation, depth, refs)})`;
57
}
58
};
59
60
addSerializer(modelSerializer);
61
62
// Get all serializers (custom ones first)
63
const allSerializers = getSerializers();
64
console.log(allSerializers.length); // Built-in + custom serializers
65
```
66
67
### Built-in Serializers
68
69
Jest Snapshot includes several built-in serializers that handle common data types:
70
71
**React Components:**
72
- `ReactElement` - Serializes React elements and JSX
73
- `ReactTestComponent` - Handles React test renderer components
74
75
**DOM Elements:**
76
- `DOMElement` - Serializes DOM nodes and HTML elements
77
- `DOMCollection` - Handles NodeLists, HTMLCollections, etc.
78
79
**Data Structures:**
80
- `Immutable` - Serializes Immutable.js data structures
81
- `AsymmetricMatcher` - Handles Jest's `expect.any()`, `expect.objectContaining()`, etc.
82
83
**Jest Specific:**
84
- `jestMockSerializer` - Serializes Jest mock functions with call information
85
86
### Custom Serializer Implementation
87
88
Create custom serializers for domain-specific objects or to customize existing type serialization:
89
90
```typescript
91
// Custom serializer for URL objects
92
const urlSerializer = {
93
test: (val) => val instanceof URL,
94
serialize: (val) => `URL("${val.href}")`
95
};
96
97
addSerializer(urlSerializer);
98
99
// Before: URL { href: "https://example.com", protocol: "https:", ... }
100
// After: URL("https://example.com")
101
102
// Custom serializer for Error objects with stack traces
103
const errorSerializer = {
104
test: (val) => val instanceof Error,
105
serialize: (val, config, indentation, depth, refs, printer) => {
106
const name = val.constructor.name;
107
const message = val.message;
108
const stack = val.stack ? `\n${val.stack}` : '';
109
return `${name}: ${message}${stack}`;
110
}
111
};
112
113
addSerializer(errorSerializer);
114
115
// Complex custom serializer with nested printing
116
const apiResponseSerializer = {
117
test: (val) => val && typeof val === 'object' && val.type === 'api-response',
118
serialize: (val, config, indentation, depth, refs, printer) => {
119
const status = val.status;
120
const data = printer(val.data, config, indentation, depth, refs);
121
return `ApiResponse(${status}) ${data}`;
122
}
123
};
124
125
addSerializer(apiResponseSerializer);
126
```
127
128
### Serializer Priority
129
130
Serializers are tested in order, with the first matching serializer being used:
131
132
```typescript
133
// Order matters - first matching test() wins
134
addSerializer(specificSerializer); // Added last, tested first
135
addSerializer(generalSerializer); // Added earlier, tested later
136
137
// Built-in serializers are tested after all custom serializers
138
// Default object/primitive serialization happens last
139
```
140
141
### Serializer Testing
142
143
Serializers include a `test` function that determines whether they should handle a specific value:
144
145
```typescript
146
const customSerializer = {
147
// Test function - return true to handle this value
148
test: (val) => {
149
return val &&
150
typeof val === 'object' &&
151
val.constructor.name === 'CustomClass' &&
152
typeof val.serialize === 'function';
153
},
154
155
// Serialize function - convert value to string
156
serialize: (val, config, indentation, depth, refs, printer) => {
157
// Use the object's own serialize method
158
return val.serialize();
159
}
160
};
161
```
162
163
### Advanced Serialization Features
164
165
**Nested Object Printing**: Use the `printer` function to serialize nested values:
166
167
```typescript
168
const wrapperSerializer = {
169
test: (val) => val && val.type === 'wrapper',
170
serialize: (val, config, indentation, depth, refs, printer) => {
171
// Use printer for nested values to maintain formatting
172
const content = printer(val.content, config, indentation, depth, refs);
173
return `Wrapper(${content})`;
174
}
175
};
176
```
177
178
**Depth and Reference Handling**: Handle circular references and depth limits:
179
180
```typescript
181
const circularSafeSerializer = {
182
test: (val) => val && val.type === 'node',
183
serialize: (val, config, indentation, depth, refs, printer) => {
184
if (depth > 5) {
185
return '[Deep Object]';
186
}
187
188
const children = val.children.map(child =>
189
printer(child, config, indentation, depth + 1, refs)
190
);
191
192
return `Node(${children.join(', ')})`;
193
}
194
};
195
```
196
197
**Configuration-aware Serialization**: Access pretty-format configuration:
198
199
```typescript
200
const configAwareSerializer = {
201
test: (val) => val instanceof Map,
202
serialize: (val, config, indentation, depth, refs, printer) => {
203
const entries = Array.from(val.entries());
204
205
if (config.min) {
206
// Compact format for min config
207
return `Map(${entries.length})`;
208
}
209
210
// Full format
211
const items = entries.map(([key, value]) => {
212
const k = printer(key, config, indentation, depth, refs);
213
const v = printer(value, config, indentation, depth, refs);
214
return `${k} => ${v}`;
215
});
216
217
return `Map {\n${indentation} ${items.join(`,\n${indentation} `)}\n${indentation}}`;
218
}
219
};
220
```
221
222
### Serializer Removal
223
224
There's currently no built-in way to remove serializers, but you can work around this:
225
226
```typescript
227
// Get current serializers
228
const currentSerializers = getSerializers();
229
230
// Find built-in serializers (after your custom ones)
231
const builtInSerializers = currentSerializers.slice(customSerializerCount);
232
233
// Clear and re-add only desired serializers
234
// (This is a workaround - not officially supported)
235
```
236
237
### Integration with Snapshot Formatting
238
239
Serializers work with Jest's snapshot formatting options:
240
241
```typescript
242
// Snapshot format affects serializer output
243
const snapshotFormat = {
244
indent: 2,
245
printWidth: 80,
246
min: false,
247
escapeRegex: false,
248
escapeString: true,
249
plugins: getSerializers() // Your custom serializers included
250
};
251
```
252
253
## Types
254
255
```typescript { .api }
256
interface PrettyFormatPlugin {
257
test: (val: unknown) => boolean;
258
serialize: (
259
val: unknown,
260
config: Config,
261
indentation: string,
262
depth: number,
263
refs: Refs,
264
printer: Printer
265
) => string;
266
}
267
268
type PrettyFormatPlugins = Array<PrettyFormatPlugin>;
269
270
type Config = {
271
callToJSON: boolean;
272
compareKeys: undefined;
273
escapeRegex: boolean;
274
escapeString: boolean;
275
highlight: boolean;
276
indent: string;
277
maxDepth: number;
278
min: boolean;
279
plugins: PrettyFormatPlugins;
280
printBasicPrototype: boolean;
281
printFunctionName: boolean;
282
spacingInner: string;
283
spacingOuter: string;
284
theme: Theme;
285
};
286
287
type Printer = (
288
val: unknown,
289
config: Config,
290
indentation: string,
291
depth: number,
292
refs: Refs
293
) => string;
294
295
type Refs = Set<unknown>;
296
297
interface Theme {
298
comment: string;
299
content: string;
300
prop: string;
301
tag: string;
302
value: string;
303
}
304
```