UNPKG

6.6 kBJavaScriptView Raw
1/* eslint-disable @typescript-eslint/no-namespace */
2'use strict';
3
4import { isJest } from "./PlatformChecker.js";
5import { ReanimatedError } from "./errors.js";
6const defaultFramerateConfig = {
7 fps: 60
8};
9const isEmpty = obj => Object.keys(obj).length === 0;
10const getStylesFromObject = obj => {
11 return obj === undefined ? {} : Object.fromEntries(Object.entries(obj).map(([property, value]) => [property, value._isReanimatedSharedValue ? value.value : value]));
12};
13const getCurrentStyle = component => {
14 const styleObject = component.props.style;
15 let currentStyle = {};
16 if (Array.isArray(styleObject)) {
17 // It is possible that style may contain nested arrays. Currently, neither `StyleSheet.flatten` nor `flattenArray` solve this issue.
18 // Hence, we're not handling nested arrays at the moment - this is a known limitation of the current implementation.
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};
57const 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};
81const 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 // eslint-disable-next-line @typescript-eslint/no-shadow
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};
114const 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};
143let frameTime = Math.round(1000 / defaultFramerateConfig.fps);
144const beforeTest = () => {
145 jest.useFakeTimers();
146};
147const afterTest = () => {
148 jest.runOnlyPendingTimers();
149 jest.useRealTimers();
150};
151export 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};
157export const advanceAnimationByTime = (time = frameTime) => {
158 console.warn('This method is deprecated, use jest.advanceTimersByTime directly');
159 jest.advanceTimersByTime(time);
160 jest.runOnlyPendingTimers();
161};
162export const advanceAnimationByFrame = count => {
163 console.warn('This method is deprecated, use jest.advanceTimersByTime directly');
164 jest.advanceTimersByTime(count * frameTime);
165 jest.runOnlyPendingTimers();
166};
167const requireFunction = isJest() ? require : () => {
168 throw new ReanimatedError('`setUpTests` is available only in Jest environment.');
169};
170export const setUpTests = (userFramerateConfig = {}) => {
171 let expect = global.expect;
172 if (expect === undefined) {
173 const expectModule = requireFunction('expect');
174 expect = expectModule;
175 // Starting from Jest 28, "expect" package uses named exports instead of default export.
176 // So, requiring "expect" package doesn't give direct access to "expect" function anymore.
177 // It gives access to the module object instead.
178 // We use this info to detect if the project uses Jest 28 or higher.
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};
198export const getAnimatedStyle = component => {
199 return getCurrentStyle(
200 // This type assertion is needed to get type checking in the following
201 // functions since `ReactTestInstance` has its `props` defined as `any`.
202 component);
203};
204//# sourceMappingURL=jestUtils.js.map
\No newline at end of file