@applicaster/zapp-react-native-utils 15.0.0-alpha.7809066324 → 15.0.0-alpha.8111467956

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 (33) hide show
  1. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +38 -0
  2. package/configurationUtils/index.ts +17 -11
  3. package/navigationUtils/index.ts +15 -5
  4. package/package.json +4 -4
  5. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  6. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  7. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  8. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  9. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  10. package/reactHooks/connection/__tests__/index.test.js +1 -1
  11. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  12. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  13. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +1 -1
  14. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  15. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +1 -1
  16. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
  17. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
  18. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  19. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  20. package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
  21. package/reactHooks/navigation/index.ts +15 -4
  22. package/reactHooks/navigation/useRoute.ts +3 -1
  23. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  24. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  25. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  26. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  27. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +1 -1
  28. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  29. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  30. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +1 -1
  31. package/reactHooks/utils/__tests__/index.test.js +1 -1
  32. package/screenState/__tests__/index.test.ts +1 -1
  33. package/stringUtils/index.ts +1 -1
@@ -31,4 +31,42 @@ describe("imageSrcFromMediaItem", () => {
31
31
 
32
32
  expect(imageSrcFromMediaItem(badEntry, ["image_base"])).toBeUndefined();
33
33
  });
34
+
35
+ it("returns undefined when fallback is false and key is not found", () => {
36
+ const result = imageSrcFromMediaItem(entry as ZappEntry, [
37
+ "does_not_exist",
38
+ false,
39
+ ]);
40
+
41
+ expect(result).toBeUndefined();
42
+ });
43
+
44
+ it("returns src when fallback is false and key is found", () => {
45
+ const result = imageSrcFromMediaItem(entry as ZappEntry, [
46
+ "logo_thumbnail",
47
+ false,
48
+ ]);
49
+
50
+ expect(result).toEqual(entry.media_group[1].media_item[0].src);
51
+ });
52
+
53
+ it("returns image_base as fallback when fallback is explicitly true and key is not found", () => {
54
+ const result = imageSrcFromMediaItem(entry as ZappEntry, [
55
+ "does_not_exist",
56
+ true,
57
+ ]);
58
+
59
+ const fallback = entry.media_group[0].media_item[0];
60
+ expect(result).toEqual(fallback.src);
61
+ expect(fallback.key).toBe("image_base");
62
+ });
63
+
64
+ it("returns src when fallback is explicitly true and key is found", () => {
65
+ const result = imageSrcFromMediaItem(entry as ZappEntry, [
66
+ "logo_thumbnail",
67
+ true,
68
+ ]);
69
+
70
+ expect(result).toEqual(entry.media_group[1].media_item[0].src);
71
+ });
34
72
  });
@@ -155,9 +155,9 @@ export function getMediaItems(entry: ZappEntry): Option<ZappMediaItem[]> {
155
155
 
156
156
  /**
157
157
  * Retrieves the "src" value from a media item in the entry's media group,
158
- * based on a provided key, with fallback logic.
158
+ * based on a provided key, with optional fallback logic.
159
159
  *
160
- * Fallback order:
160
+ * Fallback order (when enabled):
161
161
  * 1. Attempts to find a media item with the specified key (or "image_base" if none provided).
162
162
  * 2. If not found, attempts to find a media item with the key "image_base".
163
163
  * 3. If still not found, falls back to the first available media item.
@@ -166,15 +166,19 @@ export function getMediaItems(entry: ZappEntry): Option<ZappMediaItem[]> {
166
166
  * since empty URIs are invalid in some platforms (e.g., React Native).
167
167
  *
168
168
  * @param {ZappEntry} entry - The entry object containing a media group.
169
- * @param {string[] | unknown} arg - A single-element array containing the key to look up, or any unknown value.
169
+ * @param {string[] | unknown} arg - Can be an array or any other value (treated as empty array).
170
+ * When an array:
171
+ * - First element: The key to look up. If omitted or undefined, defaults to "image_base".
172
+ * - Second element: Boolean to enable/disable fallback logic. If omitted or undefined, defaults to true.
170
173
  * @returns {?string} The "src" URI from the matched media item, or undefined if not found or empty.
171
174
  */
172
175
  export function imageSrcFromMediaItem(
173
176
  entry: ZappEntry,
174
177
  arg: string[] | unknown
175
178
  ): Option<string> {
176
- const args: unknown = R.unless(Array.isArray, Array)(arg || []);
179
+ const args: any = R.unless(Array.isArray, Array)(arg || []);
177
180
  const imageKey: string = args?.[0] || "image_base"; // always a single key in this function
181
+ const fallback: boolean = args?.[1] !== false;
178
182
 
179
183
  const mediaItems = getMediaItems(entry);
180
184
 
@@ -185,14 +189,16 @@ export function imageSrcFromMediaItem(
185
189
  // Try to find the item with the given key
186
190
  let foundItem = mediaItems.find((item) => item.key === imageKey);
187
191
 
188
- // If not found and key was not "image_base", try to find "image_base"
189
- if (!foundItem && imageKey !== "image_base") {
190
- foundItem = mediaItems.find((item) => item.key === "image_base");
191
- }
192
+ if (fallback) {
193
+ // If not found and key was not "image_base", try to find "image_base"
194
+ if (!foundItem && imageKey !== "image_base") {
195
+ foundItem = mediaItems.find((item) => item.key === "image_base");
196
+ }
192
197
 
193
- // If still not found, default to first item
194
- if (!foundItem) {
195
- foundItem = mediaItems[0];
198
+ // If still not found, default to first item
199
+ if (!foundItem) {
200
+ foundItem = mediaItems[0];
201
+ }
196
202
  }
197
203
 
198
204
  const src = foundItem?.src;
@@ -5,7 +5,8 @@ import { layoutV2TypeMatcher } from "./layoutV2TypeMatcher";
5
5
  import { HOOKS_EVENTS } from "../appUtils/HooksManager/constants";
6
6
  import { HooksManager } from "../appUtils/HooksManager";
7
7
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
8
- import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
8
+
9
+ import { zappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
9
10
  import { logger } from "@applicaster/zapp-react-native-utils/logger";
10
11
  import {
11
12
  isGeneralPlugin,
@@ -15,6 +16,8 @@ import {
15
16
  } from "./itemTypeMatchers";
16
17
  import { RootState } from "@applicaster/zapp-react-native-redux/store";
17
18
 
19
+ import { pick } from "@applicaster/zapp-react-native-utils/utils";
20
+
18
21
  type PathAttribute = {
19
22
  screenType: string;
20
23
  screenId: string;
@@ -403,15 +406,22 @@ export const mapContentTypesToRivers = (
403
406
  };
404
407
 
405
408
  export const runZappHooksForEntry = async (
406
- entry: HookPluginProps["payload"],
407
- {
409
+ entry: HookPluginProps["payload"]
410
+ ): Promise<{ success: boolean; payload: ZappEntry }> => {
411
+ const {
408
412
  setState,
409
413
  resetState,
410
414
  setIsHooksExecutionInProgress,
411
415
  setIsPresentingFullScreen,
412
416
  setIsRunningInBackground,
413
- }: Partial<HookModalContextT>
414
- ): Promise<{ success: boolean; payload: ZappEntry }> => {
417
+ } = pick(zappHookModalStore.getState(), [
418
+ "setState",
419
+ "resetState",
420
+ "setIsHooksExecutionInProgress",
421
+ "setIsPresentingFullScreen",
422
+ "setIsRunningInBackground",
423
+ ]);
424
+
415
425
  resetState?.();
416
426
 
417
427
  let success;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "15.0.0-alpha.7809066324",
3
+ "version": "15.0.0-alpha.8111467956",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "15.0.0-alpha.7809066324",
30
+ "@applicaster/applicaster-types": "15.0.0-alpha.8111467956",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
34
+ "handlebars": "4.7.8",
34
35
  "memoizee": "0.4.15",
35
- "prop-types": "^15.0.0",
36
- "react-native-handlebars": "^5.0.0-alpha.1"
36
+ "prop-types": "^15.0.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@applicaster/zapp-pipes-v2-client": "*",
@@ -1,5 +1,5 @@
1
1
  import EventEmitter from "events";
2
- import { renderHook, act } from "@testing-library/react-hooks";
2
+ import { renderHook, act } from "@testing-library/react-native";
3
3
  import { useAppState } from "../useAppState";
4
4
 
5
5
  const emitter = new EventEmitter();
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
 
3
3
  jest.mock(
4
4
  "@applicaster/zapp-react-native-ui-components/Contexts/ScreenTrackedViewPositionsContext",
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { renderHook } from "@testing-library/react-hooks";
4
- import { act, waitFor } from "@testing-library/react-native";
3
+ import { renderHook, act, waitFor } from "@testing-library/react-native";
5
4
  import { Provider } from "react-redux";
6
5
  import configureStore from "redux-mock-store";
7
6
  import { useTrackedView } from "../useTrackedView";
@@ -1,10 +1,8 @@
1
1
  import * as React from "react";
2
- import { cleanup, renderHook } from "@testing-library/react-hooks";
2
+ import { cleanup, renderHook, waitFor } from "@testing-library/react-native";
3
3
  import { CellTapContext } from "@applicaster/zapp-react-native-ui-components/Contexts/CellTapContext";
4
4
  import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
5
5
 
6
- import { waitFor } from "@testing-library/react-native";
7
-
8
6
  const mockNavigator = {
9
7
  getPathname: () => "pathnameMock",
10
8
  push: jest.fn(),
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable react/prop-types */
2
2
  import React from "react";
3
- import { renderHook, cleanup } from "@testing-library/react-hooks";
3
+ import { renderHook, cleanup } from "@testing-library/react-native";
4
4
  import { ConfigurationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ConfigutaionContext";
5
5
  import { useConfiguration } from "@applicaster/zapp-react-native-utils/reactHooks/configuration";
6
6
 
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { renderHook, cleanup } from "@testing-library/react-hooks";
2
+ import { renderHook, cleanup } from "@testing-library/react-native";
3
3
  import { NetworkStatusContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NetworkStatusContext";
4
4
 
5
5
  const MockNetInfo = {
@@ -1,8 +1,7 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook, waitFor } from "@testing-library/react-native";
2
2
  import { allFeedsIsReady, useBatchLoading } from "../useBatchLoading";
3
3
  import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
4
4
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
5
- import { waitFor } from "@testing-library/react-native";
6
5
 
7
6
  jest.mock("../../navigation");
8
7
 
@@ -16,7 +15,11 @@ jest.mock(
16
15
  })
17
16
  );
18
17
 
19
- const wrapper = WrappedWithProviders;
18
+ const getWrapper =
19
+ (store) =>
20
+ ({ children }) => (
21
+ <WrappedWithProviders store={store}>{children}</WrappedWithProviders>
22
+ );
20
23
 
21
24
  describe("useBatchLoading", () => {
22
25
  const data = [
@@ -63,8 +66,7 @@ describe("useBatchLoading", () => {
63
66
  const riverId = "123";
64
67
 
65
68
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
66
- wrapper,
67
- initialProps: { store },
69
+ wrapper: getWrapper(store),
68
70
  });
69
71
 
70
72
  const actions = (appStore.getStore() as any).getActions();
@@ -84,7 +86,7 @@ describe("useBatchLoading", () => {
84
86
  });
85
87
  });
86
88
 
87
- it("loadPipesData start loading new feed when 1 feed is done loading and 1 is in loading state", () => {
89
+ it("loadPipesData start loading new feed when 1 feed is done loading and 1 is in loading state", async () => {
88
90
  const store = {
89
91
  zappPipes: {
90
92
  url1: {
@@ -110,13 +112,14 @@ describe("useBatchLoading", () => {
110
112
  const riverId = "123";
111
113
 
112
114
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
113
- wrapper,
114
- initialProps: { store },
115
+ wrapper: getWrapper(store),
115
116
  });
116
117
 
117
118
  const actions = (appStore.getStore() as any).getActions();
118
119
 
119
- expect(actions).toHaveLength(1);
120
+ await waitFor(() => {
121
+ expect(actions).toHaveLength(1);
122
+ });
120
123
 
121
124
  expect(actions[0]).toMatchObject({
122
125
  type: "ZAPP_PIPES_REQUEST_START",
@@ -124,7 +127,7 @@ describe("useBatchLoading", () => {
124
127
  });
125
128
  });
126
129
 
127
- it("loadPipesData has been called when no data cached", () => {
130
+ it("loadPipesData has been called when no data cached", async () => {
128
131
  const store = {
129
132
  zappPipes: {},
130
133
  test: "true",
@@ -134,16 +137,17 @@ describe("useBatchLoading", () => {
134
137
  const riverId = "123";
135
138
 
136
139
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
137
- wrapper,
138
- initialProps: { store },
140
+ wrapper: getWrapper(store),
139
141
  });
140
142
 
141
143
  const actions = (appStore.getStore() as any).getActions();
142
144
 
143
- expect(actions).toHaveLength(3);
145
+ await waitFor(() => {
146
+ expect(actions).toHaveLength(3);
147
+ });
144
148
  });
145
149
 
146
- it("initial batch ready when all initial items loaded", () => {
150
+ it("initial batch ready when all initial items loaded", async () => {
147
151
  const store = {
148
152
  zappPipes: {
149
153
  url1: {
@@ -169,13 +173,15 @@ describe("useBatchLoading", () => {
169
173
 
170
174
  const { result } = renderHook(
171
175
  () => useBatchLoading(data, { initialBatchSize, riverId }),
172
- { wrapper, initialProps: { store } }
176
+ { wrapper: getWrapper(store) }
173
177
  );
174
178
 
175
- expect(result.current).toBe(true);
179
+ await waitFor(() => {
180
+ expect(result.current).toBe(true);
181
+ });
176
182
  });
177
183
 
178
- it("gallery-qb: loadPipesData should be called only once for first component in the gallery", () => {
184
+ it("gallery-qb: loadPipesData should be called only once for first component in the gallery", async () => {
179
185
  const store = {
180
186
  zappPipes: {},
181
187
  test: "true",
@@ -198,16 +204,17 @@ describe("useBatchLoading", () => {
198
204
  ];
199
205
 
200
206
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
201
- wrapper,
202
- initialProps: { store },
207
+ wrapper: getWrapper(store),
203
208
  });
204
209
 
205
210
  const actions = (appStore.getStore() as any).getActions();
206
211
 
207
- expect(actions).toHaveLength(1);
212
+ await waitFor(() => {
213
+ expect(actions).toHaveLength(1);
214
+ });
208
215
  });
209
216
 
210
- it("gallery-qb: initial batch ready when all initial items loaded", () => {
217
+ it("gallery-qb: initial batch ready when all initial items loaded", async () => {
211
218
  const store = {
212
219
  zappPipes: {
213
220
  url1: {
@@ -233,10 +240,12 @@ describe("useBatchLoading", () => {
233
240
 
234
241
  const { result } = renderHook(
235
242
  () => useBatchLoading(data, { initialBatchSize, riverId }),
236
- { wrapper, initialProps: { store } }
243
+ { wrapper: getWrapper(store) }
237
244
  );
238
245
 
239
- expect(result.current).toBe(true);
246
+ await waitFor(() => {
247
+ expect(result.current).toBe(true);
248
+ });
240
249
  });
241
250
  });
242
251
 
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook, waitFor } from "@testing-library/react-native";
2
2
  import { encodeParams } from "@applicaster/zapp-pipes-v2-client/src/utils";
3
3
 
4
4
  const appData = {
@@ -42,26 +42,26 @@ describe("useBuildPipesUrl", () => {
42
42
  build: jest.fn(() => Promise.resolve(buildResult)),
43
43
  };
44
44
 
45
- const { result, waitForNextUpdate } = renderHook(() =>
45
+ const { result } = renderHook(() =>
46
46
  useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
47
47
  );
48
48
 
49
49
  expect(result.current.url).toBe("http://foo.com/show/show-1");
50
50
  expect(result.current.requestParams).toBeNull();
51
51
 
52
- await waitForNextUpdate();
53
-
54
- expect(result.current.requestParams).toEqual(
55
- expect.objectContaining({
56
- params: {
57
- version: appData.version_name,
58
- ctx: encodeParams({ platform: appData.platform }),
59
- },
60
- headers: {
61
- SDK: appData.sdk_version,
62
- },
63
- })
64
- );
52
+ await waitFor(() => {
53
+ expect(result.current.requestParams).toEqual(
54
+ expect.objectContaining({
55
+ params: {
56
+ version: appData.version_name,
57
+ ctx: encodeParams({ platform: appData.platform }),
58
+ },
59
+ headers: {
60
+ SDK: appData.sdk_version,
61
+ },
62
+ })
63
+ );
64
+ });
65
65
  });
66
66
 
67
67
  it("returns empty object if url is not in endpoints", async () => {
@@ -81,15 +81,15 @@ describe("useBuildPipesUrl", () => {
81
81
  build: jest.fn(() => Promise.resolve(buildResult)),
82
82
  };
83
83
 
84
- const { result, waitForNextUpdate } = renderHook(() =>
84
+ const { result } = renderHook(() =>
85
85
  useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
86
86
  );
87
87
 
88
88
  expect(result.current.url).toBe("http://foobar.com/show-1");
89
89
  expect(result.current.requestParams).toBeNull();
90
90
 
91
- await waitForNextUpdate();
92
-
93
- expect(result.current.requestParams).toEqual({});
91
+ await waitFor(() => {
92
+ expect(result.current.requestParams).toEqual({});
93
+ });
94
94
  });
95
95
  });
@@ -1,6 +1,6 @@
1
1
  import * as R from "ramda";
2
2
  import React from "react";
3
- import { renderHook } from "@testing-library/react-hooks";
3
+ import { renderHook } from "@testing-library/react-native";
4
4
  import { Provider } from "react-redux";
5
5
  import { createStore } from "redux";
6
6
 
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import * as R from "ramda";
3
3
  import * as zappPipesModule from "@applicaster/zapp-react-native-redux/ZappPipes";
4
4
  import * as reactReduxModules from "react-redux";
@@ -50,6 +50,16 @@ const mockZappPipesData = {
50
50
  url: "test://testfakeurl",
51
51
  };
52
52
 
53
+ const createWrapper = (
54
+ getStore: () => any
55
+ ): React.FC<{ children: React.ReactNode }> => {
56
+ const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
57
+ <WrappedWithProviders store={getStore()}>{children}</WrappedWithProviders>
58
+ );
59
+
60
+ return Wrapper;
61
+ };
62
+
53
63
  describe("useFeedLoader", () => {
54
64
  describe("with cached feed url", () => {
55
65
  const store = {
@@ -57,11 +67,7 @@ describe("useFeedLoader", () => {
57
67
  zappPipes: { "test://testfakeurl": mockZappPipesData },
58
68
  };
59
69
 
60
- const wrapper: React.FC<any> = ({ children, ...props }) => (
61
- <WrappedWithProviders store={props.store || store}>
62
- {children}
63
- </WrappedWithProviders>
64
- );
70
+ const wrapper = createWrapper(() => store);
65
71
 
66
72
  it("returns cached feed", () => {
67
73
  const { result } = renderHook(
@@ -109,12 +115,6 @@ describe("useFeedLoader", () => {
109
115
  describe("without cached feeds", () => {
110
116
  const feedUrl = "test://testfakeurl2";
111
117
 
112
- const wrapper: React.FC<any> = ({ children, ...props }) => (
113
- <WrappedWithProviders store={props.store}>
114
- {children}
115
- </WrappedWithProviders>
116
- );
117
-
118
118
  it("It loads data for new url and returns it", () => {
119
119
  const useDispatchSpy = jest
120
120
  .spyOn(reactReduxModules, "useDispatch")
@@ -129,9 +129,12 @@ describe("useFeedLoader", () => {
129
129
  zappPipes: { "test://testfakeurl": "foobar" },
130
130
  };
131
131
 
132
+ let store = initialStore;
133
+ const wrapper = createWrapper(() => store);
134
+
132
135
  const { result, rerender } = renderHook(
133
- () => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
134
- { wrapper, initialProps: { store: initialStore } }
136
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
137
+ { wrapper, initialProps: { feedUrl } }
135
138
  );
136
139
 
137
140
  expect(result.current.data).toBeNull();
@@ -150,7 +153,8 @@ describe("useFeedLoader", () => {
150
153
  zappPipes: { "test://testfakeurl2": mockZappPipesData },
151
154
  };
152
155
 
153
- rerender({ store: store2 });
156
+ store = store2;
157
+ rerender({ feedUrl });
154
158
 
155
159
  expect(R.omit(["reloadData", "loadNext"], result.current)).toEqual(
156
160
  mockZappPipesData
@@ -174,9 +178,12 @@ describe("useFeedLoader", () => {
174
178
  zappPipes: { "test://testfakeurl": "foobar" },
175
179
  };
176
180
 
181
+ let store = initialStore;
182
+ const wrapper = createWrapper(() => store);
183
+
177
184
  const { result, rerender } = renderHook(
178
- () => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
179
- { wrapper, initialProps: { store: initialStore } }
185
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
186
+ { wrapper, initialProps: { feedUrl } }
180
187
  );
181
188
 
182
189
  expect(result.current.data).toBeNull();
@@ -198,7 +205,8 @@ describe("useFeedLoader", () => {
198
205
  zappPipes: { "test://testfakeurl2": mockZappPipesData },
199
206
  };
200
207
 
201
- rerender({ store: store2 });
208
+ store = store2;
209
+ rerender({ feedUrl });
202
210
 
203
211
  loadPipesDataSpy.mockRestore();
204
212
  useDispatchSpy.mockRestore();
@@ -209,12 +217,6 @@ describe("useFeedLoader", () => {
209
217
  const feedUrl = "test://testfakeurl";
210
218
  const feedUrlWithNext = "test://withnexttestfakeurl";
211
219
 
212
- const wrapper: React.FC<any> = ({ children, ...props }) => (
213
- <WrappedWithProviders store={props.store || {}}>
214
- {children}
215
- </WrappedWithProviders>
216
- );
217
-
218
220
  describe("reloadData", () => {
219
221
  it("Tries to reload data in the redux store", () => {
220
222
  const loadPipesDataSpy = jest
@@ -230,10 +232,17 @@ describe("useFeedLoader", () => {
230
232
  zappPipes: { [feedUrl]: "foobar" },
231
233
  };
232
234
 
233
- const { result } = renderHook(() => useFeedLoader({ feedUrl }), {
234
- wrapper,
235
- initialProps: { store: initialStore },
236
- });
235
+ const store = initialStore;
236
+
237
+ const wrapper = createWrapper(() => store);
238
+
239
+ const { result } = renderHook(
240
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
241
+ {
242
+ wrapper,
243
+ initialProps: { feedUrl },
244
+ }
245
+ );
237
246
 
238
247
  const { reloadData } = result.current;
239
248
 
@@ -279,11 +288,14 @@ describe("useFeedLoader", () => {
279
288
  zappPipes: { [feedUrlWithNext]: { data: { next: nextUrl } } },
280
289
  };
281
290
 
291
+ const store = initialStore;
292
+ const wrapper = createWrapper(() => store);
293
+
282
294
  const { result } = renderHook(
283
- () => useFeedLoader({ feedUrl: feedUrlWithNext }),
295
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
284
296
  {
285
297
  wrapper,
286
- initialProps: { store: initialStore },
298
+ initialProps: { feedUrl: feedUrlWithNext },
287
299
  }
288
300
  );
289
301
 
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
 
3
3
  jest.useFakeTimers();
4
4
 
@@ -214,7 +214,7 @@ describe("getSearchContext", () => {
214
214
  });
215
215
 
216
216
  describe("useGetUrlInflater", () => {
217
- const { renderHook } = require("@testing-library/react-hooks");
217
+ const { renderHook } = require("@testing-library/react-native");
218
218
 
219
219
  it("returns original url when mapping is not provided", () => {
220
220
  const { result } = renderHook(() => useGetUrlInflater(), {
@@ -1,20 +1,24 @@
1
1
  import { reactHooksLogger } from "../../logger";
2
- import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/hooks/useZappHooksModalState";
2
+ import { useZappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
3
3
 
4
4
  const logger = reactHooksLogger.addSubsystem("useHookModalScreenData");
5
5
 
6
6
  type VariousScreenData = LegacyNavigationScreenData | ZappRiver | ZappEntry;
7
7
 
8
- export const useHookModalScreenData = (): VariousScreenData | undefined => {
9
- const hookModalState = useZappHooksModalState();
8
+ export const useHookModalScreenData = (
9
+ skipSubscription: boolean
10
+ ): VariousScreenData | undefined => {
11
+ const hookModalState = useZappHookModalStore((state) =>
12
+ skipSubscription ? undefined : state.state
13
+ );
10
14
 
11
- if (!hookModalState.state?.screenData) {
15
+ if (!hookModalState?.screenData) {
12
16
  return;
13
17
  }
14
18
 
15
19
  try {
16
- const screenData = hookModalState.state.screenData?.payload;
17
- const hookPlugin = hookModalState.state.screenData.hookPlugin;
20
+ const screenData = hookModalState.screenData?.payload;
21
+ const hookPlugin = hookModalState.screenData.hookPlugin;
18
22
 
19
23
  if (hookPlugin?.screen_id) {
20
24
  return {
@@ -23,7 +27,7 @@ export const useHookModalScreenData = (): VariousScreenData | undefined => {
23
27
  };
24
28
  }
25
29
 
26
- return hookModalState.state.screenData?.payload;
30
+ return hookModalState.screenData?.payload;
27
31
  } catch (error) {
28
32
  logger.error({
29
33
  message: "Hook modal screen data creation failed",
@@ -34,6 +38,6 @@ export const useHookModalScreenData = (): VariousScreenData | undefined => {
34
38
  jsOnly: true,
35
39
  });
36
40
 
37
- return hookModalState.state.screenData?.payload;
41
+ return hookModalState.screenData?.payload;
38
42
  }
39
43
  };
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { cleanup, renderHook } from "@testing-library/react-hooks";
3
+ import { cleanup, renderHook } from "@testing-library/react-native";
4
4
  import { Provider } from "react-redux";
5
5
  import configureStore from "redux-mock-store";
6
6
 
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import configureStore from "redux-mock-store";
3
3
 
4
4
  const mockStore = configureStore();
@@ -1,11 +1,10 @@
1
1
  import React from "react";
2
2
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
3
- import { renderHook } from "@testing-library/react-hooks";
3
+ import { renderHook } from "@testing-library/react-native";
4
4
  import { isNavBarVisible, useRoute } from "../";
5
5
  import { Provider } from "react-redux";
6
6
  import configureMockStore from "redux-mock-store";
7
7
  import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
8
- import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
9
8
  import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
10
9
  import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
11
10
 
@@ -83,10 +82,44 @@ const hookModalContextState = {
83
82
  },
84
83
  setState: jest.fn(),
85
84
  resetState: jest.fn(),
85
+ hookPresentationMode: null,
86
86
  };
87
87
 
88
88
  const hooksModalPathname = `${ROUTE_TYPES.HOOKS_MODAL}/${hookModalContextState.state.screenData.payload.id}`;
89
89
  const videoModalPathname = `${ROUTE_TYPES.VIDEO_MODAL}/${videoModalNavigator.videoModalState.item.id}`;
90
+
91
+ jest.mock(
92
+ "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext",
93
+ () => {
94
+ const mockState = {
95
+ isRunningInBackground: false,
96
+ setIsRunningInBackground: jest.fn(),
97
+ setIsPresentingFullScreen: jest.fn(),
98
+ isPresentationFullScreen: true,
99
+ isHooksExecutionInProgress: true,
100
+ setIsHooksExecutionInProgress: jest.fn(),
101
+ state: {
102
+ path: "/home",
103
+ screenData: { payload: { id: "hookExecutedInModal" } },
104
+ },
105
+ setState: jest.fn(),
106
+ resetState: jest.fn(),
107
+ hookPresentationMode: null,
108
+ };
109
+
110
+ const mockHook = jest.fn((selector) => {
111
+ return selector ? selector(mockState) : mockState;
112
+ }) as jest.MockedFunction<any> & { getState: () => typeof mockState };
113
+
114
+ mockHook.getState = jest.fn(() => mockState);
115
+
116
+ return {
117
+ useZappHookModalStore: mockHook,
118
+ zappHookModalStore: mockHook,
119
+ };
120
+ }
121
+ );
122
+
90
123
  const mockStore = configureMockStore();
91
124
 
92
125
  const store = mockStore({
@@ -125,13 +158,11 @@ const videoModalWrapper = ({ children }) => (
125
158
 
126
159
  const hookModalWrapper = ({ children }) => (
127
160
  <Provider store={store}>
128
- <ZappHookModalContext.ReactContext.Provider value={hookModalContextState}>
129
- <NavigationContext.Provider value={hookModalNavigator}>
130
- <PathnameContext.Provider value={hooksModalPathname}>
131
- {children}
132
- </PathnameContext.Provider>
133
- </NavigationContext.Provider>
134
- </ZappHookModalContext.ReactContext.Provider>
161
+ <NavigationContext.Provider value={hookModalNavigator}>
162
+ <PathnameContext.Provider value={hooksModalPathname}>
163
+ {children}
164
+ </PathnameContext.Provider>
165
+ </NavigationContext.Provider>
135
166
  </Provider>
136
167
  );
137
168
 
@@ -1,5 +1,6 @@
1
- import { useContext, useEffect, useMemo, useRef } from "react";
1
+ import { useEffect, useMemo, useRef } from "react";
2
2
  import { BackHandler } from "react-native";
3
+ import { shallow } from "zustand/shallow";
3
4
 
4
5
  import {
5
6
  useContentTypes,
@@ -8,13 +9,13 @@ import {
8
9
  import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
9
10
 
10
11
  import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
11
- import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
12
- import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
12
+ import { useZappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
13
13
  import { HOOKS_EVENTS } from "../../appUtils/HooksManager/constants";
14
14
  import { getRiverFromRoute, getTargetRoute } from "../../navigationUtils";
15
15
  import { useConnectionInfo } from "../connection";
16
16
 
17
17
  import { isTV, isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
18
+ import { pick } from "@applicaster/zapp-react-native-utils/utils";
18
19
  import { useNavbarState } from "../screen";
19
20
  import { useRivers } from "../state";
20
21
  import { useLayoutVersion } from "../layout";
@@ -168,7 +169,17 @@ export const useZappHooksForEntry = (
168
169
  setIsHooksExecutionInProgress,
169
170
  setIsPresentingFullScreen,
170
171
  setIsRunningInBackground,
171
- }: HookModalContextT = useContext(ZappHookModalContext.ReactContext);
172
+ } = useZappHookModalStore(
173
+ (state) =>
174
+ pick(state, [
175
+ "setState",
176
+ "resetState",
177
+ "setIsHooksExecutionInProgress",
178
+ "setIsPresentingFullScreen",
179
+ "setIsRunningInBackground",
180
+ ]),
181
+ shallow
182
+ );
172
183
 
173
184
  const plugins = usePlugins();
174
185
  const rivers = useRivers();
@@ -54,7 +54,9 @@ export const useRoute = (
54
54
 
55
55
  const modalScreenData = modalState.screen;
56
56
 
57
- const hookModalScreenData = useHookModalScreenData();
57
+ const hookModalScreenData = useHookModalScreenData(
58
+ !isHookModalPathname(pathname)
59
+ );
58
60
 
59
61
  const videoModalScreenData =
60
62
  navigator?.videoModalState?.item &&
@@ -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 { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
3
3
 
4
4
  import { ON_HOLD_INTERVAL, SEEK_TYPE, SKIP_TIME_BASE } from "../const";
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
3
3
  import { useTapSeek } from "../useTapSeek";
4
4
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { cleanup, renderHook } from "@testing-library/react-hooks";
3
+ import { cleanup, renderHook } from "@testing-library/react-native";
4
4
  import configureStore from "redux-mock-store";
5
5
  import { Provider } from "react-redux";
6
6
 
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { renderHook, cleanup } from "@testing-library/react-hooks";
2
+ import { renderHook, cleanup } from "@testing-library/react-native";
3
3
  import configureStore from "redux-mock-store";
4
4
  import { Provider } from "react-redux";
5
5
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Provider } from "react-redux";
3
- import { renderHook } from "@testing-library/react-hooks";
3
+ import { renderHook } from "@testing-library/react-native";
4
4
  import configureStore from "redux-mock-store";
5
5
  import { thunk } from "redux-thunk";
6
6
 
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
 
3
3
  jest.mock(
4
4
  "@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration",
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import configureStore from "redux-mock-store";
3
3
 
4
4
  const mockStore = configureStore();
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Provider } from "react-redux";
3
- import { renderHook } from "@testing-library/react-hooks";
3
+ import { renderHook } from "@testing-library/react-native";
4
4
  import configureStore from "redux-mock-store";
5
5
  import { thunk } from "redux-thunk";
6
6
 
@@ -1,5 +1,5 @@
1
1
  import { usePrevious, useIsInitialRender } from "../";
2
- import { renderHook, cleanup } from "@testing-library/react-hooks";
2
+ import { renderHook, cleanup } from "@testing-library/react-native";
3
3
 
4
4
  describe("usePrevious", () => {
5
5
  it("renders", () => {
@@ -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", () => {
@@ -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