Skip to content

Commit

Permalink
Mock composite animations when testing
Browse files Browse the repository at this point in the history
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
  • Loading branch information
javache authored and facebook-github-bot committed Oct 22, 2021
1 parent e3a71b0 commit b03e824
Showing 1 changed file with 50 additions and 10 deletions.
60 changes: 50 additions & 10 deletions Libraries/Animated/AnimatedMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -48,17 +78,27 @@ 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,
): CompositeAnimation {
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});
}),
};
};

Expand All @@ -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});
}),
};
};

Expand All @@ -86,15 +126,15 @@ const decay = function(
const sequence = function(
animations: Array<CompositeAnimation>,
): CompositeAnimation {
return emptyAnimation;
return mockCompositeAnimation(animations);
};

type ParallelConfig = {stopTogether?: boolean, ...};
const parallel = function(
animations: Array<CompositeAnimation>,
config?: ?ParallelConfig,
): CompositeAnimation {
return emptyAnimation;
return mockCompositeAnimation(animations);
};

const delay = function(time: number): CompositeAnimation {
Expand All @@ -105,7 +145,7 @@ const stagger = function(
time: number,
animations: Array<CompositeAnimation>,
): CompositeAnimation {
return emptyAnimation;
return mockCompositeAnimation(animations);
};

type LoopAnimationConfig = {
Expand Down

0 comments on commit b03e824

Please sign in to comment.