Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@
* @format
*/

import type * as React from 'react';
import {ScrollView} from '../Components/ScrollView/ScrollView';
import {View} from '../Components/View/View';
import {Image} from '../Image/Image';
import {FlatListComponent, FlatListProps} from '../Lists/FlatList';
import {
Image,
Text,
ScrollView,
ColorValue,
View,
FlatListProps,
DefaultSectionT,
SectionListComponent,
SectionListProps,
} from '../Lists/SectionList';
import {ColorValue} from '../StyleSheet/StyleSheet';
import {Text} from '../Text/Text';
import {NativeSyntheticEvent} from '../Types/CoreEventTypes';
NativeSyntheticEvent,
SectionListComponent,
FlatListComponent,
} from 'react-native';

import type * as React from 'react';

export namespace Animated {
type AnimatedValue = Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

'use strict';

import type {NativeSyntheticEvent} from '../Types/CoreEventTypes';
import type {PlatformConfig} from './AnimatedPlatformConfig';
import type {NativeSyntheticEvent} from 'react-native/Libraries/Types/CoreEventTypes';

import NativeAnimatedHelper from '../../src/private/animated/NativeAnimatedHelper';
import {findNodeHandle} from '../ReactNative/RendererProxy';
import AnimatedValue from './nodes/AnimatedValue';
import AnimatedValueXY from './nodes/AnimatedValueXY';
import invariant from 'invariant';
import {findNodeHandle} from 'react-native/Libraries/ReactNative/RendererProxy';
import NativeAnimatedHelper from 'react-native/src/private/animated/NativeAnimatedHelper';

export type Mapping =
| {[key: string]: Mapping, ...}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import typeof AnimatedSectionList from './components/AnimatedSectionList';
import typeof AnimatedText from './components/AnimatedText';
import typeof AnimatedView from './components/AnimatedView';

import Platform from '../Utilities/Platform';
import AnimatedImplementation from './AnimatedImplementation';
import AnimatedMock from './AnimatedMock';
import {Platform} from 'react-native';

const Animated: typeof AnimatedImplementation = Platform.isDisableAnimations
? AnimatedMock
Expand Down
196 changes: 196 additions & 0 deletions packages/animated/AnimatedMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/

'use strict';

import type {Numeric as AnimatedNumeric} from './AnimatedImplementation';
import type {EndResult} from './animations/Animation';
import type {EndCallback} from './animations/Animation';
import type {DecayAnimationConfig} from './animations/DecayAnimation';
import type {SpringAnimationConfig} from './animations/SpringAnimation';
import type {TimingAnimationConfig} from './animations/TimingAnimation';

import {AnimatedEvent, attachNativeEvent} from './AnimatedEvent';
import AnimatedImplementation from './AnimatedImplementation';
import createAnimatedComponent from './createAnimatedComponent';
import AnimatedColor from './nodes/AnimatedColor';
import AnimatedInterpolation from './nodes/AnimatedInterpolation';
import AnimatedNode from './nodes/AnimatedNode';
import AnimatedValue from './nodes/AnimatedValue';
import AnimatedValueXY from './nodes/AnimatedValueXY';

/**
* Animations are a source of flakiness in snapshot testing. This mock replaces
* animation functions from AnimatedImplementation with empty animations for
* 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: Array<EndResult>) => {
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,
reset: () => void,
_startNativeLoop: (iterations?: number) => void,
_isUsingNativeDriver: () => boolean,
...
};

const emptyAnimation = {
start: () => {},
stop: () => {},
reset: () => {},
_startNativeLoop: () => {},
_isUsingNativeDriver: () => {
return false;
},
};

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 | AnimatedColor,
config: SpringAnimationConfig,
): CompositeAnimation {
const anyValue: any = value;
return {
...emptyAnimation,
start: mockAnimationStart((callback?: ?EndCallback): void => {
anyValue.setValue(config.toValue);
callback?.({finished: true});
}),
};
};

const timing = function (
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: TimingAnimationConfig,
): CompositeAnimation {
const anyValue: any = value;
return {
...emptyAnimation,
start: mockAnimationStart((callback?: ?EndCallback): void => {
anyValue.setValue(config.toValue);
callback?.({finished: true});
}),
};
};

const decay = function (
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: DecayAnimationConfig,
): CompositeAnimation {
return emptyAnimation;
};

const sequence = function (
animations: Array<CompositeAnimation>,
): CompositeAnimation {
return mockCompositeAnimation(animations);
};

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

const delay = function (time: number): CompositeAnimation {
return emptyAnimation;
};

const stagger = function (
time: number,
animations: Array<CompositeAnimation>,
): CompositeAnimation {
return mockCompositeAnimation(animations);
};

type LoopAnimationConfig = {
iterations: number,
resetBeforeIteration?: boolean,
...
};

const loop = function (
animation: CompositeAnimation,
// $FlowFixMe[prop-missing]
{iterations = -1}: LoopAnimationConfig = {},
): CompositeAnimation {
return emptyAnimation;
};

export type {AnimatedNumeric as Numeric};

const AnimatedMock = {
Value: AnimatedValue,
ValueXY: AnimatedValueXY,
Color: AnimatedColor,
Interpolation: AnimatedInterpolation,
Node: AnimatedNode,
decay,
timing,
spring,
add: AnimatedImplementation.add,
subtract: AnimatedImplementation.subtract,
divide: AnimatedImplementation.divide,
multiply: AnimatedImplementation.multiply,
modulo: AnimatedImplementation.modulo,
diffClamp: AnimatedImplementation.diffClamp,
delay,
sequence,
parallel,
stagger,
loop,
event: AnimatedImplementation.event,
createAnimatedComponent,
attachNativeEvent,
forkEvent: AnimatedImplementation.forkEvent,
unforkEvent: AnimatedImplementation.unforkEvent,
Event: AnimatedEvent,
};
export default AnimatedMock;
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import type {AnimatedPropsAllowlist} from './nodes/AnimatedProps';

import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';

/**
* Styles allowed by the native animated implementation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
* @format
*/

export * from '../../src/private/specs_DEPRECATED/modules/NativeAnimatedModule';
import NativeAnimatedModule from '../../src/private/specs_DEPRECATED/modules/NativeAnimatedModule';
export * from 'react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedModule';
import NativeAnimatedModule from 'react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedModule';
export default NativeAnimatedModule;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
* @format
*/

export * from '../../src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule';
import NativeAnimatedTurboModule from '../../src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule';
export * from 'react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule';
import NativeAnimatedTurboModule from 'react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule';
export default NativeAnimatedTurboModule;
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@

import * as React from 'react';

const {create, unmount, update} = require('../../../jest/renderer');
const {PlatformColor} = require('../../StyleSheet/PlatformColorValueTypes');
let Animated = require('../Animated').default;
const AnimatedProps = require('../nodes/AnimatedProps').default;
const {create, unmount, update} = require('react-native/jest/renderer');
const {
PlatformColor,
} = require('react-native/Libraries/StyleSheet/PlatformColorValueTypes');
const TestRenderer = require('react-test-renderer');

// WORKAROUND: `jest.runAllTicks` skips tasks scheduled w/ `queueMicrotask`.
Expand All @@ -36,7 +38,7 @@ describe('Animated', () => {
beforeEach(() => {
jest.resetModules();

ReactNativeFeatureFlags = require('../../../src/private/featureflags/ReactNativeFeatureFlags');
ReactNativeFeatureFlags = require('react-native/src/private/featureflags/ReactNativeFeatureFlags');
});

mockQueueMicrotask();
Expand Down Expand Up @@ -902,14 +904,14 @@ describe('Animated', () => {
let InteractionManager;

beforeEach(() => {
jest.mock('../../Interaction/InteractionManager');
jest.mock('react-native/Libraries/Interaction/InteractionManager');
Animated = require('../Animated').default;
InteractionManager =
require('../../Interaction/InteractionManager').default;
require('react-native/Libraries/Interaction/InteractionManager').default;
});

afterEach(() => {
jest.unmock('../../Interaction/InteractionManager');
jest.unmock('react-native/Libraries/Interaction/InteractionManager');
});

it('registers an interaction by default', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
* @oncall react_native
*/

const StyleSheet = require('../../StyleSheet/StyleSheet').default;
let Animated = require('../Animated').default;
let AnimatedProps = require('../nodes/AnimatedProps').default;
const StyleSheet =
require('react-native/Libraries/StyleSheet/StyleSheet').default;

jest.mock('../../Utilities/Platform', () => ({
jest.mock('react-native/Libraries/Utilities/Platform', () => ({
__esModule: true,
default: {
OS: 'web',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('AnimatedValue', () => {
}));

NativeAnimatedHelper =
require('../../../src/private/animated/NativeAnimatedHelper').default;
require('react-native/src/private/animated/NativeAnimatedHelper').default;
AnimatedValue = require('../nodes/AnimatedValue').default;

jest.spyOn(NativeAnimatedHelper.API, 'createAnimatedNode');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('NativeAnimatedAllowlist', () => {
it('checks supported transform props', () => {
jest
.spyOn(
require('../../../src/private/featureflags/ReactNativeFeatureFlags'),
require('react-native/src/private/featureflags/ReactNativeFeatureFlags'),
'shouldUseAnimatedObjectForTransform',
)
.mockReturnValue(false);
Expand All @@ -73,7 +73,7 @@ describe('NativeAnimatedAllowlist', () => {
it('checks supported transform props with object for transform', () => {
jest
.spyOn(
require('../../../src/private/featureflags/ReactNativeFeatureFlags'),
require('react-native/src/private/featureflags/ReactNativeFeatureFlags'),
'shouldUseAnimatedObjectForTransform',
)
.mockReturnValue(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import type {PlatformConfig} from '../AnimatedPlatformConfig';
import type AnimatedNode from '../nodes/AnimatedNode';
import type AnimatedValue from '../nodes/AnimatedValue';

import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
import AnimatedProps from '../nodes/AnimatedProps';
import NativeAnimatedHelper from 'react-native/src/private/animated/NativeAnimatedHelper';
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';

export type EndResult = {finished: boolean, value?: number, ...};
export type EndCallback = (result: EndResult) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

import type {AnimatedComponentType} from '../createAnimatedComponent';

import FlatList from '../../Lists/FlatList';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
import {FlatList} from 'react-native';

export default (createAnimatedComponent(FlatList): AnimatedComponentType<
React.ElementConfig<typeof FlatList>,
Expand Down
Loading