@@ -27,8 +27,38 @@ import type {SpringAnimationConfig} from './animations/SpringAnimation';
27
27
/**
28
28
* Animations are a source of flakiness in snapshot testing. This mock replaces
29
29
* animation functions from AnimatedImplementation with empty animations for
30
- * predictability in tests.
30
+ * predictability in tests. When possible the animation will run immediately
31
+ * to the final state.
31
32
*/
33
+
34
+ // Prevent any callback invocation from recursively triggering another
35
+ // callback, which may trigger another animation
36
+ let inAnimationCallback = false ;
37
+ function mockAnimationStart (
38
+ start : ( callback ?: ?EndCallback ) => void ,
39
+ ) : ( callback ?: ?EndCallback ) => void {
40
+ return callback => {
41
+ const guardedCallback =
42
+ callback == null
43
+ ? callback
44
+ : ( ...args ) => {
45
+ if ( inAnimationCallback ) {
46
+ console . warn (
47
+ 'Ignoring recursive animation callback when running mock animations' ,
48
+ ) ;
49
+ return ;
50
+ }
51
+ inAnimationCallback = true ;
52
+ try {
53
+ callback ( ...args ) ;
54
+ } finally {
55
+ inAnimationCallback = false ;
56
+ }
57
+ } ;
58
+ start ( guardedCallback ) ;
59
+ } ;
60
+ }
61
+
32
62
export type CompositeAnimation = {
33
63
start : ( callback ?: ?EndCallback ) => void ,
34
64
stop : ( ) => void ,
@@ -48,17 +78,27 @@ const emptyAnimation = {
48
78
} ,
49
79
} ;
50
80
81
+ const mockCompositeAnimation = (
82
+ animations : Array < CompositeAnimation > ,
83
+ ) : CompositeAnimation => ( {
84
+ ...emptyAnimation ,
85
+ start : mockAnimationStart ( ( callback ?: ?EndCallback ) : void => {
86
+ animations . forEach ( animation => animation . start ( ) ) ;
87
+ callback ?. ( { finished : true } ) ;
88
+ } ) ,
89
+ } ) ;
90
+
51
91
const spring = function (
52
92
value : AnimatedValue | AnimatedValueXY ,
53
93
config : SpringAnimationConfig ,
54
94
) : CompositeAnimation {
55
95
const anyValue : any = value ;
56
96
return {
57
97
...emptyAnimation ,
58
- start : ( callback ?: ?EndCallback ) : void => {
98
+ start : mockAnimationStart ( ( callback ?: ?EndCallback ) : void => {
59
99
anyValue . setValue ( config . toValue ) ;
60
- callback && callback ( { finished : true } ) ;
61
- } ,
100
+ callback ?. ( { finished : true } ) ;
101
+ } ) ,
62
102
} ;
63
103
} ;
64
104
@@ -69,10 +109,10 @@ const timing = function(
69
109
const anyValue : any = value ;
70
110
return {
71
111
...emptyAnimation ,
72
- start : ( callback ?: ?EndCallback ) : void => {
112
+ start : mockAnimationStart ( ( callback ?: ?EndCallback ) : void => {
73
113
anyValue . setValue ( config . toValue ) ;
74
- callback && callback ( { finished : true } ) ;
75
- } ,
114
+ callback ?. ( { finished : true } ) ;
115
+ } ) ,
76
116
} ;
77
117
} ;
78
118
@@ -86,15 +126,15 @@ const decay = function(
86
126
const sequence = function (
87
127
animations : Array < CompositeAnimation > ,
88
128
) : CompositeAnimation {
89
- return emptyAnimation ;
129
+ return mockCompositeAnimation ( animations ) ;
90
130
} ;
91
131
92
132
type ParallelConfig = { stopTogether ?: boolean , ...} ;
93
133
const parallel = function (
94
134
animations : Array < CompositeAnimation > ,
95
135
config ?: ?ParallelConfig ,
96
136
) : CompositeAnimation {
97
- return emptyAnimation ;
137
+ return mockCompositeAnimation ( animations ) ;
98
138
} ;
99
139
100
140
const delay = function ( time : number ) : CompositeAnimation {
@@ -105,7 +145,7 @@ const stagger = function(
105
145
time : number ,
106
146
animations : Array < CompositeAnimation > ,
107
147
) : CompositeAnimation {
108
- return emptyAnimation ;
148
+ return mockCompositeAnimation ( animations ) ;
109
149
} ;
110
150
111
151
type LoopAnimationConfig = {
0 commit comments