10
10
import type { Path , SnapshotUpdateState } from 'types/Config' ;
11
11
12
12
import fs from 'fs' ;
13
+ import { getTopFrame } from 'jest-message-util' ;
13
14
import {
14
15
saveSnapshotFile ,
16
+ saveInlineSnapshots ,
15
17
getSnapshotData ,
16
18
getSnapshotPath ,
17
19
keyToTestName ,
18
20
serialize ,
19
21
testNameToKey ,
20
22
unescape ,
23
+ type InlineSnapshot ,
21
24
} from './utils' ;
22
25
23
26
export type SnapshotStateOptions = { |
@@ -33,6 +36,8 @@ export default class SnapshotState {
33
36
_updateSnapshot: SnapshotUpdateState ;
34
37
_snapshotData: { [ key : string ] : string } ;
35
38
_snapshotPath: Path ;
39
+ _inlineSnapshotData: { [ key : string ] : InlineSnapshot } ;
40
+ _testPath: Path ;
36
41
_uncheckedKeys: Set < string > ;
37
42
added: number ;
38
43
expand: boolean ;
@@ -42,12 +47,14 @@ export default class SnapshotState {
42
47
43
48
constructor ( testPath : Path , options : SnapshotStateOptions ) {
44
49
this . _snapshotPath = options . snapshotPath || getSnapshotPath ( testPath ) ;
50
+ this . _testPath = testPath ;
45
51
const { data, dirty} = getSnapshotData (
46
52
this . _snapshotPath ,
47
53
options . updateSnapshot ,
48
54
) ;
49
55
this . _snapshotData = data ;
50
56
this . _dirty = dirty ;
57
+ this . _inlineSnapshotData = Object . create ( null ) ;
51
58
this . _uncheckedKeys = new Set ( Object . keys ( this . _snapshotData ) ) ;
52
59
this . _counters = new Map ( ) ;
53
60
this . _index = 0 ;
@@ -67,22 +74,42 @@ export default class SnapshotState {
67
74
} ) ;
68
75
}
69
76
70
- _addSnapshot ( key : string , receivedSerialized : string ) {
77
+ _addSnapshot ( key : string , receivedSerialized : string , isInline : boolean ) {
71
78
this . _dirty = true ;
72
- this . _snapshotData [ key ] = receivedSerialized ;
79
+ if ( isInline ) {
80
+ const stack = new Error ( ) . stack . split ( / \n / ) ;
81
+ const frame = getTopFrame ( stack ) ;
82
+ if ( ! frame ) {
83
+ throw new Error ( "Jest: Couln't infer stack frame for inline snapshot." ) ;
84
+ }
85
+ this . _inlineSnapshotData [ key ] = {
86
+ frame,
87
+ snapshot : receivedSerialized ,
88
+ } ;
89
+ } else {
90
+ this . _snapshotData [ key ] = receivedSerialized ;
91
+ }
73
92
}
74
93
75
94
save ( ) {
76
- const isEmpty = Object . keys ( this . _snapshotData ) . length === 0 ;
95
+ const hasExternalSnapshots = Object . keys ( this . _snapshotData ) . length ;
96
+ const hasInlineSnapshots = Object . keys ( this . _inlineSnapshotData ) . length ;
97
+ const isEmpty = ! hasExternalSnapshots && ! hasInlineSnapshots ;
98
+
77
99
const status = {
78
100
deleted : false ,
79
101
saved : false ,
80
102
} ;
81
103
82
104
if ( ( this . _dirty || this . _uncheckedKeys . size ) && ! isEmpty ) {
83
- saveSnapshotFile ( this . _snapshotData , this . _snapshotPath ) ;
105
+ if ( hasExternalSnapshots ) {
106
+ saveSnapshotFile ( this . _snapshotData , this . _snapshotPath ) ;
107
+ }
108
+ if ( hasInlineSnapshots ) {
109
+ saveInlineSnapshots ( this . _inlineSnapshotData , this . _testPath ) ;
110
+ }
84
111
status . saved = true ;
85
- } else if ( isEmpty && fs . existsSync ( this . _snapshotPath ) ) {
112
+ } else if ( ! hasExternalSnapshots && fs . existsSync ( this . _snapshotPath ) ) {
86
113
if ( this . _updateSnapshot === 'all' ) {
87
114
fs . unlinkSync ( this . _snapshotPath ) ;
88
115
}
@@ -108,9 +135,15 @@ export default class SnapshotState {
108
135
}
109
136
}
110
137
111
- match ( testName : string , received : any , key ? : string ) {
138
+ match (
139
+ testName : string ,
140
+ received : any ,
141
+ key ? : string ,
142
+ inlineSnapshot ? : string ,
143
+ ) {
112
144
this . _counters . set ( testName , ( this . _counters . get ( testName ) || 0 ) + 1 ) ;
113
145
const count = Number ( this . _counters . get ( testName ) ) ;
146
+ const isInline = typeof inlineSnapshot === 'string' ;
114
147
115
148
if ( ! key ) {
116
149
key = testNameToKey ( testName , count ) ;
@@ -119,11 +152,13 @@ export default class SnapshotState {
119
152
this . _uncheckedKeys . delete ( key ) ;
120
153
121
154
const receivedSerialized = serialize ( received ) ;
122
- const expected = this . _snapshotData [ key ] ;
155
+ const expected = isInline ? inlineSnapshot : this . _snapshotData [ key ] ;
123
156
const pass = expected === receivedSerialized ;
124
- const hasSnapshot = this . _snapshotData [ key ] !== undefined ;
157
+ const hasSnapshot = isInline
158
+ ? inlineSnapshot !== ''
159
+ : this . _snapshotData [ key ] !== undefined ;
125
160
126
- if ( pass ) {
161
+ if ( pass && ! isInline ) {
127
162
// Executing a snapshot file as JavaScript and writing the strings back
128
163
// when other snapshots have changed loses the proper escaping for some
129
164
// characters. Since we check every snapshot in every test, use the newly
@@ -142,7 +177,7 @@ export default class SnapshotState {
142
177
// * There's no snapshot file or a file without this snapshot on a CI environment.
143
178
if (
144
179
( hasSnapshot && this . _updateSnapshot === 'all' ) ||
145
- ( ( ! hasSnapshot || ! fs . existsSync ( this . _snapshotPath ) ) &&
180
+ ( ( ! hasSnapshot || ( ! isInline && ! fs . existsSync ( this . _snapshotPath ) ) ) &&
146
181
( this . _updateSnapshot === 'new' || this . _updateSnapshot === 'all' ) )
147
182
) {
148
183
if ( this . _updateSnapshot === 'all' ) {
@@ -152,12 +187,12 @@ export default class SnapshotState {
152
187
} else {
153
188
this . added ++ ;
154
189
}
155
- this . _addSnapshot ( key , receivedSerialized ) ;
190
+ this . _addSnapshot ( key , receivedSerialized , isInline ) ;
156
191
} else {
157
192
this . matched ++ ;
158
193
}
159
194
} else {
160
- this . _addSnapshot ( key , receivedSerialized ) ;
195
+ this . _addSnapshot ( key , receivedSerialized , isInline ) ;
161
196
this . added ++ ;
162
197
}
163
198
0 commit comments