@applicaster/zapp-react-native-ui-components 12.0.0-rc.99 → 13.0.0-alpha.2330880002

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 (63) hide show
  1. package/Components/Cell/Cell.tsx +29 -10
  2. package/Components/Focusable/__tests__/index.android.test.tsx +72 -0
  3. package/Components/Focusable/index.android.tsx +15 -9
  4. package/Components/FocusableList/FocusableChild.ts +2 -2
  5. package/Components/FocusableList/index.tsx +11 -12
  6. package/Components/FocusableScrollView/index.tsx +1 -1
  7. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  8. package/Components/FreezeWithCallback/LICENSE +21 -0
  9. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  10. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  11. package/Components/FreezeWithCallback/index.tsx +3 -0
  12. package/Components/Image/Image.android.tsx +1 -1
  13. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +11 -7
  14. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -7
  15. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +6 -1
  16. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +12 -0
  17. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +6 -5
  18. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +2 -2
  19. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  20. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  21. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  22. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  23. package/Components/MasterCell/dataAdapter.ts +21 -7
  24. package/Components/MasterCell/index.tsx +5 -3
  25. package/Components/MasterCell/utils/index.ts +3 -4
  26. package/Components/PlayerContainer/PlayerContainer.tsx +14 -8
  27. package/Components/Screen/TV/hooks/index.ts +0 -2
  28. package/Components/Screen/TV/index.web.tsx +32 -19
  29. package/Components/Screen/__tests__/Screen.test.tsx +0 -49
  30. package/Components/Screen/index.tsx +2 -20
  31. package/Components/Screen/navigationHandler.ts +1 -3
  32. package/Components/Screen/orientationHandler.ts +18 -7
  33. package/Components/Screen/utils.ts +16 -0
  34. package/Components/ScreenResolver/index.tsx +6 -11
  35. package/Components/Transitioner/Scene.tsx +9 -2
  36. package/Components/Transitioner/Transitioner.tsx +38 -23
  37. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  38. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  39. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +5 -0
  40. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +3 -9
  41. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +87 -41
  42. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +20 -9
  43. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +41 -22
  44. package/Components/VideoModal/PlayerDetails.tsx +16 -2
  45. package/Components/VideoModal/PlayerWrapper.tsx +101 -67
  46. package/Components/VideoModal/VideoModal.tsx +33 -27
  47. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +7 -0
  48. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -0
  49. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +78 -16
  50. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +7 -3
  51. package/Components/ZappFrameworkComponents/BarView/Buttons/BackButton.tsx +7 -2
  52. package/Components/ZappFrameworkComponents/BarView/Buttons/CloseButton.tsx +7 -2
  53. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +87 -0
  54. package/Components/ZappFrameworkComponents/Buttons/ActionButton.tsx +9 -4
  55. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  56. package/Contexts/CachedDimensionsContext/index.ts +13 -9
  57. package/Contexts/ConfirmDialogState/index.ts +1 -1
  58. package/Contexts/ScreenContext/index.tsx +6 -1
  59. package/README.md +1 -13
  60. package/const.ts +6 -0
  61. package/index.js +3 -0
  62. package/package.json +5 -5
  63. package/Components/Screen/TV/hooks/useRestoreFocus.ts +0 -22
@@ -7,14 +7,10 @@ import {
7
7
  ViewStyle,
8
8
  } from "react-native";
9
9
  import { Edge, SafeAreaView } from "react-native-safe-area-context";
10
-
11
10
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
12
11
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
13
12
  import { PlayerDetails } from "./PlayerDetails";
14
13
  import { playerDimesionsHack } from "./utils";
15
- import { PathnameContext } from "../../Contexts/PathnameContext";
16
- import { ScreenContextProvider } from "../../Contexts/ScreenContext";
17
- import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
18
14
 
19
15
  import {
20
16
  AnimatedScrollModal,
@@ -23,6 +19,8 @@ import {
23
19
  ComponentAnimationType,
24
20
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
25
21
 
22
+ const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("screen");
23
+
26
24
  type DimensionsT = {
27
25
  width: number | string;
28
26
  height: number | string | undefined;
@@ -69,10 +67,8 @@ const directionStyles = (isTabletLandscape: boolean): ViewStyle => {
69
67
  };
70
68
 
71
69
  const getScreenAspectRatio = () => {
72
- const { width, height } = Dimensions.get("screen");
73
-
74
- const longEdge = Math.max(width, height);
75
- const shortEdge = Math.min(width, height);
70
+ const longEdge = Math.max(SCREEN_WIDTH, SCREEN_HEIGHT);
71
+ const shortEdge = Math.min(SCREEN_WIDTH, SCREEN_HEIGHT);
76
72
 
77
73
  return longEdge / shortEdge;
78
74
  };
@@ -125,10 +121,54 @@ const getTabletWidth = (
125
121
  return Number(width) - sidebarWidth;
126
122
  };
127
123
 
128
- export const PlayerWrapper = (props: Props) => {
124
+ const getStyles = (baseStyle, isMobile, isPortrait, pip) => {
125
+ if (pip) {
126
+ return baseStyle;
127
+ }
128
+
129
+ if (isMobile && isPortrait) {
130
+ return { width: SCREEN_WIDTH, height: SCREEN_HEIGHT };
131
+ }
132
+
133
+ if (isMobile && !isPortrait) {
134
+ return { width: SCREEN_HEIGHT, height: SCREEN_WIDTH };
135
+ }
136
+
137
+ return baseStyle;
138
+ };
139
+
140
+ const showDetails = (
141
+ isMobile: boolean,
142
+ docked: boolean,
143
+ isInlineModal,
144
+ pip
145
+ ): boolean => {
146
+ if (pip) {
147
+ return false;
148
+ }
149
+
150
+ if (!isInlineModal) {
151
+ return false;
152
+ }
153
+
154
+ // for mobile we always show details. Mounting of it very heavy operation.
155
+ if (isMobile) {
156
+ return true;
157
+ }
158
+
159
+ // workaround for tablets we need to mount/unmount in order to avoid PlayerDetails content dissappearing
160
+ // FIXME - find out the reason of dissapearing of content
161
+ if (docked) {
162
+ return false;
163
+ }
164
+
165
+ return true;
166
+ };
167
+
168
+ const PlayerWrapperComponent = (props: Props) => {
129
169
  const {
130
170
  entry,
131
- style,
171
+ style: baseStyle,
132
172
  containerStyle,
133
173
  inline,
134
174
  docked,
@@ -143,6 +183,8 @@ export const PlayerWrapper = (props: Props) => {
143
183
 
144
184
  const isInlineModal = inline && isModal;
145
185
 
186
+ const style = getStyles(baseStyle, !isTablet, isInlineModal, pip);
187
+
146
188
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
147
189
 
148
190
  const tabletWidth = getTabletWidth(configuration, style);
@@ -181,71 +223,63 @@ export const PlayerWrapper = (props: Props) => {
181
223
  [containerDimensions, playerDimesionsHack]
182
224
  );
183
225
 
184
- const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${entry?.id}`;
185
-
186
226
  return (
187
- <PathnameContext.Provider value={pathname}>
188
- <ScreenContextProvider pathname={pathname}>
189
- <WrapperView
190
- edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
227
+ <WrapperView
228
+ edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
229
+ style={[
230
+ safeAreaStyles(configuration, isTablet),
231
+ style,
232
+ playerDimesionsHack,
233
+ ]}
234
+ >
235
+ <AnimationComponent
236
+ animationType={ComponentAnimationType.moveUpComponent}
237
+ additionalData={{ saveArea: true }}
238
+ style={[directionStyles(isTabletLandscape), defaultStyles.flex]}
239
+ >
240
+ <View
241
+ testID={`${entry?.id}-player-container`}
191
242
  style={[
192
- safeAreaStyles(configuration, isTablet),
193
- style,
243
+ defaultStyles.playerContainer,
244
+ containerDimensions,
245
+ containerStyle,
194
246
  playerDimesionsHack,
195
247
  ]}
196
248
  >
197
249
  <AnimationComponent
198
250
  animationType={ComponentAnimationType.moveUpComponent}
199
- additionalData={{ saveArea: true }}
200
- style={[directionStyles(isTabletLandscape), defaultStyles.flex]}
251
+ style={isTabletLandscape ? defaultStyles.flex : undefined}
252
+ additionalData={{
253
+ useLayoutMeasure: isTabletLandscape,
254
+ disableAnimatedComponent: !isTabletLandscape,
255
+ resetAnimationValue: isTabletLandscape && docked,
256
+ }}
201
257
  >
202
- <PathnameContext.Provider value={pathname}>
203
- <ScreenContextProvider pathname={pathname}>
204
- <View
205
- testID={`${entry?.id}-player-container`}
206
- style={[
207
- defaultStyles.playerContainer,
208
- containerDimensions,
209
- containerStyle,
210
- playerDimesionsHack,
211
- ]}
212
- >
213
- <AnimationComponent
214
- animationType={ComponentAnimationType.moveUpComponent}
215
- style={isTabletLandscape ? defaultStyles.flex : undefined}
216
- additionalData={{
217
- useLayoutMeasure: isTabletLandscape,
218
- disableAnimatedComponent: !isTabletLandscape,
219
- resetAnimationValue: isTabletLandscape && docked,
220
- }}
221
- >
222
- <AnimatedVideoPlayerComponent>
223
- {children(childrenStyles)}
224
- </AnimatedVideoPlayerComponent>
225
- </AnimationComponent>
226
- </View>
227
- <AnimatedScrollModal>
228
- {isInlineModal && !docked ? (
229
- <AnimationComponent
230
- animationType={ComponentAnimationType.componentFade}
231
- style={defaultStyles.flex}
232
- >
233
- <PlayerDetails
234
- configuration={configuration}
235
- style={defaultStyles.playerDetails}
236
- entry={entry}
237
- isTabletLandscape={isTabletLandscape}
238
- />
239
- </AnimationComponent>
240
- ) : (
241
- <View style={defaultStyles.playerDetails} />
242
- )}
243
- </AnimatedScrollModal>
244
- </ScreenContextProvider>
245
- </PathnameContext.Provider>
258
+ <AnimatedVideoPlayerComponent>
259
+ {children(childrenStyles)}
260
+ </AnimatedVideoPlayerComponent>
246
261
  </AnimationComponent>
247
- </WrapperView>
248
- </ScreenContextProvider>
249
- </PathnameContext.Provider>
262
+ </View>
263
+
264
+ <AnimatedScrollModal>
265
+ {showDetails(!isTablet, docked, isInlineModal, pip) && (
266
+ <AnimationComponent
267
+ animationType={ComponentAnimationType.componentFade}
268
+ style={defaultStyles.flex}
269
+ >
270
+ <PlayerDetails
271
+ configuration={configuration}
272
+ style={defaultStyles.playerDetails}
273
+ entry={entry}
274
+ isTabletLandscape={isTabletLandscape}
275
+ isTablet={isTablet}
276
+ />
277
+ </AnimationComponent>
278
+ )}
279
+ </AnimatedScrollModal>
280
+ </AnimationComponent>
281
+ </WrapperView>
250
282
  );
251
283
  };
284
+
285
+ export const PlayerWrapper = PlayerWrapperComponent;
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import * as R from "ramda";
3
- import { StyleSheet, View } from "react-native";
3
+ import { StyleSheet, View, StatusBar } from "react-native";
4
4
 
5
5
  import { HandlePlayable } from "@applicaster/zapp-react-native-ui-components/Components/HandlePlayable";
6
6
  import {
@@ -129,32 +129,38 @@ const VideoModalComponent = () => {
129
129
  const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${item?.id}`;
130
130
 
131
131
  return (
132
- <PathnameContext.Provider value={pathname}>
133
- <ScreenContextProvider pathname={pathname}>
134
- {itemIdHooksFinished === item?.id ? (
135
- <AnimatedPlayerModalWrapper
136
- style={[
137
- styles.container,
138
- {
139
- backgroundColor,
140
- },
141
- ]}
142
- >
143
- <HandlePlayable
144
- item={item}
145
- isModal={mode !== "PIP"}
146
- modalHeight={modalSize.height}
147
- modalWidth={modalSize.width}
148
- mode={mode}
149
- />
150
- </AnimatedPlayerModalWrapper>
151
- ) : (
152
- <View style={styles.loaderContainer}>
153
- <Spinner />
154
- </View>
155
- )}
156
- </ScreenContextProvider>
157
- </PathnameContext.Provider>
132
+ <>
133
+ {/* TODO: Workaround to avoid unnecessary UI effect when switching from portrait to fullscreen */}
134
+ <StatusBar hidden={false} />
135
+ {/* TODO: Workaround to avoid unnecessary UI effect when switching from portrait to fullscreen */}
136
+
137
+ <PathnameContext.Provider value={pathname}>
138
+ <ScreenContextProvider pathname={pathname}>
139
+ {itemIdHooksFinished === item?.id ? (
140
+ <AnimatedPlayerModalWrapper
141
+ style={[
142
+ styles.container,
143
+ {
144
+ backgroundColor,
145
+ },
146
+ ]}
147
+ >
148
+ <HandlePlayable
149
+ item={item}
150
+ isModal={mode !== "PIP"}
151
+ modalHeight={modalSize.height}
152
+ modalWidth={modalSize.width}
153
+ mode={mode}
154
+ />
155
+ </AnimatedPlayerModalWrapper>
156
+ ) : (
157
+ <View style={styles.loaderContainer}>
158
+ <Spinner />
159
+ </View>
160
+ )}
161
+ </ScreenContextProvider>
162
+ </PathnameContext.Provider>
163
+ </>
158
164
  );
159
165
  };
160
166
 
@@ -8,6 +8,13 @@ const props = {
8
8
  configuration: { modal_background_color: "transparent" },
9
9
  };
10
10
 
11
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/layout", () => ({
12
+ useDimensions: jest.fn(() => ({
13
+ width: 20,
14
+ height: 30,
15
+ })),
16
+ }));
17
+
11
18
  jest.mock("react-native-safe-area-context", () => ({
12
19
  useSafeAreaInsets: jest.fn(() => ({
13
20
  top: 20,
@@ -9,6 +9,7 @@ exports[`PlayerDetails renders properly 1`] = `
9
9
  "flex": 1,
10
10
  "marginTop": -8,
11
11
  "paddingTop": -8,
12
+ "width": 750,
12
13
  }
13
14
  }
14
15
  >
@@ -29,6 +30,7 @@ exports[`PlayerDetails renders properly on tablet in landscape orientation 1`] =
29
30
  "flex": 1,
30
31
  "marginTop": -20,
31
32
  "paddingTop": 40,
33
+ "width": 750,
32
34
  }
33
35
  }
34
36
  >
@@ -27,8 +27,8 @@ exports[`PlayerWrapper renders inline 1`] = `
27
27
  "backgroundColor": "transparent",
28
28
  },
29
29
  Object {
30
- "height": 800,
31
- "width": 300,
30
+ "height": 1334,
31
+ "width": 750,
32
32
  },
33
33
  Object {},
34
34
  ]
@@ -72,12 +72,35 @@ exports[`PlayerWrapper renders inline 1`] = `
72
72
  testID="test-player-container"
73
73
  />
74
74
  <View
75
+ animationType="componentFade"
75
76
  style={
76
77
  Object {
77
78
  "flex": 1,
78
79
  }
79
80
  }
80
- />
81
+ >
82
+ <View
83
+ configuration={
84
+ Object {
85
+ "tablet_landscape_player_container_background_color": "red",
86
+ "tablet_landscape_sidebar_width": "35%",
87
+ }
88
+ }
89
+ entry={
90
+ Object {
91
+ "id": "test",
92
+ }
93
+ }
94
+ isTablet={false}
95
+ isTabletLandscape={false}
96
+ style={
97
+ Object {
98
+ "flex": 1,
99
+ "paddingTop": 20,
100
+ }
101
+ }
102
+ />
103
+ </View>
81
104
  </View>
82
105
  </RNCSafeAreaView>
83
106
  </RNCSafeAreaProvider>
@@ -110,8 +133,8 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
110
133
  "backgroundColor": "transparent",
111
134
  },
112
135
  Object {
113
- "height": undefined,
114
- "width": 300,
136
+ "height": 1334,
137
+ "width": 750,
115
138
  },
116
139
  Object {},
117
140
  ]
@@ -155,12 +178,35 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
155
178
  testID="test-player-container"
156
179
  />
157
180
  <View
181
+ animationType="componentFade"
158
182
  style={
159
183
  Object {
160
184
  "flex": 1,
161
185
  }
162
186
  }
163
- />
187
+ >
188
+ <View
189
+ configuration={
190
+ Object {
191
+ "tablet_landscape_player_container_background_color": "red",
192
+ "tablet_landscape_sidebar_width": "35%",
193
+ }
194
+ }
195
+ entry={
196
+ Object {
197
+ "id": "test",
198
+ }
199
+ }
200
+ isTablet={false}
201
+ isTabletLandscape={false}
202
+ style={
203
+ Object {
204
+ "flex": 1,
205
+ "paddingTop": 20,
206
+ }
207
+ }
208
+ />
209
+ </View>
164
210
  </View>
165
211
  </RNCSafeAreaView>
166
212
  </RNCSafeAreaProvider>
@@ -254,12 +300,35 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
254
300
  />
255
301
  </View>
256
302
  <View
303
+ animationType="componentFade"
257
304
  style={
258
305
  Object {
259
306
  "flex": 1,
260
307
  }
261
308
  }
262
- />
309
+ >
310
+ <View
311
+ configuration={
312
+ Object {
313
+ "tablet_landscape_player_container_background_color": "red",
314
+ "tablet_landscape_sidebar_width": "35%",
315
+ }
316
+ }
317
+ entry={
318
+ Object {
319
+ "id": "test",
320
+ }
321
+ }
322
+ isTablet={true}
323
+ isTabletLandscape={true}
324
+ style={
325
+ Object {
326
+ "flex": 1,
327
+ "paddingTop": 20,
328
+ }
329
+ }
330
+ />
331
+ </View>
263
332
  </View>
264
333
  </RNCSafeAreaView>
265
334
  </RNCSafeAreaProvider>
@@ -292,8 +361,8 @@ exports[`PlayerWrapper renders properly 1`] = `
292
361
  "backgroundColor": "transparent",
293
362
  },
294
363
  Object {
295
- "height": 800,
296
- "width": 300,
364
+ "height": 750,
365
+ "width": 1334,
297
366
  },
298
367
  Object {},
299
368
  ]
@@ -336,13 +405,6 @@ exports[`PlayerWrapper renders properly 1`] = `
336
405
  }
337
406
  testID="test-player-container"
338
407
  />
339
- <View
340
- style={
341
- Object {
342
- "flex": 1,
343
- }
344
- }
345
- />
346
408
  </View>
347
409
  </RNCSafeAreaView>
348
410
  </RNCSafeAreaProvider>
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
- import { View, StyleSheet } from "react-native";
2
+ import { StyleSheet } from "react-native";
3
+ import { SafeAreaView } from "react-native-safe-area-context";
3
4
 
4
5
  import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
5
6
  import CloseButton from "./Buttons/CloseButton";
@@ -44,11 +45,14 @@ const BarView = ({ screenStyles, barState = defaultState }: Props) => {
44
45
  );
45
46
 
46
47
  return (
47
- <View style={[style.view, isRTL ? style.rtlStyle : {}]}>
48
+ <SafeAreaView
49
+ style={[style.view, isRTL ? style.rtlStyle : {}]}
50
+ testID="BarView-safeAreaView"
51
+ >
48
52
  {backButton}
49
53
  <BarTitle title={barState.title} screenStyles={screenStyles} />
50
54
  {closeButton}
51
- </View>
55
+ </SafeAreaView>
52
56
  );
53
57
  };
54
58
 
@@ -11,12 +11,16 @@ const renderEmptyView = () => {
11
11
  return <View style={emptyViewStyle} />;
12
12
  };
13
13
 
14
- type FloatingButtonProps = {
14
+ type FloatingButtonProps = Testable & {
15
15
  onPress: () => void;
16
16
  screenStyles: any;
17
17
  };
18
18
 
19
- const BackButton = ({ onPress, screenStyles }: FloatingButtonProps) => {
19
+ const BackButton = ({
20
+ onPress,
21
+ screenStyles,
22
+ testID = "backButton",
23
+ }: FloatingButtonProps) => {
20
24
  const containerStyle: any = {};
21
25
 
22
26
  if (!onPress) {
@@ -25,6 +29,7 @@ const BackButton = ({ onPress, screenStyles }: FloatingButtonProps) => {
25
29
 
26
30
  return (
27
31
  <ActionButton
32
+ testID={`${testID}-actionButton`}
28
33
  onPress={onPress}
29
34
  buttonStyles={containerStyle}
30
35
  imageUrl={screenStyles.back_button_image}
@@ -11,12 +11,16 @@ const renderEmptyView = () => {
11
11
  return <View style={emptyViewStyle} />;
12
12
  };
13
13
 
14
- type CloseButtonProps = {
14
+ type CloseButtonProps = Testable & {
15
15
  onPress: () => void;
16
16
  screenStyles?: any;
17
17
  };
18
18
 
19
- const CloseButton = ({ onPress, screenStyles }: CloseButtonProps) => {
19
+ const CloseButton = ({
20
+ onPress,
21
+ screenStyles,
22
+ testID = "closeButton",
23
+ }: CloseButtonProps) => {
20
24
  const containerStyle: any = {};
21
25
 
22
26
  if (!onPress) {
@@ -25,6 +29,7 @@ const CloseButton = ({ onPress, screenStyles }: CloseButtonProps) => {
25
29
 
26
30
  return (
27
31
  <ActionButton
32
+ testID={`${testID}-actionButton`}
28
33
  onPress={onPress}
29
34
  buttonStyles={containerStyle}
30
35
  imageUrl={screenStyles.close_button_image}
@@ -0,0 +1,87 @@
1
+ import React from "react";
2
+ import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
3
+ import { fireEvent } from "@testing-library/react-native";
4
+
5
+ const mockUseIsRTL = jest.fn(() => true);
6
+
7
+ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
8
+ useIsRTL: mockUseIsRTL,
9
+ }));
10
+
11
+ const BarView = require("../BarView").default;
12
+
13
+ describe("BarView", () => {
14
+ const screenStyles = {
15
+ title_font_color: "#000",
16
+ title_font_android: "Roboto",
17
+ title_font_ios: "San Francisco",
18
+ title_font_size: "16",
19
+ background_color: "#fff",
20
+ };
21
+
22
+ const barState = {
23
+ backHandler: jest.fn(),
24
+ closeHandler: jest.fn(),
25
+ title: "Test Title",
26
+ };
27
+
28
+ beforeEach(() => {
29
+ jest.clearAllMocks();
30
+ });
31
+
32
+ it("renders without crashing", () => {
33
+ mockUseIsRTL.mockReturnValue(false);
34
+
35
+ const { getByText } = renderWithProviders(
36
+ <BarView screenStyles={screenStyles} barState={barState} />
37
+ );
38
+
39
+ expect(getByText("Test Title")).toBeTruthy();
40
+ });
41
+
42
+ it("applies RTL styles when isRTL is true", () => {
43
+ mockUseIsRTL.mockReturnValue(true);
44
+
45
+ const { getByTestId } = renderWithProviders(
46
+ <BarView screenStyles={screenStyles} barState={barState} />
47
+ );
48
+
49
+ expect(getByTestId("BarView-safeAreaView").props.style).toContainEqual({
50
+ transform: [{ scaleX: -1 }],
51
+ });
52
+ });
53
+
54
+ it("does not apply RTL styles when isRTL is false", () => {
55
+ mockUseIsRTL.mockReturnValue(false);
56
+
57
+ const { getByTestId } = renderWithProviders(
58
+ <BarView screenStyles={screenStyles} barState={barState} />
59
+ );
60
+
61
+ expect(getByTestId("BarView-safeAreaView").props.style).not.toContainEqual({
62
+ transform: [{ scaleX: -1 }],
63
+ });
64
+ });
65
+
66
+ it("calls closeHandler when CloseButton is pressed", () => {
67
+ mockUseIsRTL.mockReturnValue(false);
68
+
69
+ const { getByTestId } = renderWithProviders(
70
+ <BarView screenStyles={screenStyles} barState={barState} />
71
+ );
72
+
73
+ fireEvent.press(getByTestId("closeButton-actionButton-touchable"));
74
+ expect(barState.closeHandler).toHaveBeenCalled();
75
+ });
76
+
77
+ it("calls backHandler when BackButton is pressed", () => {
78
+ mockUseIsRTL.mockReturnValue(false);
79
+
80
+ const { getByTestId } = renderWithProviders(
81
+ <BarView screenStyles={screenStyles} barState={barState} />
82
+ );
83
+
84
+ fireEvent.press(getByTestId("backButton-actionButton-touchable"));
85
+ expect(barState.backHandler).toHaveBeenCalled();
86
+ });
87
+ });
@@ -28,7 +28,7 @@ styles: {
28
28
  }
29
29
  */
30
30
 
31
- type ActionButtonProps = {
31
+ type ActionButtonProps = Testable & {
32
32
  onPress: () => void;
33
33
  buttonStyles: any;
34
34
  imageUrl: string;
@@ -46,11 +46,16 @@ const ActionButton = ({
46
46
  buttonStyles,
47
47
  imageUrl,
48
48
  imageStyle = closeButtonStyle,
49
+ testID,
49
50
  }: ActionButtonProps) => {
50
51
  return (
51
- <View style={buttonStyles}>
52
- <TouchableOpacity onPress={onPress}>
53
- <Image source={{ uri: imageUrl }} style={imageStyle} />
52
+ <View style={buttonStyles} testID={testID}>
53
+ <TouchableOpacity onPress={onPress} testID={`${testID}-touchable`}>
54
+ <Image
55
+ source={{ uri: imageUrl }}
56
+ style={imageStyle}
57
+ testID={`${testID}-image`}
58
+ />
54
59
  </TouchableOpacity>
55
60
  </View>
56
61
  );