Skip to content

Commit a424896

Browse files
authored
Document and test custom, async, inline snapshot matcher (#10922)
1 parent b0bf802 commit a424896

File tree

6 files changed

+228
-0
lines changed

6 files changed

+228
-0
lines changed

docs/ExpectAPI.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,41 @@ it('stores only 10 characters', () => {
255255
});
256256
```
257257

258+
#### async
259+
260+
If your custom inline snapshot matcher is async i.e. uses `async`-`await` you might encounter an error like "Multiple inline snapshots for the same call are not supported". Jest needs additional context information to find where the custom inline snapshot matcher was used to update the snapshots properly.
261+
262+
```js
263+
const {toMatchInlineSnapshot} = require('jest-snapshot');
264+
265+
expect.extend({
266+
async toMatchObservationInlineSnapshot(fn, ...rest) {
267+
// The error (and its stacktrace) must be created before any `await`
268+
this.error = new Error();
269+
270+
// The implementation of `observe` doesn't matter.
271+
// It only matters that the custom snapshot matcher is async.
272+
const observation = await observe(async () => {
273+
await fn();
274+
});
275+
276+
return toMatchInlineSnapshot.call(this, recording, ...rest);
277+
},
278+
});
279+
280+
it('observes something', async () => {
281+
await expect(async () => {
282+
return 'async action';
283+
}).toMatchTrimmedInlineSnapshot();
284+
/*
285+
The snapshot will be added inline like
286+
await expect(async () => {
287+
return 'async action';
288+
}).toMatchTrimmedInlineSnapshot(`"async action"`);
289+
*/
290+
});
291+
```
292+
258293
### `expect.anything()`
259294

260295
`expect.anything()` matches anything but `null` or `undefined`. You can use it inside `toEqual` or `toBeCalledWith` instead of a literal value. For example, if you want to check that a mock function is called with a non-null argument:
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`works with custom inline snapshot matchers 1`] = `
4+
FAIL __tests__/asynchronous.test.js
5+
✕ new async, inline snapshots
6+
✕ mismatching async, inline snapshots
7+
8+
● new async, inline snapshots
9+
10+
expect(received).toMatchInlineSnapshot()
11+
12+
Snapshot name: \`new async, inline snapshots 1\`
13+
14+
New snapshot was not written. The update flag must be explicitly passed to write a new snapshot.
15+
16+
This is likely because this test is run in a continuous integration (CI) environment in which snapshots are not written by default.
17+
18+
Received: "result #1"
19+
20+
20 |
21+
21 | test('new async, inline snapshots', async () => {
22+
> 22 | await expect(async () => 'result #1').toMatchObservationInlineSnapshot();
23+
| ^
24+
23 | await expect(async () => 'result #2').toMatchObservationInlineSnapshot();
25+
24 | });
26+
25 |
27+
28+
at Object.toMatchObservationInlineSnapshot (__tests__/asynchronous.test.js:22:41)
29+
30+
● new async, inline snapshots
31+
32+
expect(received).toMatchInlineSnapshot()
33+
34+
Snapshot name: \`new async, inline snapshots 2\`
35+
36+
New snapshot was not written. The update flag must be explicitly passed to write a new snapshot.
37+
38+
This is likely because this test is run in a continuous integration (CI) environment in which snapshots are not written by default.
39+
40+
Received: "result #2"
41+
42+
21 | test('new async, inline snapshots', async () => {
43+
22 | await expect(async () => 'result #1').toMatchObservationInlineSnapshot();
44+
> 23 | await expect(async () => 'result #2').toMatchObservationInlineSnapshot();
45+
| ^
46+
24 | });
47+
25 |
48+
26 | test('mismatching async, inline snapshots', async () => {
49+
50+
at Object.toMatchObservationInlineSnapshot (__tests__/asynchronous.test.js:23:41)
51+
52+
mismatching async, inline snapshots
53+
54+
expect(received).toMatchInlineSnapshot(snapshot)
55+
56+
Snapshot name: \`mismatching async, inline snapshots 1\`
57+
58+
Snapshot: "result #?"
59+
Received: "result #1"
60+
61+
25 |
62+
26 | test('mismatching async, inline snapshots', async () => {
63+
> 27 | await expect(async () => 'result #1').toMatchObservationInlineSnapshot(
64+
| ^
65+
28 | \`"result #?"\`,
66+
29 | );
67+
30 | await expect(async () => 'result #2').toMatchObservationInlineSnapshot(
68+
69+
at Object.toMatchObservationInlineSnapshot (__tests__/asynchronous.test.js:27:41)
70+
71+
● mismatching async, inline snapshots
72+
73+
expect(received).toMatchInlineSnapshot(snapshot)
74+
75+
Snapshot name: \`mismatching async, inline snapshots 2\`
76+
77+
Snapshot: "result #?"
78+
Received: "result #2"
79+
80+
28 | \`"result #?"\`,
81+
29 | );
82+
> 30 | await expect(async () => 'result #2').toMatchObservationInlineSnapshot(
83+
| ^
84+
31 | \`"result #?"\`,
85+
32 | );
86+
33 | });
87+
88+
at Object.toMatchObservationInlineSnapshot (__tests__/asynchronous.test.js:30:41)
89+
90+
› 4 snapshots failed.
91+
Snapshot Summary
92+
› 4 snapshots failed from 1 test suite. Inspect your code changes or re-run jest with \`-u\` to update them.
93+
`;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import {wrap} from 'jest-snapshot-serializer-raw';
9+
import {extractSummary} from '../Utils';
10+
import runJest from '../runJest';
11+
12+
test('works with custom inline snapshot matchers', () => {
13+
const {stderr} = runJest('custom-inline-snapshot-matchers', [
14+
// Prevent adding new snapshots or rather changing the test.
15+
'--ci',
16+
'asynchronous.test.js',
17+
]);
18+
19+
let {rest} = extractSummary(stderr);
20+
21+
rest = rest
22+
.split('\n')
23+
.filter(line => line.indexOf('at Error (native)') < 0)
24+
.join('\n');
25+
26+
expect(wrap(rest)).toMatchSnapshot();
27+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
const {toMatchInlineSnapshot} = require('jest-snapshot');
8+
9+
expect.extend({
10+
async toMatchObservationInlineSnapshot(fn, ...args) {
11+
this.error = new Error();
12+
// This specific behavior can be implemented without a custom matcher.
13+
// In a real example one might want to observe some global value that `fn()` is affecting.
14+
// The difference between before and after `fn()` might then be persisted as a snapshot.
15+
const result = await fn();
16+
17+
return toMatchInlineSnapshot.call(this, result, ...args);
18+
},
19+
});
20+
21+
test('new async, inline snapshots', async () => {
22+
await expect(async () => 'result #1').toMatchObservationInlineSnapshot();
23+
await expect(async () => 'result #2').toMatchObservationInlineSnapshot();
24+
});
25+
26+
test('mismatching async, inline snapshots', async () => {
27+
await expect(async () => 'result #1').toMatchObservationInlineSnapshot(
28+
`"result #?"`,
29+
);
30+
await expect(async () => 'result #2').toMatchObservationInlineSnapshot(
31+
`"result #?"`,
32+
);
33+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"jest": {
3+
"testEnvironment": "node"
4+
}
5+
}

website/versioned_docs/version-25.x/ExpectAPI.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,41 @@ it('stores only 10 characters', () => {
256256
});
257257
```
258258

259+
#### async
260+
261+
If your custom inline snapshot matcher is async i.e. uses `async`-`await` you might encounter an error like "Multiple inline snapshots for the same call are not supported". Jest needs additional context information to find where the custom inline snapshot matcher was used to update the snapshots properly.
262+
263+
```js
264+
const {toMatchInlineSnapshot} = require('jest-snapshot');
265+
266+
expect.extend({
267+
async toMatchObservationInlineSnapshot(fn, ...rest) {
268+
// The error (and its stacktrace) must be created before any `await`
269+
this.error = new Error();
270+
271+
// The implementation of `observe` doesn't matter.
272+
// It only matters that the custom snapshot matcher is async.
273+
const observation = await observe(async () => {
274+
await fn();
275+
});
276+
277+
return toMatchInlineSnapshot.call(this, recording, ...rest);
278+
},
279+
});
280+
281+
it('observes something', async () => {
282+
await expect(async () => {
283+
return 'async action';
284+
}).toMatchTrimmedInlineSnapshot();
285+
/*
286+
The snapshot will be added inline like
287+
await expect(async () => {
288+
return 'async action';
289+
}).toMatchTrimmedInlineSnapshot(`"async action"`);
290+
*/
291+
});
292+
```
293+
259294
### `expect.anything()`
260295

261296
`expect.anything()` matches anything but `null` or `undefined`. You can use it inside `toEqual` or `toBeCalledWith` instead of a literal value. For example, if you want to check that a mock function is called with a non-null argument:

0 commit comments

Comments
 (0)