1 | import Animated, { Easing } from './Animated';
|
2 | import ReanimatedModule from './ReanimatedModule';
|
3 | import React from 'react';
|
4 |
|
5 | import renderer from 'react-test-renderer';
|
6 |
|
7 | jest.mock('./ReanimatedEventEmitter');
|
8 | jest.mock('./ReanimatedModule');
|
9 | jest.mock('./derived/evaluateOnce');
|
10 | jest.mock('./core/AnimatedProps');
|
11 |
|
12 | const { Value, timing, spring, decay } = Animated;
|
13 | describe('Reanimated backward compatible API', () => {
|
14 | beforeEach(() => {
|
15 | let numberOfNodes = 0;
|
16 | ReanimatedModule.createNode = () => numberOfNodes++;
|
17 | ReanimatedModule.dropNode = () => numberOfNodes--;
|
18 | ReanimatedModule.getNumberOfNodes = () => numberOfNodes;
|
19 | });
|
20 |
|
21 | const checkIfNodesGetDetachedCorrectly = animation => {
|
22 | class TestComponent extends React.Component {
|
23 | constructor(props) {
|
24 | super(props);
|
25 | this.transX = new Value(0);
|
26 | this.anim = animation.node(this.transX, animation.config);
|
27 | }
|
28 |
|
29 | start(method) {
|
30 | this.anim.start(method);
|
31 | }
|
32 |
|
33 | stop(res) {
|
34 | this.anim.__stopImmediately_testOnly(res);
|
35 | }
|
36 |
|
37 | render() {
|
38 | return (
|
39 | <Animated.View style={{ transform: [{ translateX: this.transX }] }} />
|
40 | );
|
41 | }
|
42 | }
|
43 | const ref = React.createRef();
|
44 | let result;
|
45 | const resMethod = ({ finished }) => (result = finished);
|
46 | const initial = ReanimatedModule.getNumberOfNodes();
|
47 | const wrapper = renderer.create(<TestComponent ref={ref} />);
|
48 | const before = ReanimatedModule.getNumberOfNodes();
|
49 | ref.current.start(resMethod);
|
50 | const during = ReanimatedModule.getNumberOfNodes();
|
51 | ref.current.stop(true);
|
52 | const after = ReanimatedModule.getNumberOfNodes();
|
53 | wrapper.unmount();
|
54 | const final = ReanimatedModule.getNumberOfNodes();
|
55 |
|
56 | return (
|
57 | result &&
|
58 | initial === final &&
|
59 | after === before &&
|
60 | during > after &&
|
61 | initial === 0 &&
|
62 | before === 4
|
63 | );
|
64 | };
|
65 |
|
66 | it('fails if timing does not attach nodes correctly', () => {
|
67 | expect(
|
68 | checkIfNodesGetDetachedCorrectly({
|
69 | node: timing,
|
70 | name: 'timing',
|
71 | config: {
|
72 | duration: 5000,
|
73 | toValue: 120,
|
74 | easing: Easing.inOut(Easing.ease),
|
75 | },
|
76 | })
|
77 | ).toBeTruthy();
|
78 | });
|
79 |
|
80 | it('fails if decay does not attach nodes correctly', () => {
|
81 | expect(
|
82 | checkIfNodesGetDetachedCorrectly({
|
83 | node: decay,
|
84 | name: 'decay',
|
85 | config: {
|
86 | deceleration: 0.997,
|
87 | },
|
88 | })
|
89 | ).toBeTruthy();
|
90 | });
|
91 |
|
92 | it('fails if spring does not attach nodes correctly', () => {
|
93 | expect(
|
94 | checkIfNodesGetDetachedCorrectly({
|
95 | node: spring,
|
96 | name: 'spring',
|
97 | config: {
|
98 | toValue: 0,
|
99 | damping: 7,
|
100 | mass: 1,
|
101 | stiffness: 121.6,
|
102 | overshootClamping: false,
|
103 | restSpeedThreshold: 0.001,
|
104 | restDisplacementThreshold: 0.001,
|
105 | },
|
106 | })
|
107 | ).toBeTruthy();
|
108 | });
|
109 |
|
110 | it('fails if animation related nodes are still attached after detaching of value with two animations triggered', () => {
|
111 | const { timing, Value } = Animated;
|
112 | class TestComponent extends React.Component {
|
113 | constructor(props) {
|
114 | super(props);
|
115 | this.transX = new Value(0);
|
116 | const config = {
|
117 | duration: 5000,
|
118 | toValue: -120,
|
119 | easing: Easing.inOut(Easing.ease),
|
120 | };
|
121 | this.anim = timing(this.transX, config);
|
122 | this.anim2 = timing(this.transX, config);
|
123 | }
|
124 |
|
125 | start1(method) {
|
126 | this.anim.start(method);
|
127 | }
|
128 |
|
129 | start2(method) {
|
130 | this.anim2.start(method);
|
131 | }
|
132 |
|
133 | render() {
|
134 | return (
|
135 | <Animated.View style={{ transform: [{ translateX: this.transX }] }} />
|
136 | );
|
137 | }
|
138 | }
|
139 | const ref = React.createRef();
|
140 | const wrapper = renderer.create(<TestComponent ref={ref} />);
|
141 | let result = true;
|
142 | const resMethod = ({ finished }) => (result = finished);
|
143 | ref.current.start1(resMethod);
|
144 | ref.current.start2(resMethod);
|
145 | expect(result).toBeFalsy();
|
146 | result = true;
|
147 | const numberOfNodesBeforeUnmounting = ReanimatedModule.getNumberOfNodes();
|
148 | wrapper.unmount();
|
149 | expect(result).toBeFalsy();
|
150 | const numberOfNodesAfterUnmounting = ReanimatedModule.getNumberOfNodes();
|
151 | const pass =
|
152 | numberOfNodesAfterUnmounting === 0 && numberOfNodesBeforeUnmounting > 0;
|
153 | expect(pass).toBeTruthy();
|
154 | });
|
155 |
|
156 | it('fails if animation related nodes are detached if there are two children and only one detach', () => {
|
157 | const { timing, Value } = Animated;
|
158 | const transX = new Value(0);
|
159 | const wrapper1 = renderer.create(
|
160 | <Animated.View
|
161 | style={{
|
162 | transform: [{ translateX: transX }],
|
163 | }}
|
164 | />
|
165 | );
|
166 | const wrapper2 = renderer.create(
|
167 | <Animated.View
|
168 | style={{
|
169 | transform: [{ translateX: transX }],
|
170 | }}
|
171 | />
|
172 | );
|
173 | const config = {
|
174 | duration: 5000,
|
175 | toValue: -120,
|
176 | easing: Easing.inOut(Easing.ease),
|
177 | };
|
178 | const anim = timing(transX, config);
|
179 | anim.start();
|
180 | const numberOfNodesBeforeDetach = ReanimatedModule.getNumberOfNodes();
|
181 | wrapper1.unmount();
|
182 | const numberOfNodesAfterDetach = ReanimatedModule.getNumberOfNodes();
|
183 | const result =
|
184 | // 3 means AnimatedProps, AnimatedStyle and AnimatedTransform
|
185 | // which are nodes not related to animation and has to be detached
|
186 | numberOfNodesBeforeDetach - 3 === numberOfNodesAfterDetach &&
|
187 | numberOfNodesAfterDetach > 3;
|
188 | expect(result).toBeTruthy();
|
189 | wrapper2.unmount();
|
190 | expect(ReanimatedModule.getNumberOfNodes() === 0).toBeTruthy();
|
191 | });
|
192 |
|
193 | it('fails if animation attaches some node without view related', () => {
|
194 | const { timing, Value } = Animated;
|
195 | const transX = new Value(0);
|
196 |
|
197 | const config = {
|
198 | duration: 5000,
|
199 | toValue: -120,
|
200 | easing: Easing.inOut(Easing.ease),
|
201 | };
|
202 | const anim = timing(transX, config);
|
203 | anim.start();
|
204 | expect(ReanimatedModule.getNumberOfNodes()).toBe(0);
|
205 | });
|
206 | });
|