1 |
|
2 | 'use strict';
|
3 |
|
4 | import { isJest } from "./PlatformChecker.js";
|
5 | import { ReanimatedError } from "./errors.js";
|
6 | const defaultFramerateConfig = {
|
7 | fps: 60
|
8 | };
|
9 | const isEmpty = obj => Object.keys(obj).length === 0;
|
10 | const getStylesFromObject = obj => {
|
11 | return obj === undefined ? {} : Object.fromEntries(Object.entries(obj).map(([property, value]) => [property, value._isReanimatedSharedValue ? value.value : value]));
|
12 | };
|
13 | const getCurrentStyle = component => {
|
14 | const styleObject = component.props.style;
|
15 | let currentStyle = {};
|
16 | if (Array.isArray(styleObject)) {
|
17 |
|
18 |
|
19 | styleObject.forEach(style => {
|
20 | currentStyle = {
|
21 | ...currentStyle,
|
22 | ...style
|
23 | };
|
24 | });
|
25 | return currentStyle;
|
26 | }
|
27 | const jestInlineStyles = component.props.jestInlineStyle;
|
28 | const jestAnimatedStyleValue = component.props.jestAnimatedStyle?.value;
|
29 | if (Array.isArray(jestInlineStyles)) {
|
30 | for (const obj of jestInlineStyles) {
|
31 | if ('jestAnimatedStyle' in obj) {
|
32 | continue;
|
33 | }
|
34 | const inlineStyles = getStylesFromObject(obj);
|
35 | currentStyle = {
|
36 | ...currentStyle,
|
37 | ...inlineStyles
|
38 | };
|
39 | }
|
40 | currentStyle = {
|
41 | ...styleObject,
|
42 | ...currentStyle,
|
43 | ...jestAnimatedStyleValue
|
44 | };
|
45 | return currentStyle;
|
46 | }
|
47 | const inlineStyles = getStylesFromObject(jestInlineStyles);
|
48 | currentStyle = isEmpty(jestAnimatedStyleValue) ? {
|
49 | ...styleObject,
|
50 | ...inlineStyles
|
51 | } : {
|
52 | ...styleObject,
|
53 | ...jestAnimatedStyleValue
|
54 | };
|
55 | return currentStyle;
|
56 | };
|
57 | const checkEqual = (current, expected) => {
|
58 | if (Array.isArray(expected)) {
|
59 | if (!Array.isArray(current) || expected.length !== current.length) {
|
60 | return false;
|
61 | }
|
62 | for (let i = 0; i < current.length; i++) {
|
63 | if (!checkEqual(current[i], expected[i])) {
|
64 | return false;
|
65 | }
|
66 | }
|
67 | } else if (typeof current === 'object' && current) {
|
68 | if (typeof expected !== 'object' || !expected) {
|
69 | return false;
|
70 | }
|
71 | for (const property in expected) {
|
72 | if (!checkEqual(current[property], expected[property])) {
|
73 | return false;
|
74 | }
|
75 | }
|
76 | } else {
|
77 | return current === expected;
|
78 | }
|
79 | return true;
|
80 | };
|
81 | const findStyleDiff = (current, expected, shouldMatchAllProps) => {
|
82 | const diffs = [];
|
83 | let isEqual = true;
|
84 | let property;
|
85 | for (property in expected) {
|
86 | if (!checkEqual(current[property], expected[property])) {
|
87 | isEqual = false;
|
88 | diffs.push({
|
89 | property,
|
90 | current: current[property],
|
91 | expect: expected[property]
|
92 | });
|
93 | }
|
94 | }
|
95 | if (shouldMatchAllProps && Object.keys(current).length !== Object.keys(expected).length) {
|
96 | isEqual = false;
|
97 |
|
98 | let property;
|
99 | for (property in current) {
|
100 | if (expected[property] === undefined) {
|
101 | diffs.push({
|
102 | property,
|
103 | current: current[property],
|
104 | expect: expected[property]
|
105 | });
|
106 | }
|
107 | }
|
108 | }
|
109 | return {
|
110 | isEqual,
|
111 | diffs
|
112 | };
|
113 | };
|
114 | const compareStyle = (component, expectedStyle, config) => {
|
115 | if (!component.props.style) {
|
116 | return {
|
117 | message: () => `Component doesn't have a style.`,
|
118 | pass: false
|
119 | };
|
120 | }
|
121 | const {
|
122 | shouldMatchAllProps
|
123 | } = config;
|
124 | const currentStyle = getCurrentStyle(component);
|
125 | const {
|
126 | isEqual,
|
127 | diffs
|
128 | } = findStyleDiff(currentStyle, expectedStyle, shouldMatchAllProps);
|
129 | if (isEqual) {
|
130 | return {
|
131 | message: () => 'ok',
|
132 | pass: true
|
133 | };
|
134 | }
|
135 | const currentStyleStr = JSON.stringify(currentStyle);
|
136 | const expectedStyleStr = JSON.stringify(expectedStyle);
|
137 | const differences = diffs.map(diff => `- '${diff.property}' should be ${JSON.stringify(diff.expect)}, but is ${JSON.stringify(diff.current)}`).join('\n');
|
138 | return {
|
139 | message: () => `Expected: ${expectedStyleStr}\nReceived: ${currentStyleStr}\n\nDifferences:\n${differences}`,
|
140 | pass: false
|
141 | };
|
142 | };
|
143 | let frameTime = Math.round(1000 / defaultFramerateConfig.fps);
|
144 | const beforeTest = () => {
|
145 | jest.useFakeTimers();
|
146 | };
|
147 | const afterTest = () => {
|
148 | jest.runOnlyPendingTimers();
|
149 | jest.useRealTimers();
|
150 | };
|
151 | export const withReanimatedTimer = animationTest => {
|
152 | console.warn('This method is deprecated, you should define your own before and after test hooks to enable jest.useFakeTimers(). Check out the documentation for details on testing');
|
153 | beforeTest();
|
154 | animationTest();
|
155 | afterTest();
|
156 | };
|
157 | export const advanceAnimationByTime = (time = frameTime) => {
|
158 | console.warn('This method is deprecated, use jest.advanceTimersByTime directly');
|
159 | jest.advanceTimersByTime(time);
|
160 | jest.runOnlyPendingTimers();
|
161 | };
|
162 | export const advanceAnimationByFrame = count => {
|
163 | console.warn('This method is deprecated, use jest.advanceTimersByTime directly');
|
164 | jest.advanceTimersByTime(count * frameTime);
|
165 | jest.runOnlyPendingTimers();
|
166 | };
|
167 | const requireFunction = isJest() ? require : () => {
|
168 | throw new ReanimatedError('`setUpTests` is available only in Jest environment.');
|
169 | };
|
170 | export const setUpTests = (userFramerateConfig = {}) => {
|
171 | let expect = global.expect;
|
172 | if (expect === undefined) {
|
173 | const expectModule = requireFunction('expect');
|
174 | expect = expectModule;
|
175 |
|
176 |
|
177 |
|
178 |
|
179 | if (typeof expect === 'object') {
|
180 | const jestGlobals = requireFunction('@jest/globals');
|
181 | expect = jestGlobals.expect;
|
182 | }
|
183 | if (expect === undefined || expect.extend === undefined) {
|
184 | expect = expectModule.default;
|
185 | }
|
186 | }
|
187 | const framerateConfig = {
|
188 | ...defaultFramerateConfig,
|
189 | ...userFramerateConfig
|
190 | };
|
191 | frameTime = Math.round(1000 / framerateConfig.fps);
|
192 | expect.extend({
|
193 | toHaveAnimatedStyle(component, expectedStyle, config = {}) {
|
194 | return compareStyle(component, expectedStyle, config);
|
195 | }
|
196 | });
|
197 | };
|
198 | export const getAnimatedStyle = component => {
|
199 | return getCurrentStyle(
|
200 |
|
201 |
|
202 | component);
|
203 | };
|
204 |
|
\ | No newline at end of file |