0
# Jest Integration API
1
2
Native Jest snapshot testing support with functions to convert VNodes and rendered components to Jest-compatible snapshots. These utilities enable seamless integration with Jest's snapshot testing capabilities for Inferno applications.
3
4
## Snapshot Functions
5
6
### vNodeToSnapshot
7
8
```javascript { .api }
9
/**
10
* Converts a VNode to a Jest-compatible snapshot object
11
* @param vNode - VNode to convert to snapshot
12
* @returns InfernoSnapshot object compatible with Jest snapshots
13
*/
14
function vNodeToSnapshot(vNode: VNode): InfernoSnapshot
15
```
16
17
This function converts individual VNodes into the snapshot format that Jest expects, making them suitable for snapshot testing.
18
19
```javascript
20
import { vNodeToSnapshot } from 'inferno-test-utils';
21
import { createElement } from 'inferno-create-element';
22
23
// Simple DOM element snapshot
24
const simpleVNode = <div className="test">Hello World</div>;
25
const snapshot = vNodeToSnapshot(simpleVNode);
26
27
console.log(snapshot);
28
// {
29
// type: "div",
30
// props: { className: "test" },
31
// children: ["Hello World"],
32
// $$typeof: Symbol(react.test.json)
33
// }
34
35
// Complex nested structure
36
const complexVNode = (
37
<div className="container">
38
<h1>Title</h1>
39
<p>Description</p>
40
<button disabled>Action</button>
41
</div>
42
);
43
44
const complexSnapshot = vNodeToSnapshot(complexVNode);
45
console.log(complexSnapshot);
46
// {
47
// type: "div",
48
// props: { className: "container" },
49
// children: [
50
// { type: "h1", props: {}, children: ["Title"] },
51
// { type: "p", props: {}, children: ["Description"] },
52
// { type: "button", props: { disabled: true }, children: ["Action"] }
53
// ],
54
// $$typeof: Symbol(react.test.json)
55
// }
56
```
57
58
### renderToSnapshot
59
60
```javascript { .api }
61
/**
62
* Renders a VNode and converts it to a Jest-compatible snapshot
63
* @param input - VNode to render and convert to snapshot
64
* @returns InfernoSnapshot object suitable for Jest snapshot testing
65
*/
66
function renderToSnapshot(input: VNode): InfernoSnapshot
67
```
68
69
This function combines rendering and snapshot conversion in one step, handling the full render lifecycle including state updates and component lifecycle methods.
70
71
```javascript
72
import { renderToSnapshot } from 'inferno-test-utils';
73
import { Component } from 'inferno';
74
75
// Simple component snapshot
76
function SimpleComponent({ name }) {
77
return <div className="greeting">Hello {name}!</div>;
78
}
79
80
const simpleSnapshot = renderToSnapshot(<SimpleComponent name="World" />);
81
console.log(simpleSnapshot);
82
// {
83
// type: "div",
84
// props: { className: "greeting" },
85
// children: ["Hello World!"],
86
// $$typeof: Symbol(react.test.json)
87
// }
88
89
// Class component with state
90
class StatefulComponent extends Component {
91
constructor(props) {
92
super(props);
93
this.state = { count: props.initialCount || 0 };
94
}
95
96
render() {
97
return (
98
<div className="counter">
99
<span>Count: {this.state.count}</span>
100
<button>Increment</button>
101
</div>
102
);
103
}
104
}
105
106
const statefulSnapshot = renderToSnapshot(<StatefulComponent initialCount={5} />);
107
console.log(statefulSnapshot);
108
// {
109
// type: "div",
110
// props: { className: "counter" },
111
// children: [
112
// { type: "span", props: {}, children: ["Count: 5"] },
113
// { type: "button", props: {}, children: ["Increment"] }
114
// ],
115
// $$typeof: Symbol(react.test.json)
116
// }
117
```
118
119
## Jest Integration Patterns
120
121
### Basic Snapshot Testing
122
123
```javascript
124
import { renderToSnapshot } from 'inferno-test-utils';
125
import { Component } from 'inferno';
126
127
// Component to test
128
class WelcomeMessage extends Component {
129
render() {
130
const { name, role } = this.props;
131
return (
132
<div className="welcome">
133
<h2>Welcome, {name}!</h2>
134
{role && <p className="role">Role: {role}</p>}
135
<button className="btn-primary">Get Started</button>
136
</div>
137
);
138
}
139
}
140
141
// Jest test
142
describe('WelcomeMessage', () => {
143
it('renders correctly with name only', () => {
144
const snapshot = renderToSnapshot(<WelcomeMessage name="John" />);
145
expect(snapshot).toMatchSnapshot();
146
});
147
148
it('renders correctly with name and role', () => {
149
const snapshot = renderToSnapshot(<WelcomeMessage name="Jane" role="Admin" />);
150
expect(snapshot).toMatchSnapshot();
151
});
152
});
153
```
154
155
### Component State Snapshots
156
157
```javascript
158
import { renderToSnapshot, renderIntoContainer } from 'inferno-test-utils';
159
import { Component } from 'inferno';
160
161
class ToggleComponent extends Component {
162
constructor(props) {
163
super(props);
164
this.state = { isOpen: false };
165
}
166
167
toggle = () => {
168
this.setState({ isOpen: !this.state.isOpen });
169
}
170
171
render() {
172
return (
173
<div className="toggle">
174
<button onClick={this.toggle}>
175
{this.state.isOpen ? 'Close' : 'Open'}
176
</button>
177
{this.state.isOpen && (
178
<div className="content">
179
<p>Toggle content is visible</p>
180
</div>
181
)}
182
</div>
183
);
184
}
185
}
186
187
describe('ToggleComponent', () => {
188
it('renders correctly in closed state', () => {
189
const snapshot = renderToSnapshot(<ToggleComponent />);
190
expect(snapshot).toMatchSnapshot();
191
});
192
193
it('renders correctly in open state', () => {
194
// Render component to access instance
195
const rendered = renderIntoContainer(<ToggleComponent />);
196
197
// Change state
198
rendered.toggle();
199
200
// Create snapshot of updated state
201
const snapshot = vNodeToSnapshot(rendered.$LI); // Access VNode from instance
202
expect(snapshot).toMatchSnapshot();
203
});
204
});
205
```
206
207
### Complex Component Hierarchies
208
209
```javascript
210
import { renderToSnapshot } from 'inferno-test-utils';
211
import { Component } from 'inferno';
212
213
// Child components
214
function UserAvatar({ user }) {
215
return (
216
<div className="avatar">
217
<img src={user.avatar} alt={user.name} />
218
<span className="status" data-status={user.status}></span>
219
</div>
220
);
221
}
222
223
function UserInfo({ user }) {
224
return (
225
<div className="user-info">
226
<h3>{user.name}</h3>
227
<p>{user.email}</p>
228
<span className="role">{user.role}</span>
229
</div>
230
);
231
}
232
233
// Parent component
234
class UserCard extends Component {
235
render() {
236
const { user, showActions } = this.props;
237
238
return (
239
<div className="user-card">
240
<UserAvatar user={user} />
241
<UserInfo user={user} />
242
{showActions && (
243
<div className="actions">
244
<button className="btn-edit">Edit</button>
245
<button className="btn-delete">Delete</button>
246
</div>
247
)}
248
</div>
249
);
250
}
251
}
252
253
describe('UserCard', () => {
254
const mockUser = {
255
name: 'John Doe',
256
email: 'john@example.com',
257
role: 'Developer',
258
status: 'online',
259
avatar: 'avatar.jpg'
260
};
261
262
it('renders user card without actions', () => {
263
const snapshot = renderToSnapshot(
264
<UserCard user={mockUser} showActions={false} />
265
);
266
expect(snapshot).toMatchSnapshot();
267
});
268
269
it('renders user card with actions', () => {
270
const snapshot = renderToSnapshot(
271
<UserCard user={mockUser} showActions={true} />
272
);
273
expect(snapshot).toMatchSnapshot();
274
});
275
});
276
```
277
278
### Conditional Rendering Snapshots
279
280
```javascript
281
import { renderToSnapshot } from 'inferno-test-utils';
282
283
function LoadingComponent({ isLoading, data, error }) {
284
if (error) {
285
return (
286
<div className="error">
287
<h3>Error occurred</h3>
288
<p>{error.message}</p>
289
<button>Retry</button>
290
</div>
291
);
292
}
293
294
if (isLoading) {
295
return (
296
<div className="loading">
297
<div className="spinner"></div>
298
<p>Loading...</p>
299
</div>
300
);
301
}
302
303
return (
304
<div className="data">
305
<h3>Data loaded</h3>
306
<ul>
307
{data.map(item => (
308
<li key={item.id}>{item.name}</li>
309
))}
310
</ul>
311
</div>
312
);
313
}
314
315
describe('LoadingComponent', () => {
316
it('renders loading state', () => {
317
const snapshot = renderToSnapshot(
318
<LoadingComponent isLoading={true} data={null} error={null} />
319
);
320
expect(snapshot).toMatchSnapshot();
321
});
322
323
it('renders error state', () => {
324
const error = { message: 'Failed to load data' };
325
const snapshot = renderToSnapshot(
326
<LoadingComponent isLoading={false} data={null} error={error} />
327
);
328
expect(snapshot).toMatchSnapshot();
329
});
330
331
it('renders data state', () => {
332
const data = [
333
{ id: 1, name: 'Item 1' },
334
{ id: 2, name: 'Item 2' }
335
];
336
const snapshot = renderToSnapshot(
337
<LoadingComponent isLoading={false} data={data} error={null} />
338
);
339
expect(snapshot).toMatchSnapshot();
340
});
341
});
342
```
343
344
## Types and Interfaces
345
346
### InfernoSnapshot
347
348
```typescript { .api }
349
interface InfernoSnapshot {
350
type: string;
351
props: Record<string, any>;
352
children: null | InfernoTestRendererNode[];
353
$$typeof?: symbol | string;
354
}
355
356
type InfernoTestRendererNode = InfernoSnapshot | string;
357
```
358
359
The InfernoSnapshot interface represents the structure of snapshot objects created by the testing utilities:
360
361
- **type**: The HTML tag name or component name as a string
362
- **props**: All props passed to the element/component (excludes children)
363
- **children**: Array of child snapshots or text content, null if no children
364
- **$$typeof**: React test renderer compatibility symbol
365
366
```javascript
367
import { vNodeToSnapshot } from 'inferno-test-utils';
368
369
const vnode = (
370
<div className="example" id="test">
371
<span>Text content</span>
372
<button disabled>Click me</button>
373
</div>
374
);
375
376
const snapshot = vNodeToSnapshot(vnode);
377
// Type: InfernoSnapshot
378
// {
379
// type: "div",
380
// props: { className: "example", id: "test" },
381
// children: [
382
// { type: "span", props: {}, children: ["Text content"] },
383
// { type: "button", props: { disabled: true }, children: ["Click me"] }
384
// ],
385
// $$typeof: Symbol(react.test.json)
386
// }
387
```
388
389
## Snapshot Testing Best Practices
390
391
### Testing Props Variations
392
393
```javascript
394
import { renderToSnapshot } from 'inferno-test-utils';
395
396
function Button({ variant, size, disabled, children }) {
397
const className = `btn btn-${variant} btn-${size}`;
398
return (
399
<button className={className} disabled={disabled}>
400
{children}
401
</button>
402
);
403
}
404
405
describe('Button component', () => {
406
const testCases = [
407
{ variant: 'primary', size: 'large', disabled: false },
408
{ variant: 'secondary', size: 'medium', disabled: false },
409
{ variant: 'danger', size: 'small', disabled: true }
410
];
411
412
testCases.forEach(({ variant, size, disabled }) => {
413
it(`renders ${variant} ${size} button (disabled: ${disabled})`, () => {
414
const snapshot = renderToSnapshot(
415
<Button variant={variant} size={size} disabled={disabled}>
416
Test Button
417
</Button>
418
);
419
expect(snapshot).toMatchSnapshot();
420
});
421
});
422
});
423
```
424
425
### Testing with Mock Data
426
427
```javascript
428
import { renderToSnapshot } from 'inferno-test-utils';
429
430
function ProductList({ products }) {
431
return (
432
<div className="product-list">
433
{products.map(product => (
434
<div key={product.id} className="product-item">
435
<h3>{product.name}</h3>
436
<p className="price">${product.price}</p>
437
<p className="description">{product.description}</p>
438
</div>
439
))}
440
</div>
441
);
442
}
443
444
describe('ProductList', () => {
445
it('renders empty list', () => {
446
const snapshot = renderToSnapshot(<ProductList products={[]} />);
447
expect(snapshot).toMatchSnapshot();
448
});
449
450
it('renders multiple products', () => {
451
const mockProducts = [
452
{ id: 1, name: 'Product 1', price: 10.99, description: 'Description 1' },
453
{ id: 2, name: 'Product 2', price: 15.99, description: 'Description 2' }
454
];
455
456
const snapshot = renderToSnapshot(<ProductList products={mockProducts} />);
457
expect(snapshot).toMatchSnapshot();
458
});
459
});
460
```
461
462
The Jest integration utilities ensure that your Inferno components can be tested with the same snapshot testing workflow as React components, providing consistency across different component libraries.