1010import type { Path , SnapshotUpdateState } from 'types/Config' ;
1111
1212import fs from 'fs' ;
13+ import { getTopFrame } from 'jest-message-util' ;
1314import {
1415 saveSnapshotFile ,
16+ saveInlineSnapshots ,
1517 getSnapshotData ,
1618 getSnapshotPath ,
1719 keyToTestName ,
1820 serialize ,
1921 testNameToKey ,
2022 unescape ,
23+ type InlineSnapshot ,
2124} from './utils' ;
2225
2326export type SnapshotStateOptions = { |
@@ -33,6 +36,8 @@ export default class SnapshotState {
3336 _updateSnapshot: SnapshotUpdateState ;
3437 _snapshotData: { [ key : string ] : string } ;
3538 _snapshotPath: Path ;
39+ _inlineSnapshotData: { [ key : string ] : InlineSnapshot } ;
40+ _testPath: Path ;
3641 _uncheckedKeys: Set < string > ;
3742 added: number ;
3843 expand: boolean ;
@@ -42,12 +47,14 @@ export default class SnapshotState {
4247
4348 constructor ( testPath : Path , options : SnapshotStateOptions ) {
4449 this . _snapshotPath = options . snapshotPath || getSnapshotPath ( testPath ) ;
50+ this . _testPath = testPath ;
4551 const { data, dirty} = getSnapshotData (
4652 this . _snapshotPath ,
4753 options . updateSnapshot ,
4854 ) ;
4955 this . _snapshotData = data ;
5056 this . _dirty = dirty ;
57+ this . _inlineSnapshotData = Object . create ( null ) ;
5158 this . _uncheckedKeys = new Set ( Object . keys ( this . _snapshotData ) ) ;
5259 this . _counters = new Map ( ) ;
5360 this . _index = 0 ;
@@ -67,22 +74,42 @@ export default class SnapshotState {
6774 } ) ;
6875 }
6976
70- _addSnapshot ( key : string , receivedSerialized : string ) {
77+ _addSnapshot ( key : string , receivedSerialized : string , isInline : boolean ) {
7178 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+ }
7392 }
7493
7594 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+
7799 const status = {
78100 deleted : false ,
79101 saved : false ,
80102 } ;
81103
82104 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+ }
84111 status . saved = true ;
85- } else if ( isEmpty && fs . existsSync ( this . _snapshotPath ) ) {
112+ } else if ( ! hasExternalSnapshots && fs . existsSync ( this . _snapshotPath ) ) {
86113 if ( this . _updateSnapshot === 'all' ) {
87114 fs . unlinkSync ( this . _snapshotPath ) ;
88115 }
@@ -108,9 +135,15 @@ export default class SnapshotState {
108135 }
109136 }
110137
111- match ( testName : string , received : any , key ? : string ) {
138+ match (
139+ testName : string ,
140+ received : any ,
141+ key ? : string ,
142+ inlineSnapshot ? : string ,
143+ ) {
112144 this . _counters . set ( testName , ( this . _counters . get ( testName ) || 0 ) + 1 ) ;
113145 const count = Number ( this . _counters . get ( testName ) ) ;
146+ const isInline = typeof inlineSnapshot === 'string' ;
114147
115148 if ( ! key ) {
116149 key = testNameToKey ( testName , count ) ;
@@ -119,11 +152,13 @@ export default class SnapshotState {
119152 this . _uncheckedKeys . delete ( key ) ;
120153
121154 const receivedSerialized = serialize ( received ) ;
122- const expected = this . _snapshotData [ key ] ;
155+ const expected = isInline ? inlineSnapshot : this . _snapshotData [ key ] ;
123156 const pass = expected === receivedSerialized ;
124- const hasSnapshot = this . _snapshotData [ key ] !== undefined ;
157+ const hasSnapshot = isInline
158+ ? inlineSnapshot !== ''
159+ : this . _snapshotData [ key ] !== undefined ;
125160
126- if ( pass ) {
161+ if ( pass && ! isInline ) {
127162 // Executing a snapshot file as JavaScript and writing the strings back
128163 // when other snapshots have changed loses the proper escaping for some
129164 // characters. Since we check every snapshot in every test, use the newly
@@ -142,7 +177,7 @@ export default class SnapshotState {
142177 // * There's no snapshot file or a file without this snapshot on a CI environment.
143178 if (
144179 ( hasSnapshot && this . _updateSnapshot === 'all' ) ||
145- ( ( ! hasSnapshot || ! fs . existsSync ( this . _snapshotPath ) ) &&
180+ ( ( ! hasSnapshot || ( ! isInline && ! fs . existsSync ( this . _snapshotPath ) ) ) &&
146181 ( this . _updateSnapshot === 'new' || this . _updateSnapshot === 'all' ) )
147182 ) {
148183 if ( this . _updateSnapshot === 'all' ) {
@@ -152,12 +187,12 @@ export default class SnapshotState {
152187 } else {
153188 this . added ++ ;
154189 }
155- this . _addSnapshot ( key , receivedSerialized ) ;
190+ this . _addSnapshot ( key , receivedSerialized , isInline ) ;
156191 } else {
157192 this . matched ++ ;
158193 }
159194 } else {
160- this . _addSnapshot ( key , receivedSerialized ) ;
195+ this . _addSnapshot ( key , receivedSerialized , isInline ) ;
161196 this . added ++ ;
162197 }
163198
0 commit comments