Skip to content

Commit

Permalink
Test predefined entering animation (#5995)
Browse files Browse the repository at this point in the history
<!-- Thanks for submitting a pull request! We appreciate you spending
the time to work on these changes. Please follow the template so that
the reviewers can easily understand what the code changes affect. -->

## Summary

The tests require about 1minute 40s to run.

The new tests:
* verify that all the exported predefined entering animations have
stable behaviour
* verify that they work with our most important modifiers: springify &
duration

Also I improve the way I deep copy updates

## Test plan


![image](https://github.com/software-mansion/react-native-reanimated/assets/56199675/97f97c49-4555-4db6-9374-676d86771f58)



<!-- Provide a minimal but complete code snippet that can be used to
test out this change along with instructions how to run it and a
description of the expected behavior. -->
  • Loading branch information
Latropos committed May 27, 2024
1 parent 607e59a commit 86b163d
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ export function createUpdatesContainer(testRunner: TestRunner) {
jsUpdates.modify(updates => {
updates.push({
tag,
update: { ...update },
// Deep Copy, works with nested objects, but doesn't copy functions (which should be fine here)
update: JSON.parse(JSON.stringify(update)),
});
return updates;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export function indentNestingLevel(nestingLevel: number) {
export function appendWhiteSpaceToMatchLength(message: string | number, length: number) {
const messageStr = message.toString();
const messageLen = messageStr.length;
return `${messageStr}${' '.repeat(length - messageLen)}`;
const indentSize = Math.max(0, length - messageLen);
return `${messageStr}${' '.repeat(indentSize)}`;
}

export function color(value: NullableTestValue, color: 'yellow' | 'cyan' | 'green' | 'red' | 'gray' | 'orange') {
Expand Down
1 change: 1 addition & 0 deletions app/src/examples/RuntimeTests/RuntimeTestsExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import './tests/animations/withTiming/transformMatrices.test';
import './tests/animations/withSpring/variousConfig.test';

import './tests/layoutAnimations/entering/enteringColors.test';
import './tests/layoutAnimations/entering/predefinedEntering.test';

import './tests/utilities/relativeCoords.test';

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
render,
wait,
} from '../../../ReanimatedRuntimeTestsRunner/RuntimeTestsApi';
import { Snapshots } from './entering.snapshot';
import { ColorSnapshots as Snapshots } from './entering.snapshot';

const AnimatedComponent = ({ fromColor, toColor }: { fromColor: string; toColor: string }) => {
const customAnim = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { View, StyleSheet } from 'react-native';
import Animated, {
FadeIn,
FadeInRight,
FadeInLeft,
FadeInUp,
FadeInDown,
BounceIn,
BounceInRight,
BounceInLeft,
BounceInUp,
BounceInDown,
FlipInEasyX,
FlipInEasyY,
FlipInXDown,
FlipInXUp,
FlipInYLeft,
FlipInYRight,
LightSpeedInRight,
LightSpeedInLeft,
PinwheelIn,
RotateInDownLeft,
RotateInDownRight,
RotateInUpLeft,
RotateInUpRight,
SlideInRight,
SlideInLeft,
SlideInUp,
SlideInDown,
StretchInX,
StretchInY,
ZoomIn,
ZoomInDown,
ZoomInEasyDown,
ZoomInEasyUp,
ZoomInLeft,
ZoomInRight,
ZoomInRotate,
ZoomInUp,
RollInRight,
RollInLeft,
} from 'react-native-reanimated';
import React from 'react';
import {
describe,
test,
expect,
mockAnimationTimer,
recordAnimationUpdates,
render,
wait,
unmockAnimationTimer,
clearRenderOutput,
} from '../../../ReanimatedRuntimeTestsRunner/RuntimeTestsApi';
import {
DurationEnteringSnapshots,
NoModifierEnteringSnapshots,
SpringifyEnteringSnapshots,
} from './entering.snapshot';

const FADE_ENTERING = [FadeIn, FadeInRight, FadeInRight, FadeInLeft, FadeInUp, FadeInDown];
const BOUNCE_ENTERING = [BounceIn, BounceInRight, BounceInLeft, BounceInUp, BounceInDown];
const FLIP_ENTERING = [FlipInEasyX, FlipInEasyY, FlipInXDown, FlipInXUp, FlipInYLeft, FlipInYRight];
const LIGHTSPEED_ENTERING = [LightSpeedInRight, LightSpeedInLeft];
const PINWHEEL_ENTERING = [PinwheelIn];
const ROLL_ENTERING = [RollInRight, RollInLeft]; //Don't test RollIn, until recording rotation snapshot gets fixed
const ROTATE_ENTERING = [RotateInDownLeft, RotateInDownRight, RotateInUpLeft, RotateInUpRight];
const SLIDE_ENTERING = [SlideInRight, SlideInLeft, SlideInUp, SlideInDown];
const STRETCH_ENTERING = [StretchInX, StretchInY];

const ZOOM_ENTERING = [
ZoomIn,
ZoomInDown,
ZoomInEasyDown,
ZoomInEasyUp,
ZoomInLeft,
ZoomInRight,
ZoomInRotate,
ZoomInUp,
];

const ENTERING_SETS: Array<[string, unknown[], number]> = [
['Fade', FADE_ENTERING, 1350],
['Bounce', BOUNCE_ENTERING, 650],
['Flip', FLIP_ENTERING, 1750],
['LightSpeed', LIGHTSPEED_ENTERING, 1600],
['Pinwheel', PINWHEEL_ENTERING, 1000],
['Roll', ROLL_ENTERING, 1750],
['Rotate', ROTATE_ENTERING, 1600],
['Slide', SLIDE_ENTERING, 1800],
['Stretch', STRETCH_ENTERING, 1000],
['Zoom', ZOOM_ENTERING, 1800],
];

const EnteringOnMountComponent = ({ entering }: { entering: any }) => {
return (
<View style={styles.container}>
<Animated.View entering={entering} style={styles.animatedBox} />
</View>
);
};

async function getSnapshotUpdates(entering: any, waitTime: number, duration: number | undefined, springify = false) {
await mockAnimationTimer();

const updatesContainer = await recordAnimationUpdates();
const springEntering = springify ? entering : entering.springify();
const componentEntering = duration ? springEntering.duration(duration) : springEntering;

await render(<EnteringOnMountComponent entering={componentEntering} />);
await wait(waitTime);
const updates = updatesContainer.getUpdates();
await unmockAnimationTimer();
await clearRenderOutput();

return updates;
}

describe('Test predefined entering', () => {
describe('Entering on mount, no modifiers', async () => {
test.each(ENTERING_SETS)('Test suite of ${0}In', async ([_setName, enteringSet, waitTime]) => {
for (const entering of enteringSet) {
const snapshotName = (entering as any).name;
const updates = await getSnapshotUpdates(entering, waitTime, undefined);
expect(updates).toMatchSnapshots(
NoModifierEnteringSnapshots[snapshotName as keyof typeof NoModifierEnteringSnapshots],
);
}
});
});

describe('Entering on mount, duration 100', async () => {
test.each(ENTERING_SETS)('Test suite of ${0}In', async ([_setName, enteringSet, _waitTime]) => {
for (const entering of enteringSet) {
const enteringName: string = (entering as any).name;
let updates = await getSnapshotUpdates(entering, 105, 100);
expect(updates).toMatchSnapshots(
DurationEnteringSnapshots[enteringName as keyof typeof DurationEnteringSnapshots],
);
}
});
});

describe('Entering on mount, springify', async () => {
test.each(ENTERING_SETS)('Test suite of ${0}In', async ([_setName, enteringSet, waitTime]) => {
const timeToWait = _setName === 'Bounce' ? 650 : waitTime * 0.3;
for (const entering of enteringSet) {
const snapshotName = (entering as any).name;
const updates = await getSnapshotUpdates(entering, timeToWait, undefined, true);
expect(updates).toMatchSnapshots(
SpringifyEnteringSnapshots[snapshotName as keyof typeof SpringifyEnteringSnapshots],
);
}
});
});
});

const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
animatedBox: {
backgroundColor: 'royalblue',
height: 80,
margin: 40,
},
});

0 comments on commit 86b163d

Please sign in to comment.