Skip to content

Commit 747eb3c

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
Introduce Fantom.unstable_advanceAnimationsByTime (#51752)
Summary: Pull Request resolved: #51752 changelog: [internal] Introduce a way to test animations: `unstable_advanceAnimationsByTime`. An API that fakes passage of time and triggers UI ticks to simulate how animations are run on iOS and Android. The API is marked as unstable because it might evolve as we write more tests for C++ Animated. Reviewed By: mdvacca Differential Revision: D75787082 fbshipit-source-id: 24e29732bbbf581871e7868289257ab60d891ddf
1 parent dd590c5 commit 747eb3c

3 files changed

Lines changed: 86 additions & 0 deletions

File tree

packages/react-native-fantom/src/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,17 @@ export function runTask(task: () => void | Promise<void>) {
186186
runWorkLoop();
187187
}
188188

189+
/**
190+
* Advances the animation clock by the specified number of milliseconds.
191+
* This function allows tests to simulate the passage of time for animations
192+
* without actually waiting, making animation testing more efficient.
193+
*
194+
* @param miliseconds - The number of milliseconds to advance animations by
195+
*/
196+
export function unstable_advanceAnimationsByTime(milliseconds: number) {
197+
NativeFantom.advanceAnimationsByTime(milliseconds);
198+
}
199+
189200
/**
190201
* Simulates running a task on the UI thread and forces side effect to drain
191202
* the event queue, scheduling events to be dispatched to JavaScript.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
12+
13+
import type {HostInstance} from 'react-native';
14+
15+
import ensureInstance from '../../../src/private/__tests__/utilities/ensureInstance';
16+
import * as Fantom from '@react-native/fantom';
17+
import {createRef} from 'react';
18+
import {Animated, useAnimatedValue} from 'react-native';
19+
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
20+
21+
test('moving box by 100 points', () => {
22+
let _translateX;
23+
const viewRef = createRef<HostInstance>();
24+
25+
function MyApp() {
26+
const translateX = useAnimatedValue(0);
27+
_translateX = translateX;
28+
return (
29+
<Animated.View
30+
ref={viewRef}
31+
style={[
32+
{
33+
width: 100,
34+
height: 100,
35+
backgroundColor: 'red',
36+
},
37+
{transform: [{translateX}]},
38+
]}
39+
testID="box"
40+
/>
41+
);
42+
}
43+
44+
const root = Fantom.createRoot();
45+
46+
Fantom.runTask(() => {
47+
root.render(<MyApp />);
48+
});
49+
50+
const viewElement = ensureInstance(viewRef.current, ReactNativeElement);
51+
52+
let boundingClientRect = viewElement.getBoundingClientRect();
53+
54+
expect(boundingClientRect.x).toBe(0);
55+
56+
Fantom.runTask(() => {
57+
Animated.timing(_translateX, {
58+
toValue: 100,
59+
duration: 1000, // 1 second
60+
useNativeDriver: true,
61+
}).start();
62+
});
63+
64+
// TODO: this fails with any value below 1038, even though anything above 1000 should be enough.
65+
Fantom.unstable_advanceAnimationsByTime(1038);
66+
boundingClientRect = viewElement.getBoundingClientRect();
67+
expect(boundingClientRect.x).toBe(100);
68+
69+
// TODO: this shouldn't be needed but C++ Animated still schedules a React state update
70+
// for synchronisation, even though it doesn't need to.
71+
Fantom.runWorkLoop();
72+
boundingClientRect = viewElement.getBoundingClientRect();
73+
expect(boundingClientRect.x).toBe(100);
74+
});

packages/react-native/src/private/testing/fantom/specs/NativeFantom.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ interface Spec extends TurboModule {
9090
takeMountingManagerLogs: (surfaceId: number) => Array<string>;
9191
flushMessageQueue: () => void;
9292
flushEventQueue: () => void;
93+
advanceAnimationsByTime: (miliseconds: number) => void;
9394
validateEmptyMessageQueue: () => void;
9495
getRenderedOutput: (surfaceId: number, config: RenderFormatOptions) => string;
9596
reportTestSuiteResultsJSON: (results: string) => void;

0 commit comments

Comments
 (0)