@applicaster/zapp-react-native-ui-components 14.0.0-alpha.1235043154 → 14.0.0-alpha.1308901965

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/Components/AnimatedInOut/index.tsx +3 -5
  2. package/Components/AudioPlayer/tv/Artwork.tsx +3 -2
  3. package/Components/AudioPlayer/tv/Channel.tsx +7 -7
  4. package/Components/AudioPlayer/tv/Layout.tsx +100 -93
  5. package/Components/AudioPlayer/tv/Runtime.tsx +7 -1
  6. package/Components/AudioPlayer/tv/Summary.tsx +6 -2
  7. package/Components/AudioPlayer/tv/Title.tsx +6 -2
  8. package/Components/AudioPlayer/tv/__tests__/__snapshots__/Runtime.test.js.snap +2 -2
  9. package/Components/AudioPlayer/tv/__tests__/__snapshots__/audioPlayer.test.js.snap +20 -26
  10. package/Components/AudioPlayer/tv/__tests__/__snapshots__/channel.test.js.snap +8 -17
  11. package/Components/AudioPlayer/tv/__tests__/__snapshots__/summary.test.js.snap +1 -2
  12. package/Components/AudioPlayer/tv/__tests__/__snapshots__/title.test.js.snap +1 -2
  13. package/Components/AudioPlayer/tv/index.tsx +6 -0
  14. package/Components/Cell/index.js +6 -2
  15. package/Components/Focusable/FocusableTvOS.tsx +3 -3
  16. package/Components/Focusable/__tests__/index.android.test.tsx +3 -0
  17. package/Components/Focusable/index.android.tsx +12 -8
  18. package/Components/HandlePlayable/HandlePlayable.tsx +8 -14
  19. package/Components/MasterCell/elementMapper.tsx +2 -1
  20. package/Components/MasterCell/index.tsx +1 -1
  21. package/Components/MasterCell/utils/behaviorProvider.ts +82 -14
  22. package/Components/MasterCell/utils/index.ts +23 -3
  23. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +18 -13
  24. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +0 -9
  25. package/Components/PlayerContainer/PlayerContainer.tsx +1 -1
  26. package/Components/River/ComponentsMap/ComponentsMap.tsx +1 -0
  27. package/Components/River/TV/withTVEventHandler.tsx +1 -1
  28. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +0 -2
  29. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +0 -34
  30. package/Components/Transitioner/Scene.tsx +1 -0
  31. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +9 -15
  32. package/Components/VideoLive/animationUtils.ts +3 -3
  33. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +16 -12
  34. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +24 -84
  35. package/Components/Viewport/VisibilitySensor/VisibilitySensor.tsx +3 -3
  36. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/index.ts +3 -3
  37. package/Contexts/ScreenDataContext/index.tsx +2 -0
  38. package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
  39. package/Decorators/RiverFeedLoader/index.tsx +8 -2
  40. package/Decorators/RiverFeedLoader/utils/index.ts +7 -2
  41. package/Decorators/ZappPipesDataConnector/index.tsx +20 -2
  42. package/package.json +6 -5
@@ -43,11 +43,13 @@ export const FocusableContext = React.createContext<
43
43
  // eslint-disable-next-line
44
44
  setIsFocusable: (enableFocus: boolean) => void;
45
45
  ref: FocusManager.FocusableRef;
46
+ parentFocusableId: Option<string>;
46
47
  } & ParentFocus
47
48
  >({
48
49
  focused: false,
49
50
  setIsFocusable: () => {},
50
51
  ref: { current: null },
52
+ parentFocusableId: undefined,
51
53
  });
52
54
 
53
55
  export const useFocusable = () => React.useContext(FocusableContext);
@@ -74,7 +76,7 @@ function FocusableComponent(props: Props, forwardedRef) {
74
76
 
75
77
  const isRTL = useIsRTL();
76
78
  const focusManager = useFocusManager();
77
- const { ref: parentFocusable } = useFocusable();
79
+ const { ref: parentFocusableRef, parentFocusableId } = useFocusable();
78
80
  const touchableRef = React.useRef(null);
79
81
 
80
82
  const [focused, setFocused] = React.useState(() =>
@@ -98,13 +100,14 @@ function FocusableComponent(props: Props, forwardedRef) {
98
100
  }
99
101
  }, [disableFocus]);
100
102
 
101
- React.useEffect(() => {
103
+ React.useLayoutEffect(() => {
102
104
  if (id) {
103
- const unregister = focusManager.registerFocusable(
105
+ const unregister = focusManager.registerFocusable({
104
106
  touchableRef,
105
- parentFocusable,
106
- isFocusableCell
107
- );
107
+ parentFocusableRef,
108
+ isFocusableCell,
109
+ parentFocusableId,
110
+ });
108
111
 
109
112
  onRegister();
110
113
 
@@ -112,7 +115,7 @@ function FocusableComponent(props: Props, forwardedRef) {
112
115
  unregister();
113
116
  };
114
117
  }
115
- }, [id, onRegister, isFocusableCell]);
118
+ }, [id, onRegister, isFocusableCell, parentFocusableId]);
116
119
 
117
120
  if (R.isNil(id)) {
118
121
  // eslint-disable-next-line no-console
@@ -164,8 +167,9 @@ function FocusableComponent(props: Props, forwardedRef) {
164
167
  ...parentFocus,
165
168
  ref: touchableRef,
166
169
  setIsFocusable,
170
+ parentFocusableId: id,
167
171
  };
168
- }, [parentFocus, focused]);
172
+ }, [parentFocus, focused, id]);
169
173
 
170
174
  return (
171
175
  <Touchable
@@ -13,7 +13,6 @@ import {
13
13
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
14
14
  import { PlayerContainer } from "../PlayerContainer";
15
15
  import { useModalSize } from "../VideoModal/hooks";
16
- import { ViewStyle } from "react-native";
17
16
 
18
17
  type Props = {
19
18
  item: ZappEntry;
@@ -141,19 +140,14 @@ export function HandlePlayable({
141
140
  const modalSize = useModalSize();
142
141
 
143
142
  const style = React.useMemo(
144
- () =>
145
- ({
146
- width: isModal
147
- ? modalSize.width
148
- : mode === "PIP"
149
- ? "100%"
150
- : screenWidth,
151
- height: isModal
152
- ? modalSize.height
153
- : mode === "PIP"
154
- ? "100%"
155
- : screenHeight,
156
- }) as ViewStyle,
143
+ () => ({
144
+ width: isModal ? modalSize.width : mode === "PIP" ? "100%" : screenWidth,
145
+ height: isModal
146
+ ? modalSize.height
147
+ : mode === "PIP"
148
+ ? "100%"
149
+ : screenHeight,
150
+ }),
157
151
  [screenWidth, screenHeight, modalSize, isModal, mode]
158
152
  );
159
153
 
@@ -73,6 +73,7 @@ export function elementMapper(
73
73
  : {};
74
74
 
75
75
  const componentProps = {
76
+ key,
76
77
  style,
77
78
  skipButtons: otherProps?.skipButtons,
78
79
  emitAsyncElementRegistrate: otherProps?.emitAsyncElementRegistrate,
@@ -90,7 +91,7 @@ export function elementMapper(
90
91
  const fn = mapElementWithKey(elementMapper(components, otherProps));
91
92
 
92
93
  return (
93
- <Component key={key} {...componentProps}>
94
+ <Component {...componentProps}>
94
95
  {focusableTypes.has(type) && elements.length > 0
95
96
  ? elements.map(fn)
96
97
  : null}
@@ -86,7 +86,7 @@ export function masterCellBuilder({
86
86
  entry: item,
87
87
  state: getEntryState(state, entryIsSelected),
88
88
  }),
89
- [state, item?.id, entryIsSelected] // Assuming that item won't mutate
89
+ [state, item, entryIsSelected] // Assuming that item won't mutate
90
90
  );
91
91
 
92
92
  const wrapperRef = React.useRef(null);
@@ -1,28 +1,58 @@
1
1
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
2
- import { StorageSingleValueProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageSingleSelectProvider";
2
+ import { StorageSingleValueProvider } from "@applicaster/zapp-react-native-utils/storage/StorageSingleSelectProvider";
3
3
  import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
4
- import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
4
+ import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-utils/storage/StorageMultiSelectProvider";
5
5
  import React, { useEffect } from "react";
6
6
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
7
7
  import { BehaviorSubject } from "rxjs";
8
8
  import { masterCellLogger } from "../logger";
9
9
  import get from "lodash/get";
10
-
11
- const parseContextKey = (key: string): string | null => {
12
- if (!key?.startsWith("@{ctx/")) return null;
13
-
14
- return key.substring("@{ctx/".length, key.length - 1);
10
+ import { ScreenMultiSelectProvider } from "@applicaster/zapp-react-native-utils/storage/ScreenStateMultiSelectProvider";
11
+ import { ScreenSingleValueProvider } from "@applicaster/zapp-react-native-utils/storage/ScreenSingleValueProvider";
12
+ import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks";
13
+ import { useScreenStateStore } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useScreenStateStore";
14
+
15
+ const parseContextKey = (
16
+ key: string,
17
+ context: string = "ctx"
18
+ ): string | null => {
19
+ if (!key?.startsWith(`@{${context}/`)) return null;
20
+
21
+ return key.substring(`@{${context}/`.length, key.length - 1);
15
22
  };
16
23
 
17
24
  const getDataSourceProvider = (
18
- behavior: Behavior
25
+ behavior: Behavior,
26
+ screenRoute: string,
27
+ screenStateStore: ScreenStateStore
19
28
  ): BehaviorSubject<string[] | string> | null => {
20
29
  if (!behavior) return null;
21
30
 
22
31
  const selection = String(behavior.current_selection);
32
+ const screenKey = parseContextKey(selection, "screen");
33
+
34
+ if (screenKey) {
35
+ if (behavior.select_mode === "multi") {
36
+ return ScreenMultiSelectProvider.getProvider(
37
+ screenKey,
38
+ screenRoute,
39
+ screenStateStore
40
+ ).getObservable();
41
+ }
42
+
43
+ if (behavior.select_mode === "single") {
44
+ return ScreenSingleValueProvider.getProvider(
45
+ screenKey,
46
+ screenRoute,
47
+ screenStateStore
48
+ ).getObservable();
49
+ }
50
+ }
51
+
23
52
  const contextKey = parseContextKey(selection);
24
53
 
25
54
  if (contextKey) {
55
+ // TODO: Add storage scope to behavior
26
56
  if (behavior.select_mode === "multi") {
27
57
  return StorageMultiSelectProvider.getProvider(contextKey).getObservable();
28
58
  }
@@ -41,6 +71,8 @@ const getDataSourceProvider = (
41
71
 
42
72
  export const useBehaviorUpdate = (behavior: Behavior) => {
43
73
  const [lastUpdate, setLastUpdate] = React.useState<number | null>(null);
74
+ const screenRoute = useRoute()?.pathname || "";
75
+ const screenStateStore = useScreenStateStore();
44
76
  const player = usePlayer();
45
77
 
46
78
  const triggerUpdate = () => setLastUpdate(Date.now());
@@ -48,7 +80,11 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
48
80
  useEffect(() => {
49
81
  if (!behavior) return;
50
82
 
51
- const dataSource = getDataSourceProvider(behavior);
83
+ const dataSource = getDataSourceProvider(
84
+ behavior,
85
+ screenRoute,
86
+ screenStateStore
87
+ );
52
88
 
53
89
  if (dataSource) {
54
90
  const subscription = dataSource.subscribe(triggerUpdate);
@@ -72,10 +108,17 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
72
108
 
73
109
  // We cant use async in this function (its inside render),
74
110
  // so we rely on useBehaviorUpdate to update current value and trigger re-render
75
- export const isCellSelected = (
76
- item: ZappEntry,
77
- behavior?: Behavior
78
- ): boolean => {
111
+ export const isCellSelected = ({
112
+ item,
113
+ screenRoute,
114
+ screenStateStore,
115
+ behavior,
116
+ }: {
117
+ item: ZappEntry;
118
+ screenRoute: string;
119
+ screenStateStore: ScreenStateStore;
120
+ behavior?: Behavior;
121
+ }): boolean => {
79
122
  if (!behavior) return false;
80
123
 
81
124
  const id = behavior.selector ? get(item, behavior.selector) : item.id;
@@ -99,7 +142,32 @@ export const isCellSelected = (
99
142
  }
100
143
 
101
144
  const selection = String(behavior.current_selection);
102
- const contextKey = parseContextKey(selection);
145
+
146
+ const screenKey = parseContextKey(selection, "screen");
147
+
148
+ if (screenKey) {
149
+ if (behavior.select_mode === "single") {
150
+ const selectedItem = ScreenSingleValueProvider.getProvider(
151
+ screenKey,
152
+ screenRoute,
153
+ screenStateStore
154
+ ).getValue();
155
+
156
+ return selectedItem === String(id);
157
+ }
158
+
159
+ if (behavior.select_mode === "multi") {
160
+ const selectedItems = ScreenMultiSelectProvider.getProvider(
161
+ screenKey,
162
+ screenRoute,
163
+ screenStateStore
164
+ ).getSelectedItems();
165
+
166
+ return selectedItems?.includes(String(id));
167
+ }
168
+ }
169
+
170
+ const contextKey = parseContextKey(selection, "ctx");
103
171
 
104
172
  if (contextKey) {
105
173
  if (behavior.select_mode === "single") {
@@ -8,6 +8,8 @@ import { masterCellLogger } from "../logger";
8
8
  import { getCellState } from "../../Cell/utils";
9
9
  import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
10
10
  import { isCellSelected, useBehaviorUpdate } from "./behaviorProvider";
11
+ import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks";
12
+ import { useScreenStateStore } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useScreenStateStore";
11
13
 
12
14
  const hasElementSpecificViewType = (viewType) => (element) => {
13
15
  if (R.isNil(element)) {
@@ -190,8 +192,18 @@ export const getFocusedButtonId = (focusable) => {
190
192
  });
191
193
  };
192
194
 
193
- export const isSelected = (item: ZappEntry, behavior?: Behavior) => {
194
- return isCellSelected(item, behavior);
195
+ export const isSelected = ({
196
+ item,
197
+ screenRoute,
198
+ screenStateStore,
199
+ behavior,
200
+ }: {
201
+ item: ZappEntry;
202
+ screenRoute: string;
203
+ screenStateStore: ScreenStateStore;
204
+ behavior?: Behavior;
205
+ }) => {
206
+ return isCellSelected({ item, screenRoute, screenStateStore, behavior });
195
207
  };
196
208
 
197
209
  export const useCellState = ({
@@ -204,9 +216,17 @@ export const useCellState = ({
204
216
  focused: boolean;
205
217
  }): CellState => {
206
218
  const lastUpdate = useBehaviorUpdate(behavior);
219
+ const router = useRoute();
220
+ const screenStateStore = useScreenStateStore();
207
221
 
208
222
  const _isSelected = useMemo(
209
- () => isSelected(item, behavior),
223
+ () =>
224
+ isSelected({
225
+ item,
226
+ screenRoute: router?.pathname,
227
+ screenStateStore,
228
+ behavior,
229
+ }),
210
230
  [behavior, item, lastUpdate]
211
231
  );
212
232
 
@@ -1,12 +1,9 @@
1
1
  import React from "react";
2
2
  import { Text, Animated } from "react-native";
3
- import { render } from "@testing-library/react-native";
4
3
 
5
- import {
6
- NotificationView,
7
- onlinePhrase,
8
- offlinePhrase,
9
- } from "../NotificationView";
4
+ import renderer from "react-test-renderer";
5
+
6
+ jest.useFakeTimers();
10
7
 
11
8
  jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
12
9
  usePickFromState: () => ({
@@ -35,31 +32,39 @@ jest.mock("react-native-safe-area-context", () => ({
35
32
 
36
33
  const dismiss = jest.fn();
37
34
 
35
+ const {
36
+ NotificationView,
37
+ onlinePhrase,
38
+ offlinePhrase,
39
+ } = require("../NotificationView");
40
+
38
41
  describe("NotificationView", () => {
39
42
  it("Show online message when Online", () => {
40
- const component = render(<NotificationView online dismiss={dismiss} />);
43
+ const component = renderer.create(
44
+ <NotificationView online dismiss={dismiss} />
45
+ );
41
46
 
42
- expect(component.UNSAFE_getByType(Text).props.children).toBe(onlinePhrase);
47
+ expect(component.root.findByType(Text).props.children).toBe(onlinePhrase);
43
48
  });
44
49
 
45
50
  it("Show offline message when Online", () => {
46
- const component = render(
51
+ const component = renderer.create(
47
52
  <NotificationView online={false} dismiss={dismiss} />
48
53
  );
49
54
 
50
- expect(component.UNSAFE_getByType(Text).props.children).toBe(offlinePhrase);
55
+ expect(component.root.findByType(Text).props.children).toBe(offlinePhrase);
51
56
  });
52
57
 
53
58
  it("When hidden is false to true notification is visible", () => {
54
- const component = render(
59
+ const component = renderer.create(
55
60
  <NotificationView online={false} hidden={false} dismiss={dismiss} />
56
61
  );
57
62
 
58
- component.rerender(
63
+ component.update(
59
64
  <NotificationView online={false} hidden={true} dismiss={dismiss} />
60
65
  );
61
66
 
62
- const animatedView = component.UNSAFE_getByType(Animated.View);
67
+ const animatedView = component.root.findByType(Animated.View);
63
68
  const animatedViewStyles = animatedView.props.style;
64
69
 
65
70
  expect(animatedViewStyles.opacity).toBe(1);
@@ -21,15 +21,6 @@ exports[`OfflineHandler renders 1`] = `
21
21
  }
22
22
  >
23
23
  <View
24
- accessibilityState={
25
- {
26
- "busy": undefined,
27
- "checked": undefined,
28
- "disabled": undefined,
29
- "expanded": undefined,
30
- "selected": undefined,
31
- }
32
- }
33
24
  accessible={true}
34
25
  collapsable={false}
35
26
  focusable={true}
@@ -627,7 +627,7 @@ const PlayerContainerComponent = (props: Props) => {
627
627
  <PlayerContainerContext.Consumer>
628
628
  {(context) => (
629
629
  <TVEventHandlerComponent
630
- tvEventHandler={(event) =>
630
+ tvEventHandler={(_component, event) =>
631
631
  playerRemoteHandler(event, context.isLanguageOverlayVisible)
632
632
  }
633
633
  >
@@ -286,6 +286,7 @@ function ComponentsMapComponent(props: Props) {
286
286
  initialNumToRender={3}
287
287
  maxToRenderPerBatch={10}
288
288
  windowSize={12}
289
+ listKey={riverId}
289
290
  keyExtractor={keyExtractor}
290
291
  renderItem={renderRiverItem}
291
292
  data={riverComponents}
@@ -8,7 +8,7 @@ export const withTvEventHandler = (Component) => {
8
8
  return function WithTVEventHandler(props) {
9
9
  const navigator = useNavigation();
10
10
 
11
- const remoteHandler = (event) => {
11
+ const remoteHandler = (_, event) => {
12
12
  const { eventType } = event;
13
13
 
14
14
  const canGoBack = navigator.canGoBack();
@@ -159,7 +159,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
159
159
  >
160
160
  <View>
161
161
  <View
162
- onFocusCapture={[Function]}
163
162
  onLayout={[Function]}
164
163
  style={null}
165
164
  >
@@ -175,7 +174,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
175
174
  </View>
176
175
  </View>
177
176
  <View
178
- onFocusCapture={[Function]}
179
177
  onLayout={[Function]}
180
178
  style={null}
181
179
  >
@@ -3,23 +3,6 @@
3
3
  exports[`<Touchable /> when not running in automated tests environment renders correctly 1`] = `
4
4
  <View
5
5
  accessibilityLabel="some-test-id"
6
- accessibilityState={
7
- {
8
- "busy": undefined,
9
- "checked": undefined,
10
- "disabled": undefined,
11
- "expanded": undefined,
12
- "selected": undefined,
13
- }
14
- }
15
- accessibilityValue={
16
- {
17
- "max": undefined,
18
- "min": undefined,
19
- "now": undefined,
20
- "text": undefined,
21
- }
22
- }
23
6
  accessible={true}
24
7
  collapsable={false}
25
8
  focusable={true}
@@ -46,23 +29,6 @@ exports[`<Touchable /> when not running in automated tests environment renders c
46
29
  exports[`<Touchable /> when running in automated tests environment has accessible flag set to false 1`] = `
47
30
  <View
48
31
  accessibilityLabel="some-test-id"
49
- accessibilityState={
50
- {
51
- "busy": undefined,
52
- "checked": undefined,
53
- "disabled": undefined,
54
- "expanded": undefined,
55
- "selected": undefined,
56
- }
57
- }
58
- accessibilityValue={
59
- {
60
- "max": undefined,
61
- "min": undefined,
62
- "now": undefined,
63
- "text": undefined,
64
- }
65
- }
66
32
  accessible={false}
67
33
  collapsable={false}
68
34
  focusable={true}
@@ -36,6 +36,7 @@ export function CurrentScreenContextProvider({
36
36
  screenData: NavigationScreenData;
37
37
  }) {
38
38
  const { pathname, isActive = false, screenData } = props;
39
+ console.log("CurrentScreenContextProvider", { screenData });
39
40
 
40
41
  const [initialScreenData, setInitialScreenData] = React.useState(screenData);
41
42
 
@@ -6,21 +6,15 @@ exports[`<Scene /> renders correctly 1`] = `
6
6
  collapsable={false}
7
7
  pointerEvents="auto"
8
8
  style={
9
- [
10
- {
11
- "flex": 1,
12
- },
13
- {
14
- "paddingBottom": 49,
15
- },
16
- {
17
- "fontScale": 2,
18
- "height": 1334,
19
- "scale": 2,
20
- "statusBarHeight": null,
21
- "width": 750,
22
- },
23
- ]
9
+ {
10
+ "flex": 1,
11
+ "fontScale": 2,
12
+ "height": 1334,
13
+ "paddingBottom": 49,
14
+ "scale": 2,
15
+ "statusBarHeight": null,
16
+ "width": 750,
17
+ }
24
18
  }
25
19
  />
26
20
  </View>
@@ -1,8 +1,8 @@
1
1
  import { Animated, Easing, EasingFunction, StyleProp } from "react-native";
2
2
 
3
3
  type AnimatedInterpolatedStyle =
4
- | Animated.AnimatedInterpolation<number>
5
- | [{ [Key: string]: Animated.AnimatedInterpolation<number> }];
4
+ | Animated.AnimatedInterpolation
5
+ | [{ [Key: string]: Animated.AnimatedInterpolation }];
6
6
 
7
7
  type AnimationConfig = {
8
8
  duration: number;
@@ -31,7 +31,7 @@ const interpolate = (
31
31
  animatedValue: Animated.Value,
32
32
  from: number = 0,
33
33
  to: number = 1
34
- ): Animated.AnimatedInterpolation<number> =>
34
+ ): Animated.AnimatedInterpolation =>
35
35
  animatedValue.interpolate({
36
36
  inputRange: [0, 1],
37
37
  outputRange: [from, to],
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from "react";
4
4
 
5
- import { act, render } from "@testing-library/react-native";
5
+ import { act, create as render } from "react-test-renderer";
6
6
 
7
7
  import { ViewportAware } from "../";
8
8
  import { ViewportTracker } from "../../ViewportTracker";
@@ -12,17 +12,21 @@ import ReactNative from "react-native";
12
12
 
13
13
  jest.useFakeTimers();
14
14
 
15
- const { ScrollView } = ReactNative;
16
-
17
- jest.spyOn(ReactNative, "findNodeHandle").mockImplementation(() => 1234);
15
+ jest.mock("react-native/Libraries/ReactNative/UIManager", () => {
16
+ return {
17
+ ...jest.requireActual("react-native/Libraries/ReactNative/NativeUIManager"),
18
+ measureLayout: (handle, parent, error, success) => {
19
+ success(100, 100, 400, 400);
20
+ },
21
+ };
22
+ });
18
23
 
19
- ReactNative.UIManager.measureLayout = jest.fn(
20
- (handle, parent, error, success) => {
21
- success(100, 100, 400, 400);
22
- }
23
- );
24
+ jest.mock("react-native/Libraries/Renderer/shims/ReactNative", () => ({
25
+ ...jest.requireActual("react-native/Libraries/Renderer/shims/ReactNative"),
26
+ findNodeHandle: () => 1234,
27
+ }));
24
28
 
25
- ReactNative.findNodeHandle = () => 1234;
29
+ const { ScrollView } = ReactNative;
26
30
 
27
31
  const viewportEventsManager = new ViewportEvents(true);
28
32
 
@@ -134,7 +138,7 @@ describe("<ViewportAware />", () => {
134
138
  expect(wrapper.toJSON()).toMatchSnapshot();
135
139
  expect(onViewportEnter).toHaveBeenCalled();
136
140
 
137
- const scrollviews = wrapper.UNSAFE_getAllByType(ScrollView);
141
+ const scrollviews = wrapper.root.findAllByType(ScrollView);
138
142
  expect(scrollviews).toBeArray();
139
143
  expect(scrollviews).toHaveProperty("length", 2);
140
144
 
@@ -175,7 +179,7 @@ describe("<ViewportAware />", () => {
175
179
 
176
180
  expect(wrapper.toJSON()).toMatchSnapshot();
177
181
 
178
- const scrollviews = wrapper.UNSAFE_getAllByType(ScrollView);
182
+ const scrollviews = wrapper.root.findAllByType(ScrollView);
179
183
  expect(scrollviews).toBeArray();
180
184
  expect(scrollviews).toHaveProperty("length", 2);
181
185