@applicaster/zapp-react-native-utils 15.0.0-rc.12 → 15.0.0-rc.120

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 (159) hide show
  1. package/README.md +0 -6
  2. package/actionsExecutor/ActionExecutorContext.tsx +3 -6
  3. package/actionsExecutor/feedDecorator.ts +6 -6
  4. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  5. package/adsUtils/index.ts +2 -2
  6. package/analyticsUtils/README.md +1 -1
  7. package/analyticsUtils/analyticsMapper.ts +10 -2
  8. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  9. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  10. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  11. package/appUtils/HooksManager/index.ts +10 -10
  12. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  13. package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
  14. package/appUtils/accessibilityManager/const.ts +4 -0
  15. package/appUtils/accessibilityManager/hooks.ts +20 -13
  16. package/appUtils/accessibilityManager/index.ts +28 -1
  17. package/appUtils/accessibilityManager/utils.ts +59 -8
  18. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  19. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  20. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  21. package/appUtils/contextKeysManager/index.ts +65 -10
  22. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +4 -0
  23. package/appUtils/focusManager/index.ios.ts +59 -3
  24. package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
  25. package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
  26. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  27. package/appUtils/focusManagerAux/utils/index.ts +21 -5
  28. package/appUtils/focusManagerAux/utils/utils.ios.ts +234 -0
  29. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  30. package/appUtils/localizationsHelper.ts +4 -0
  31. package/appUtils/orientationHelper.ts +2 -4
  32. package/appUtils/platform/platformUtils.ts +117 -18
  33. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
  34. package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
  35. package/appUtils/playerManager/player.ts +4 -0
  36. package/appUtils/playerManager/playerNative.ts +31 -17
  37. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  38. package/arrayUtils/__tests__/allTruthy.test.ts +24 -0
  39. package/arrayUtils/__tests__/anyThruthy.test.ts +24 -0
  40. package/arrayUtils/index.ts +5 -0
  41. package/cellUtils/index.ts +32 -0
  42. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  43. package/cloudEventsUtils/index.ts +65 -1
  44. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +38 -0
  45. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  46. package/configurationUtils/index.ts +17 -11
  47. package/dateUtils/__tests__/dayjs.test.ts +330 -0
  48. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  49. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  50. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  51. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  52. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  53. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  54. package/errorUtils/__tests__/invariant.test.ts +112 -0
  55. package/focusManager/aux/index.ts +1 -1
  56. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  57. package/headersUtils/index.ts +2 -1
  58. package/manifestUtils/defaultManifestConfigurations/player.js +115 -11
  59. package/manifestUtils/keys.js +21 -0
  60. package/manifestUtils/platformIsTV.js +13 -0
  61. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
  62. package/manifestUtils/tvAction/container/index.js +1 -1
  63. package/navigationUtils/index.ts +15 -5
  64. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  65. package/numberUtils/__tests__/toPositiveNumber.test.ts +193 -0
  66. package/numberUtils/index.ts +23 -1
  67. package/package.json +4 -4
  68. package/playerUtils/usePlayerTTS.ts +8 -3
  69. package/pluginUtils/index.ts +4 -0
  70. package/reactHooks/advertising/index.ts +2 -2
  71. package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
  72. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  73. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  74. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  75. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  76. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  77. package/reactHooks/connection/__tests__/index.test.js +1 -1
  78. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  79. package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
  80. package/reactHooks/device/useIsTablet.tsx +14 -19
  81. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  82. package/reactHooks/events/index.ts +20 -0
  83. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  84. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  85. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  86. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  87. package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
  88. package/reactHooks/feed/index.ts +0 -2
  89. package/reactHooks/feed/useBatchLoading.ts +7 -1
  90. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  91. package/reactHooks/feed/useInflatedUrl.ts +44 -18
  92. package/reactHooks/feed/usePipesCacheReset.ts +3 -1
  93. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  94. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
  95. package/reactHooks/index.ts +2 -0
  96. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  97. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  98. package/reactHooks/layout/index.ts +1 -1
  99. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  100. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  101. package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
  102. package/reactHooks/navigation/index.ts +27 -11
  103. package/reactHooks/navigation/useRoute.ts +11 -7
  104. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  105. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  106. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  107. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  108. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  109. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  110. package/reactHooks/resolvers/useComponentResolver.ts +19 -3
  111. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  112. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  113. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  114. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  115. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  116. package/reactHooks/state/__tests__/useComponentScreenState.test.ts +246 -0
  117. package/reactHooks/state/index.ts +2 -0
  118. package/reactHooks/state/useComponentScreenState.ts +45 -0
  119. package/reactHooks/state/useRefWithInitialValue.ts +10 -0
  120. package/reactHooks/state/useRivers.ts +1 -1
  121. package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
  122. package/reactHooks/usePluginConfiguration.ts +2 -2
  123. package/reactHooks/utils/__tests__/index.test.js +1 -1
  124. package/rectUtils/__tests__/index.test.ts +549 -0
  125. package/rectUtils/index.ts +2 -2
  126. package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +161 -0
  127. package/refreshUtils/RefreshCoordinator/index.ts +216 -0
  128. package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
  129. package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
  130. package/screenPickerUtils/__tests__/index.test.ts +333 -0
  131. package/screenPickerUtils/index.ts +5 -0
  132. package/screenState/__tests__/index.test.ts +1 -1
  133. package/screenUtils/index.ts +3 -0
  134. package/searchUtils/const.ts +7 -0
  135. package/searchUtils/index.ts +3 -0
  136. package/services/storageServiceSync.web.ts +1 -1
  137. package/stringUtils/index.ts +1 -1
  138. package/testUtils/index.tsx +30 -21
  139. package/time/__tests__/BackgroundTimer.test.ts +156 -0
  140. package/time/__tests__/Timer.test.ts +236 -0
  141. package/typeGuards/__tests__/isString.test.ts +21 -0
  142. package/typeGuards/index.ts +4 -0
  143. package/utils/__tests__/clone.test.ts +158 -0
  144. package/utils/__tests__/mapAccum.test.ts +73 -0
  145. package/utils/__tests__/mergeRight.test.ts +48 -0
  146. package/utils/__tests__/path.test.ts +7 -0
  147. package/utils/__tests__/selectors.test.ts +124 -0
  148. package/utils/clone.ts +7 -0
  149. package/utils/index.ts +22 -1
  150. package/utils/mapAccum.ts +23 -0
  151. package/utils/mergeRight.ts +5 -0
  152. package/utils/path.ts +6 -3
  153. package/utils/pathOr.ts +5 -1
  154. package/utils/selectors.ts +46 -0
  155. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +49 -12
  156. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  157. package/reactHooks/componentsMap/index.ts +0 -55
  158. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
  159. package/reactHooks/feed/useFeedRefresh.tsx +0 -65
@@ -0,0 +1,333 @@
1
+ import {
2
+ getFocusableId,
3
+ getPickerSelectorId,
4
+ SCREEN_PICKER_CONTAINER,
5
+ getScreenPickerId,
6
+ getScreenPickerSelectorContainerId,
7
+ getScreenPickerContentContainerId,
8
+ } from "../index";
9
+
10
+ describe("screenPickerUtils", () => {
11
+ describe("getFocusableId", () => {
12
+ it("should generate focusable ID with PickerItem prefix", () => {
13
+ expect(getFocusableId("item1")).toBe("PickerItem.item1");
14
+ });
15
+
16
+ it("should handle numeric IDs", () => {
17
+ expect(getFocusableId(123)).toBe("PickerItem.123");
18
+ });
19
+
20
+ it("should handle string IDs with special characters", () => {
21
+ expect(getFocusableId("item-123_test")).toBe("PickerItem.item-123_test");
22
+ });
23
+
24
+ it("should handle empty string ID", () => {
25
+ expect(getFocusableId("")).toBe("PickerItem.");
26
+ });
27
+
28
+ it("should handle IDs with spaces", () => {
29
+ expect(getFocusableId("my item")).toBe("PickerItem.my item");
30
+ });
31
+
32
+ it("should handle IDs with dots", () => {
33
+ expect(getFocusableId("parent.child")).toBe("PickerItem.parent.child");
34
+ });
35
+
36
+ it("should handle null ID", () => {
37
+ expect(getFocusableId(null)).toBe("PickerItem.null");
38
+ });
39
+
40
+ it("should handle undefined ID", () => {
41
+ expect(getFocusableId(undefined)).toBe("PickerItem.undefined");
42
+ });
43
+ });
44
+
45
+ describe("getPickerSelectorId", () => {
46
+ it("should generate picker selector ID with PickerSelector prefix", () => {
47
+ expect(getPickerSelectorId("selector1")).toBe("PickerSelector.selector1");
48
+ });
49
+
50
+ it("should handle numeric IDs", () => {
51
+ expect(getPickerSelectorId(456)).toBe("PickerSelector.456");
52
+ });
53
+
54
+ it("should handle string IDs with special characters", () => {
55
+ expect(getPickerSelectorId("selector-abc_xyz")).toBe(
56
+ "PickerSelector.selector-abc_xyz"
57
+ );
58
+ });
59
+
60
+ it("should handle empty string ID", () => {
61
+ expect(getPickerSelectorId("")).toBe("PickerSelector.");
62
+ });
63
+
64
+ it("should handle IDs with spaces", () => {
65
+ expect(getPickerSelectorId("my selector")).toBe(
66
+ "PickerSelector.my selector"
67
+ );
68
+ });
69
+
70
+ it("should handle null ID", () => {
71
+ expect(getPickerSelectorId(null)).toBe("PickerSelector.null");
72
+ });
73
+
74
+ it("should handle undefined ID", () => {
75
+ expect(getPickerSelectorId(undefined)).toBe("PickerSelector.undefined");
76
+ });
77
+ });
78
+
79
+ describe("SCREEN_PICKER_CONTAINER", () => {
80
+ it("should have correct constant value", () => {
81
+ expect(SCREEN_PICKER_CONTAINER).toBe("ScreenPickerContainer");
82
+ });
83
+
84
+ it("should be a string", () => {
85
+ expect(typeof SCREEN_PICKER_CONTAINER).toBe("string");
86
+ });
87
+ });
88
+
89
+ describe("getScreenPickerId", () => {
90
+ it("should generate screen picker ID with container prefix", () => {
91
+ expect(getScreenPickerId("screen1")).toBe(
92
+ "ScreenPickerContainer.screen1"
93
+ );
94
+ });
95
+
96
+ it("should use SCREEN_PICKER_CONTAINER constant", () => {
97
+ const id = "test";
98
+ expect(getScreenPickerId(id)).toBe(`${SCREEN_PICKER_CONTAINER}.${id}`);
99
+ });
100
+
101
+ it("should handle numeric IDs", () => {
102
+ expect(getScreenPickerId(789)).toBe("ScreenPickerContainer.789");
103
+ });
104
+
105
+ it("should handle string IDs with special characters", () => {
106
+ expect(getScreenPickerId("screen-123_test")).toBe(
107
+ "ScreenPickerContainer.screen-123_test"
108
+ );
109
+ });
110
+
111
+ it("should handle empty string ID", () => {
112
+ expect(getScreenPickerId("")).toBe("ScreenPickerContainer.");
113
+ });
114
+
115
+ it("should handle IDs with spaces", () => {
116
+ expect(getScreenPickerId("my screen")).toBe(
117
+ "ScreenPickerContainer.my screen"
118
+ );
119
+ });
120
+
121
+ it("should handle null ID", () => {
122
+ expect(getScreenPickerId(null)).toBe("ScreenPickerContainer.null");
123
+ });
124
+
125
+ it("should handle undefined ID", () => {
126
+ expect(getScreenPickerId(undefined)).toBe(
127
+ "ScreenPickerContainer.undefined"
128
+ );
129
+ });
130
+ });
131
+
132
+ describe("getScreenPickerSelectorContainerId", () => {
133
+ it("should generate selector container ID with suffix", () => {
134
+ expect(getScreenPickerSelectorContainerId("screen1")).toBe(
135
+ "ScreenPickerContainer.screen1-screen-selector"
136
+ );
137
+ });
138
+
139
+ it("should build on top of getScreenPickerId", () => {
140
+ const id = "test";
141
+ const baseId = getScreenPickerId(id);
142
+
143
+ expect(getScreenPickerSelectorContainerId(id)).toBe(
144
+ `${baseId}-screen-selector`
145
+ );
146
+ });
147
+
148
+ it("should handle numeric IDs", () => {
149
+ expect(getScreenPickerSelectorContainerId(123)).toBe(
150
+ "ScreenPickerContainer.123-screen-selector"
151
+ );
152
+ });
153
+
154
+ it("should handle string IDs with special characters", () => {
155
+ expect(getScreenPickerSelectorContainerId("screen-abc_xyz")).toBe(
156
+ "ScreenPickerContainer.screen-abc_xyz-screen-selector"
157
+ );
158
+ });
159
+
160
+ it("should handle empty string ID", () => {
161
+ expect(getScreenPickerSelectorContainerId("")).toBe(
162
+ "ScreenPickerContainer.-screen-selector"
163
+ );
164
+ });
165
+
166
+ it("should handle IDs with spaces", () => {
167
+ expect(getScreenPickerSelectorContainerId("my screen")).toBe(
168
+ "ScreenPickerContainer.my screen-screen-selector"
169
+ );
170
+ });
171
+
172
+ it("should handle null ID", () => {
173
+ expect(getScreenPickerSelectorContainerId(null)).toBe(
174
+ "ScreenPickerContainer.null-screen-selector"
175
+ );
176
+ });
177
+
178
+ it("should handle undefined ID", () => {
179
+ expect(getScreenPickerSelectorContainerId(undefined)).toBe(
180
+ "ScreenPickerContainer.undefined-screen-selector"
181
+ );
182
+ });
183
+ });
184
+
185
+ describe("getScreenPickerContentContainerId", () => {
186
+ it("should generate content container ID with suffix", () => {
187
+ expect(getScreenPickerContentContainerId("screen1")).toBe(
188
+ "ScreenPickerContainer.screen1-screen-container"
189
+ );
190
+ });
191
+
192
+ it("should build on top of getScreenPickerId", () => {
193
+ const id = "test";
194
+ const baseId = getScreenPickerId(id);
195
+
196
+ expect(getScreenPickerContentContainerId(id)).toBe(
197
+ `${baseId}-screen-container`
198
+ );
199
+ });
200
+
201
+ it("should handle numeric IDs", () => {
202
+ expect(getScreenPickerContentContainerId(456)).toBe(
203
+ "ScreenPickerContainer.456-screen-container"
204
+ );
205
+ });
206
+
207
+ it("should handle string IDs with special characters", () => {
208
+ expect(getScreenPickerContentContainerId("content-abc_xyz")).toBe(
209
+ "ScreenPickerContainer.content-abc_xyz-screen-container"
210
+ );
211
+ });
212
+
213
+ it("should handle empty string ID", () => {
214
+ expect(getScreenPickerContentContainerId("")).toBe(
215
+ "ScreenPickerContainer.-screen-container"
216
+ );
217
+ });
218
+
219
+ it("should handle IDs with spaces", () => {
220
+ expect(getScreenPickerContentContainerId("my content")).toBe(
221
+ "ScreenPickerContainer.my content-screen-container"
222
+ );
223
+ });
224
+
225
+ it("should handle null ID", () => {
226
+ expect(getScreenPickerContentContainerId(null)).toBe(
227
+ "ScreenPickerContainer.null-screen-container"
228
+ );
229
+ });
230
+
231
+ it("should handle undefined ID", () => {
232
+ expect(getScreenPickerContentContainerId(undefined)).toBe(
233
+ "ScreenPickerContainer.undefined-screen-container"
234
+ );
235
+ });
236
+ });
237
+
238
+ describe("ID relationships", () => {
239
+ it("should generate different IDs for different functions", () => {
240
+ const id = "test";
241
+
242
+ const focusableId = getFocusableId(id);
243
+ const selectorId = getPickerSelectorId(id);
244
+ const screenPickerId = getScreenPickerId(id);
245
+
246
+ expect(focusableId).not.toBe(selectorId);
247
+ expect(focusableId).not.toBe(screenPickerId);
248
+ expect(selectorId).not.toBe(screenPickerId);
249
+ });
250
+
251
+ it("should have consistent prefixes across calls", () => {
252
+ expect(getFocusableId("a")).toContain("PickerItem.");
253
+ expect(getFocusableId("b")).toContain("PickerItem.");
254
+ expect(getPickerSelectorId("a")).toContain("PickerSelector.");
255
+ expect(getPickerSelectorId("b")).toContain("PickerSelector.");
256
+ expect(getScreenPickerId("a")).toContain("ScreenPickerContainer.");
257
+ expect(getScreenPickerId("b")).toContain("ScreenPickerContainer.");
258
+ });
259
+
260
+ it("should generate selector and content IDs from same base", () => {
261
+ const id = "common";
262
+ const baseId = getScreenPickerId(id);
263
+ const selectorId = getScreenPickerSelectorContainerId(id);
264
+ const contentId = getScreenPickerContentContainerId(id);
265
+
266
+ expect(selectorId).toContain(baseId);
267
+ expect(contentId).toContain(baseId);
268
+ expect(selectorId).not.toBe(contentId);
269
+ });
270
+
271
+ it("should distinguish between selector and content containers", () => {
272
+ const id = "test";
273
+
274
+ const selectorId = getScreenPickerSelectorContainerId(id);
275
+ const contentId = getScreenPickerContentContainerId(id);
276
+
277
+ expect(selectorId).toContain("-screen-selector");
278
+ expect(contentId).toContain("-screen-container");
279
+ expect(selectorId).not.toBe(contentId);
280
+ });
281
+ });
282
+
283
+ describe("special characters and edge cases", () => {
284
+ it("should handle IDs with slashes", () => {
285
+ const id = "path/to/screen";
286
+
287
+ expect(getFocusableId(id)).toBe("PickerItem.path/to/screen");
288
+ expect(getPickerSelectorId(id)).toBe("PickerSelector.path/to/screen");
289
+
290
+ expect(getScreenPickerId(id)).toBe(
291
+ "ScreenPickerContainer.path/to/screen"
292
+ );
293
+ });
294
+
295
+ it("should handle IDs with Unicode characters", () => {
296
+ const id = "écran-日本語";
297
+
298
+ expect(getFocusableId(id)).toBe("PickerItem.écran-日本語");
299
+ expect(getPickerSelectorId(id)).toBe("PickerSelector.écran-日本語");
300
+ expect(getScreenPickerId(id)).toBe("ScreenPickerContainer.écran-日本語");
301
+ });
302
+
303
+ it("should handle very long IDs", () => {
304
+ const id = "a".repeat(1000);
305
+
306
+ expect(getFocusableId(id)).toContain("PickerItem.");
307
+ expect(getPickerSelectorId(id)).toContain("PickerSelector.");
308
+ expect(getScreenPickerId(id)).toContain("ScreenPickerContainer.");
309
+ });
310
+
311
+ it("should handle IDs with equals signs", () => {
312
+ const id = "key=value";
313
+
314
+ expect(getFocusableId(id)).toBe("PickerItem.key=value");
315
+ expect(getPickerSelectorId(id)).toBe("PickerSelector.key=value");
316
+ expect(getScreenPickerId(id)).toBe("ScreenPickerContainer.key=value");
317
+ });
318
+
319
+ it("should handle boolean values", () => {
320
+ expect(getFocusableId(true)).toBe("PickerItem.true");
321
+ expect(getPickerSelectorId(false)).toBe("PickerSelector.false");
322
+ expect(getScreenPickerId(true)).toBe("ScreenPickerContainer.true");
323
+ });
324
+
325
+ it("should handle object IDs", () => {
326
+ const obj = { toString: () => "customId" };
327
+
328
+ expect(getFocusableId(obj)).toContain("PickerItem.");
329
+ expect(getPickerSelectorId(obj)).toContain("PickerSelector.");
330
+ expect(getScreenPickerId(obj)).toContain("ScreenPickerContainer.");
331
+ });
332
+ });
333
+ });
@@ -1,3 +1,5 @@
1
+ import { endsWith } from "@applicaster/zapp-react-native-utils/utils";
2
+
1
3
  export const getFocusableId = (id) => `PickerItem.${id}`;
2
4
 
3
5
  export const getPickerSelectorId = (id) => `PickerSelector.${id}`;
@@ -11,3 +13,6 @@ export const getScreenPickerSelectorContainerId = (id) =>
11
13
 
12
14
  export const getScreenPickerContentContainerId = (id) =>
13
15
  `${getScreenPickerId(id)}-screen-container`;
16
+
17
+ export const isTabsScreenContentContainerId = (id) =>
18
+ endsWith("-screen-container", id);
@@ -1,4 +1,4 @@
1
- import { act, renderHook } from "@testing-library/react-hooks";
1
+ import { act, renderHook } from "@testing-library/react-native";
2
2
  import { useScreenState } from "../index";
3
3
 
4
4
  describe("useScreenState", () => {
@@ -0,0 +1,3 @@
1
+ export const TV_SCREEN_HEIGHT = 1080;
2
+
3
+ export const TV_SCREEN_WIDTH = 1920;
@@ -0,0 +1,7 @@
1
+ export const FOCUSABLE_GROUP_ID = "search-screen";
2
+
3
+ export const FOCUSABLE_RESULTS_ID = "search-screen-results";
4
+
5
+ export const SEARCH_BOX_GROUP_ID = "search_box_group_id";
6
+
7
+ export const SEARCH_INPUT_FOCUSABLE_ID = "search_input_group_id";
@@ -0,0 +1,3 @@
1
+ import { SEARCH_INPUT_FOCUSABLE_ID } from "./const";
2
+
3
+ export const isSearchInputId = (id) => id === SEARCH_INPUT_FOCUSABLE_ID;
@@ -17,7 +17,7 @@ export const resolveStorageContextKey = (storageKey: string) => {
17
17
  const key = splitKey[1];
18
18
 
19
19
  if (!key) {
20
- return getFromSessionOrLocalStorage(key);
20
+ return getFromSessionOrLocalStorage(namespaceOrKey);
21
21
  } else {
22
22
  return getFromSessionOrLocalStorage(key, namespaceOrKey);
23
23
  }
@@ -4,7 +4,7 @@ declare const global;
4
4
  import * as R from "ramda";
5
5
  import camelize from "camelize";
6
6
  // @ts-ignore
7
- import Handlebars from "react-native-handlebars";
7
+ import Handlebars from "handlebars";
8
8
 
9
9
  global.Buffer = global.Buffer || require("buffer").Buffer;
10
10
 
@@ -4,7 +4,7 @@ import React, { PropsWithChildren } from "react";
4
4
  import configureStore from "redux-mock-store";
5
5
  import { Provider } from "react-redux";
6
6
  import { View } from "react-native";
7
- import thunk from "redux-thunk";
7
+ import { thunk } from "redux-thunk";
8
8
  import * as R from "ramda";
9
9
 
10
10
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
@@ -56,9 +56,29 @@ const initialState = {
56
56
  contentTypes: null,
57
57
  };
58
58
 
59
+ const themeObjDefault = {
60
+ component_margin_top: 0,
61
+ component_margin_bottom: 0,
62
+ component_margin_left: 0,
63
+ component_margin_right: 0,
64
+ component_padding_top: 0,
65
+ component_padding_bottom: 0,
66
+ component_padding_left: 0,
67
+ component_padding_right: 0,
68
+ component_gutter_vertical: 0,
69
+ component_gutter_horizontal: 0,
70
+ component_corner_radius: 0,
71
+ app_background_color: "rgba(0,0,0,0)",
72
+ screen_margin_top: 0,
73
+ screen_margin_bottom: 0,
74
+ component_anchor_point_y: 0,
75
+ assets: "",
76
+ };
77
+
59
78
  export const WrappedWithProviders = ({
60
79
  children,
61
80
  store: storeObj = {},
81
+ theme: themeObj = themeObjDefault,
62
82
  }: any) => {
63
83
  const _store = configureStore([thunk])(
64
84
  R.mergeDeepRight(initialState, { ...storeObj })
@@ -70,24 +90,7 @@ export const WrappedWithProviders = ({
70
90
  <ThemeContext.Provider
71
91
  value={{
72
92
  themes: {
73
- light: {
74
- component_margin_top: 0,
75
- component_margin_bottom: 0,
76
- component_margin_left: 0,
77
- component_margin_right: 0,
78
- component_padding_top: 0,
79
- component_padding_bottom: 0,
80
- component_padding_left: 0,
81
- component_padding_right: 0,
82
- component_gutter_vertical: 0,
83
- component_gutter_horizontal: 0,
84
- component_corner_radius: 0,
85
- app_background_color: "rgba(0,0,0,0)",
86
- screen_margin_top: 0,
87
- screen_margin_bottom: 0,
88
- component_anchor_point_y: 0,
89
- assets: "",
90
- },
93
+ light: themeObj,
91
94
  },
92
95
  selectedThemeId: "light",
93
96
  setSelectedThemeId: () => {},
@@ -113,11 +116,17 @@ export const WrappedWithProviders = ({
113
116
  * @param store optional store to pass to the provider
114
117
  * @returns
115
118
  */
116
- export const renderWithProviders = (component, storeObj?: unknown) => {
119
+ export const renderWithProviders = (
120
+ component,
121
+ storeObj?: unknown,
122
+ themeObj?: unknown
123
+ ) => {
117
124
  return render(component, {
118
125
  wrapper: function TestWrapper({ children }: PropsWithChildren<any>) {
119
126
  return (
120
- <WrappedWithProviders store={storeObj}>{children}</WrappedWithProviders>
127
+ <WrappedWithProviders store={storeObj} theme={themeObj}>
128
+ {children}
129
+ </WrappedWithProviders>
121
130
  );
122
131
  },
123
132
  });
@@ -0,0 +1,156 @@
1
+ const mockBackgroundTimerModule = {
2
+ setTimeout: jest.fn(),
3
+ clearTimeout: jest.fn(),
4
+ };
5
+
6
+ jest.mock("../../reactUtils", () => ({
7
+ platformSelect: jest.fn((options) => options.android || options.default),
8
+ }));
9
+
10
+ describe("BackgroundTimer", () => {
11
+ let BackgroundTimer: any;
12
+
13
+ const setupTimer = (withNativeModule = true) => {
14
+ jest.resetModules();
15
+
16
+ jest.doMock("react-native", () => ({
17
+ NativeModules: {
18
+ BackgroundTimer: withNativeModule
19
+ ? mockBackgroundTimerModule
20
+ : undefined,
21
+ },
22
+ DeviceEventEmitter: {
23
+ addListener: jest.fn(),
24
+ removeListener: jest.fn(),
25
+ },
26
+ }));
27
+
28
+ BackgroundTimer = require("../BackgroundTimer").default;
29
+ };
30
+
31
+ beforeEach(() => {
32
+ jest.clearAllMocks();
33
+ });
34
+
35
+ describe("Native Module Environment", () => {
36
+ beforeEach(() => {
37
+ setupTimer(true);
38
+ });
39
+
40
+ it("should initialize device event listener on startup", () => {
41
+ const { DeviceEventEmitter } = require("react-native");
42
+
43
+ expect(DeviceEventEmitter.addListener).toHaveBeenCalledWith(
44
+ "BackgroundTimer.timer.fired",
45
+ expect.any(Function)
46
+ );
47
+ });
48
+
49
+ it("should delegate setTimeout to native module and return a unique ID", () => {
50
+ const callback1 = jest.fn();
51
+ const callback2 = jest.fn();
52
+ const timeout = 1000;
53
+
54
+ const id1 = BackgroundTimer.setTimeout(callback1, timeout);
55
+ const id2 = BackgroundTimer.setTimeout(callback2, timeout);
56
+
57
+ expect(mockBackgroundTimerModule.setTimeout).toHaveBeenCalledWith(
58
+ id1,
59
+ timeout
60
+ );
61
+
62
+ expect(mockBackgroundTimerModule.setTimeout).toHaveBeenCalledWith(
63
+ id2,
64
+ timeout
65
+ );
66
+
67
+ expect(id1).not.toBe(id2);
68
+ expect(typeof id1).toBe("number");
69
+ });
70
+
71
+ it("should delegate clearTimeout to native module", () => {
72
+ const id = BackgroundTimer.setTimeout(jest.fn(), 1000);
73
+ BackgroundTimer.clearTimeout(id);
74
+
75
+ expect(mockBackgroundTimerModule.clearTimeout).toHaveBeenCalledWith(id);
76
+ });
77
+
78
+ it("should execute callback when native timer fires", () => {
79
+ const { DeviceEventEmitter } = require("react-native");
80
+ const callback = jest.fn();
81
+
82
+ const id = BackgroundTimer.setTimeout(callback, 1000);
83
+
84
+ const listener = DeviceEventEmitter.addListener.mock.calls[0][1];
85
+
86
+ listener(id);
87
+
88
+ expect(callback).toHaveBeenCalledTimes(1);
89
+ });
90
+
91
+ it("should cleanup callback after execution (prevent double firing)", () => {
92
+ const { DeviceEventEmitter } = require("react-native");
93
+ const callback = jest.fn();
94
+
95
+ const id = BackgroundTimer.setTimeout(callback, 1000);
96
+ const listener = DeviceEventEmitter.addListener.mock.calls[0][1];
97
+
98
+ listener(id);
99
+ listener(id);
100
+
101
+ expect(callback).toHaveBeenCalledTimes(1);
102
+ });
103
+
104
+ it("should not execute callback if cleared before firing", () => {
105
+ const { DeviceEventEmitter } = require("react-native");
106
+ const callback = jest.fn();
107
+
108
+ const id = BackgroundTimer.setTimeout(callback, 1000);
109
+ BackgroundTimer.clearTimeout(id);
110
+
111
+ const listener = DeviceEventEmitter.addListener.mock.calls[0][1];
112
+ listener(id);
113
+
114
+ expect(callback).not.toHaveBeenCalled();
115
+ });
116
+
117
+ it("should ignore events for unknown/invalid IDs", () => {
118
+ const { DeviceEventEmitter } = require("react-native");
119
+ const callback = jest.fn();
120
+
121
+ BackgroundTimer.setTimeout(callback, 1000);
122
+
123
+ const listener = DeviceEventEmitter.addListener.mock.calls[0][1];
124
+ listener(99999);
125
+
126
+ expect(callback).not.toHaveBeenCalled();
127
+ });
128
+ });
129
+
130
+ describe("Fallback Environment (No Native Module)", () => {
131
+ beforeEach(() => {
132
+ setupTimer(false);
133
+ });
134
+
135
+ it("should use global setTimeout when native module is missing", () => {
136
+ const callback = jest.fn();
137
+ const timeout = 500;
138
+
139
+ const globalSpy = jest.spyOn(global, "setTimeout");
140
+
141
+ BackgroundTimer.setTimeout(callback, timeout);
142
+
143
+ expect(globalSpy).toHaveBeenCalledWith(callback, timeout);
144
+ });
145
+
146
+ it("should use global clearTimeout when native module is missing", () => {
147
+ const callback = jest.fn();
148
+ const globalSpy = jest.spyOn(global, "clearTimeout");
149
+
150
+ const id = BackgroundTimer.setTimeout(callback, 500);
151
+ BackgroundTimer.clearTimeout(id);
152
+
153
+ expect(globalSpy).toHaveBeenCalledWith(id);
154
+ });
155
+ });
156
+ });