Mock composite animations when testing

Summary:
Single and composite animations were handled inconsistently in AnimatedMock. Also added a guard to prevent callbacks from triggering additional animations, since we had a test-scenario that did exactly that.

Changelog:
[General][Fixed] - Composite animations will now be ran immediately when the app is in testing mode

Reviewed By: yungsters

Differential Revision: D31826967

fbshipit-source-id: a6416b42e227fe79f5c3a55a9c51beb8451874f8
This commit is contained in:
Pieter De Baets
2021-10-22 06:38:17 -07:00
committed by Facebook GitHub Bot
parent e3a71b019f
commit b03e824c52
+50 -10
View File
@@ -27,8 +27,38 @@ import type {SpringAnimationConfig} from './animations/SpringAnimation';
/**
* Animations are a source of flakiness in snapshot testing. This mock replaces
* animation functions from AnimatedImplementation with empty animations for
* predictability in tests.
* predictability in tests. When possible the animation will run immediately
* to the final state.
*/
// Prevent any callback invocation from recursively triggering another
// callback, which may trigger another animation
let inAnimationCallback = false;
function mockAnimationStart(
start: (callback?: ?EndCallback) => void,
): (callback?: ?EndCallback) => void {
return callback => {
const guardedCallback =
callback == null
? callback
: (...args) => {
if (inAnimationCallback) {
console.warn(
'Ignoring recursive animation callback when running mock animations',
);
return;
}
inAnimationCallback = true;
try {
callback(...args);
} finally {
inAnimationCallback = false;
}
};
start(guardedCallback);
};
}
export type CompositeAnimation = {
start: (callback?: ?EndCallback) => void,
stop: () => void,
@@ -48,6 +78,16 @@ const emptyAnimation = {
},
};
const mockCompositeAnimation = (
animations: Array<CompositeAnimation>,
): CompositeAnimation => ({
...emptyAnimation,
start: mockAnimationStart((callback?: ?EndCallback): void => {
animations.forEach(animation => animation.start());
callback?.({finished: true});
}),
});
const spring = function(
value: AnimatedValue | AnimatedValueXY,
config: SpringAnimationConfig,
@@ -55,10 +95,10 @@ const spring = function(
const anyValue: any = value;
return {
...emptyAnimation,
start: (callback?: ?EndCallback): void => {
start: mockAnimationStart((callback?: ?EndCallback): void => {
anyValue.setValue(config.toValue);
callback && callback({finished: true});
},
callback?.({finished: true});
}),
};
};
@@ -69,10 +109,10 @@ const timing = function(
const anyValue: any = value;
return {
...emptyAnimation,
start: (callback?: ?EndCallback): void => {
start: mockAnimationStart((callback?: ?EndCallback): void => {
anyValue.setValue(config.toValue);
callback && callback({finished: true});
},
callback?.({finished: true});
}),
};
};
@@ -86,7 +126,7 @@ const decay = function(
const sequence = function(
animations: Array<CompositeAnimation>,
): CompositeAnimation {
return emptyAnimation;
return mockCompositeAnimation(animations);
};
type ParallelConfig = {stopTogether?: boolean, ...};
@@ -94,7 +134,7 @@ const parallel = function(
animations: Array<CompositeAnimation>,
config?: ?ParallelConfig,
): CompositeAnimation {
return emptyAnimation;
return mockCompositeAnimation(animations);
};
const delay = function(time: number): CompositeAnimation {
@@ -105,7 +145,7 @@ const stagger = function(
time: number,
animations: Array<CompositeAnimation>,
): CompositeAnimation {
return emptyAnimation;
return mockCompositeAnimation(animations);
};
type LoopAnimationConfig = {