@applicaster/quick-brick-core 12.0.0-alpha.5251355865 → 12.0.0-alpha.5335460000

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.
@@ -91,9 +91,7 @@ const getActionInitialStateSetters = (key) => {
91
91
  const now = performance.now();
92
92
 
93
93
  logger.info({
94
- message: `Invocation Started - action plugin ${key}, pluginId: ${
95
- subscription.pluginId
96
- }`,
94
+ message: `Invocation Started - action plugin ${key}, pluginId: ${subscription.pluginId}`,
97
95
  });
98
96
 
99
97
  const promiseFunc = subscription[key];
@@ -323,7 +323,7 @@ describe("asset cache", () => {
323
323
 
324
324
  expect(saveCacheData).toHaveBeenCalledWith(
325
325
  layoutId,
326
- newFiles.filter(({ url }) => !url.includes("fail")),
326
+ newFiles.filter(({ url }) => !url.includes("fail"))
327
327
  );
328
328
  });
329
329
 
@@ -143,7 +143,12 @@ export async function cacheAssets({
143
143
 
144
144
  newCacheState.forEach(({ file, url }) => (urlFileMap[url] = file));
145
145
 
146
- const updatedLayout = remapAssetPath(layoutAssets, layout, urlFileMap, "layoutAssets");
146
+ const updatedLayout = remapAssetPath(
147
+ layoutAssets,
148
+ layout,
149
+ urlFileMap,
150
+ "layoutAssets"
151
+ );
147
152
 
148
153
  const updatedPluginConfigurations = remapAssetPath(
149
154
  pluginAssets,
@@ -169,6 +174,8 @@ export async function cacheAssets({
169
174
 
170
175
  return { layout, pluginConfigurations, cellStyles };
171
176
  } finally {
172
- log_verbose(`cacheAssets: caching assets took ${performance.now() - time} ms`);
177
+ log_verbose(
178
+ `cacheAssets: caching assets took ${performance.now() - time} ms`
179
+ );
173
180
  }
174
181
  }
@@ -1,7 +1,4 @@
1
- import {
2
- useActions,
3
- usePickFromState,
4
- } from "@applicaster/zapp-react-native-redux/hooks";
1
+ import { useActions } from "@applicaster/zapp-react-native-redux/hooks";
5
2
  import * as R from "ramda";
6
3
  import * as React from "react";
7
4
  import axios from "axios";
@@ -28,6 +25,7 @@ import {
28
25
  } from "../../helpers";
29
26
 
30
27
  import { log_error, log_info } from "../../logger";
28
+ import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks/state";
31
29
 
32
30
  const getFeed = (query) => ({
33
31
  content: { src: query.data_source },
@@ -60,7 +58,7 @@ export function usePresentSchemeHandler({
60
58
  feedUrl: data_source,
61
59
  });
62
60
 
63
- const { rivers } = usePickFromState(["rivers"]);
61
+ const rivers = useRivers();
64
62
  const screenRiver = findRiver({ screen_id, rivers });
65
63
  const dispatch = useDispatch();
66
64
 
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { render, waitFor, cleanup } from "@testing-library/react-native";
2
+ import { cleanup, render, waitFor } from "@testing-library/react-native";
3
3
 
4
4
  const theme = {
5
5
  screen_margin_top: 0,
@@ -8,6 +8,8 @@ const theme = {
8
8
 
9
9
  const plugins = [];
10
10
 
11
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
12
+
11
13
  jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
12
14
  useTheme: jest.fn(() => theme),
13
15
  }));
@@ -64,6 +64,8 @@ import { ZappPipesEntryContext } from "@applicaster/zapp-react-native-ui-compone
64
64
  import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
65
65
  import { inflateUrl } from "@applicaster/zapp-react-native-ui-components/Components/LinkHandler/LinkHandler";
66
66
  import { useModalStore } from "@applicaster/zapp-react-native-utils/modalState";
67
+ import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
68
+ import { QBUIComponentEvents } from "@applicaster/zapp-react-native-ui-components/events";
67
69
 
68
70
  const logger = coreAppLogger.addSubsystem("Navigator");
69
71
 
@@ -130,6 +132,10 @@ export function NavigationProvider({ children }: Props) {
130
132
 
131
133
  const online = useConnectionInfo(true);
132
134
 
135
+ const replaceEvent = useSubscriberFor(
136
+ QBUIComponentEvents.navigatorReplaceItem
137
+ );
138
+
133
139
  React.useEffect(() => {
134
140
  stateRef.current = state;
135
141
  pathnameRef.current = pathname;
@@ -167,7 +173,7 @@ export function NavigationProvider({ children }: Props) {
167
173
  [rivers, homeRiver]
168
174
  );
169
175
 
170
- const getStack = () => [...stateRef?.current?.stack?.mainStack];
176
+ const getStack = () => [...state?.stack?.mainStack];
171
177
 
172
178
  const openVideoModal = (
173
179
  item: ZappEntry,
@@ -259,6 +265,7 @@ export function NavigationProvider({ children }: Props) {
259
265
  item?.id !==
260
266
  legacyScreenData(state?.location?.state as NavigationScreenData)?.id
261
267
  ) {
268
+ replaceEvent();
262
269
  navigateTo(item, ACTIONS.REPLACE, options);
263
270
  }
264
271
  };
@@ -275,7 +282,7 @@ export function NavigationProvider({ children }: Props) {
275
282
  route.includes(pathname)
276
283
  );
277
284
 
278
- return pathnameStackIndex > 1;
285
+ return pathnameStackIndex >= 1;
279
286
  }
280
287
 
281
288
  if (!Number.isNaN(filteredStack?.length)) {
@@ -407,9 +414,12 @@ export function NavigationProvider({ children }: Props) {
407
414
  }
408
415
  };
409
416
 
410
- const handleHookCancel = ({ hookPlugin }, dispose) => {
411
- if (hookPlugin?.lastHook) {
412
- dispose();
417
+ const handleHookCancel = ({ hookPlugin, callback }, dispose) => {
418
+ dispose();
419
+ setStartUpHooks(false);
420
+
421
+ if (callback && typeof callback === "function") {
422
+ callback();
413
423
  }
414
424
 
415
425
  if (hookPlugin.isModalHook()) {
@@ -475,7 +485,13 @@ export function NavigationProvider({ children }: Props) {
475
485
  return false;
476
486
  }, [pluginConfigurations, plugins, rivers]);
477
487
 
478
- const [startUpHooks, setStartUpHooks] = React.useState(checkStartUpHooks);
488
+ const [startUpHooks, _setStartUpHooks] = React.useState(checkStartUpHooks);
489
+ const currentStartUpHooks = React.useRef(checkStartUpHooks);
490
+
491
+ const setStartUpHooks = (value) => {
492
+ _setStartUpHooks(value);
493
+ currentStartUpHooks.current = value;
494
+ };
479
495
 
480
496
  const handleHookComplete =
481
497
  (navigationAction, targetRoute, { screen, options }) =>
@@ -483,7 +499,7 @@ export function NavigationProvider({ children }: Props) {
483
499
  if (hookPlugin?.lastHook) {
484
500
  dispose({ disposeAll: true });
485
501
 
486
- startUpHooks && setStartUpHooks(false);
502
+ startUpHooks.current && setStartUpHooks(false);
487
503
  }
488
504
 
489
505
  dispatch(
@@ -592,7 +608,10 @@ export function NavigationProvider({ children }: Props) {
592
608
  targetScreen: screen,
593
609
  rivers,
594
610
  plugins,
595
- startUpHooksData: { startUpHooks, setStartUpHooks },
611
+ startUpHooksData: {
612
+ startUpHooks: currentStartUpHooks.current,
613
+ setStartUpHooks,
614
+ },
596
615
  };
597
616
 
598
617
  HooksManager(hooksOptions)
@@ -665,15 +684,15 @@ export function NavigationProvider({ children }: Props) {
665
684
 
666
685
  // It will only work for the regular stack and pathname, It won't work for modals
667
686
  // TODO: integrate video/hook and regular modal into stack.
668
- const getStackForPathname = React.useCallback((pathname: string):
669
- | NavigationScreenState
670
- | undefined => {
671
- const stack = getStack();
687
+ const getStackForPathname = (
688
+ pathname: string
689
+ ): NavigationScreenState | undefined => {
690
+ const stack = [...state?.stack?.mainStack];
672
691
 
673
692
  const currentStack = stack.find(({ route }) => route === pathname);
674
693
 
675
694
  return currentStack;
676
- }, []);
695
+ };
677
696
 
678
697
  const navigator: QuickBrickAppNavigator = React.useMemo(
679
698
  () => ({
@@ -717,6 +736,7 @@ export function NavigationProvider({ children }: Props) {
717
736
  replaceTop,
718
737
  getStack,
719
738
  getStackForPathname,
739
+ mainStack: state.stack.mainStack,
720
740
  }),
721
741
  [rivers, plugins, JSON.stringify(state), appLaunched, startUpHooks]
722
742
  );
@@ -5,6 +5,9 @@ import { createStore } from "redux";
5
5
  import { Provider } from "react-redux";
6
6
 
7
7
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
+ import { getByTestId } from "@applicaster/zapp-react-native-utils/testUtils/getByTestId";
9
+ // @TODO @szhigunov to complete the migration to @testing-library/react-native
10
+ // import { act, waitFor } from "@testing-library/react-native";
8
11
 
9
12
  const rivers = {
10
13
  A1234: {
@@ -151,37 +154,58 @@ const failingHook = {
151
154
  name: "failing hook",
152
155
  };
153
156
 
157
+ // const store = {
158
+ // rivers,
159
+ // plugins: [hookPlugin, hookPlugin2, failingHook],
160
+ // };
161
+
162
+ const store = createStore(() => ({
163
+ appData: { layoutVersion: "v1" },
164
+ contentTypes: null,
165
+ rivers,
166
+ plugins: [hookPlugin, hookPlugin2, failingHook],
167
+ appState: { appLaunched: true },
168
+ }));
169
+
154
170
  const ContextConsumer = () => {
155
171
  const { state, ...navigator } = useNavigation();
156
172
 
157
- const renderHook = () => {
158
- if (navigator.currentRoute.includes("/hooks/")) {
159
- const { hookPlugin, payload, callback } = navigator.screenData;
160
- const Component = hookPlugin.module.Component;
173
+ let renderHook;
161
174
 
162
- return <Component payload={payload} callback={callback} />;
163
- }
175
+ if (navigator.currentRoute.includes("/hooks/")) {
176
+ const { hookPlugin, payload, callback } = navigator.screenData;
177
+ const Component = hookPlugin.module.Component;
164
178
 
165
- return null;
166
- };
179
+ renderHook = <Component payload={payload} callback={callback} />;
180
+ }
181
+
182
+ renderHook = null;
183
+
184
+ const WrapperView: any = "View";
167
185
 
168
186
  return (
169
- <View navigator={navigator} state={state}>
170
- {renderHook()}
171
- </View>
187
+ <WrapperView testID="WrapperView" navigator={navigator} state={state}>
188
+ {renderHook}
189
+ </WrapperView>
172
190
  );
173
191
  };
174
192
 
175
- const store = createStore(() => ({
176
- appData: { layoutVersion: "v1" },
177
- contentTypes: null,
178
- rivers,
179
- plugins: [hookPlugin, hookPlugin2, failingHook],
180
- appState: { appLaunched: true },
181
- }));
182
-
183
193
  const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {});
184
194
 
195
+ // const renderContextConsumer = (_store = store) => {
196
+ // return renderWithProviders(<ContextConsumer />, _store);
197
+ // };
198
+
199
+ const renderContextConsumer = (_store = store) => {
200
+ return create(
201
+ <Provider store={store}>
202
+ <NavigationProvider>
203
+ <ContextConsumer />
204
+ </NavigationProvider>
205
+ </Provider>
206
+ );
207
+ };
208
+
185
209
  afterAll(() => {
186
210
  consoleSpy.mockReset();
187
211
  });
@@ -189,86 +213,39 @@ afterAll(() => {
189
213
  describe("<NavigationProvider />", () => {
190
214
  let wrapper;
191
215
 
192
- it("renders correctly", () => {
216
+ it("navigator contains expected properties", () => {
193
217
  act(() => {
194
- wrapper = create(
195
- <Provider store={store}>
196
- <NavigationProvider>
197
- <ContextConsumer />
198
- </NavigationProvider>
199
- </Provider>
200
- );
218
+ wrapper = renderContextConsumer();
201
219
  });
202
220
 
203
- expect(wrapper.toJSON()).toMatchSnapshot();
204
- });
221
+ const view = getByTestId(wrapper, "WrapperView");
205
222
 
206
- describe("navigator Properties", () => {
207
- act(() => {
208
- wrapper = create(
209
- <Provider store={store}>
210
- <NavigationProvider>
211
- <ContextConsumer />
212
- </NavigationProvider>
213
- </Provider>
214
- );
215
- });
216
-
217
- const view = wrapper.root.findByType(View);
218
223
  const { navigator } = view.props;
224
+ expect(navigator.activeRiver).toEqual(rivers.B4567);
225
+ expect(navigator.currentRoute).toEqual("/river/B4567");
226
+ expect(navigator.previousAction).toEqual("REPLACE");
219
227
 
220
- it("exposes the active river", () => {
221
- expect(navigator.activeRiver).toEqual(rivers.B4567);
222
- });
223
-
224
- it("exposes the currentRoute", () => {
225
- expect(navigator.currentRoute).toEqual("/river/B4567");
228
+ expect(navigator.screenData).toEqual({
229
+ ...rivers.B4567,
230
+ targetScreen: rivers.B4567,
226
231
  });
227
232
 
228
- it("exposes the previous action", () => {
229
- expect(navigator.previousAction).toEqual("REPLACE");
230
- });
231
-
232
- it("exposes the screen data", () => {
233
- expect(navigator.screenData).toEqual(rivers.B4567);
234
- });
235
-
236
- it("exposes a routeData function", () => {
237
- const consoleSpy = jest
238
- .spyOn(console, "warn")
239
- .mockImplementation(jest.fn());
240
-
241
- expect(navigator.routeData()).toEqual(rivers.B4567);
242
- consoleSpy.mockRestore();
243
- });
244
-
245
- it("warns in the console when calling navigator.routeData()", () => {
246
- const consoleSpy = jest
247
- .spyOn(console, "warn")
248
- .mockImplementation(jest.fn());
249
-
250
- navigator.routeData();
251
- expect(consoleSpy.mock.calls).toMatchSnapshot();
252
-
253
- consoleSpy.mockRestore();
233
+ expect(navigator.routeData()).toEqual({
234
+ ...rivers.B4567,
235
+ targetScreen: rivers.B4567,
254
236
  });
255
237
  });
256
238
 
257
239
  describe("pushing a new route", () => {
258
240
  act(() => {
259
- wrapper = create(
260
- <Provider store={store}>
261
- <NavigationProvider>
262
- <ContextConsumer />
263
- </NavigationProvider>
264
- </Provider>
265
- );
241
+ wrapper = renderContextConsumer();
266
242
  });
267
243
 
268
- const view = wrapper.root.findByType(View);
244
+ it("sets the data to that route", async () => {
245
+ const view = getByTestId(wrapper, "WrapperView");
269
246
 
270
- it("sets the data to that route", () => {
271
247
  act(() => view.props.navigator.push(rivers.A1234));
248
+
272
249
  expect(view.props.navigator).toHaveProperty("activeRiver", rivers.A1234);
273
250
 
274
251
  expect(view.props.navigator).toHaveProperty(
@@ -276,23 +253,21 @@ describe("<NavigationProvider />", () => {
276
253
  "/river/B4567/river/A1234"
277
254
  );
278
255
 
279
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
280
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(2);
256
+ expect(view.props.navigator.screenData).toEqual({
257
+ ...rivers.A1234,
258
+ targetScreen: rivers.A1234,
259
+ });
260
+
261
+ expect(view.props.state.stack.mainStack).toHaveLength(2);
281
262
  });
282
263
  });
283
264
 
284
265
  describe("replacing a current route", () => {
285
266
  act(() => {
286
- wrapper = create(
287
- <Provider store={store}>
288
- <NavigationProvider>
289
- <ContextConsumer />
290
- </NavigationProvider>
291
- </Provider>
292
- );
267
+ wrapper = renderContextConsumer();
293
268
  });
294
269
 
295
- const view = wrapper.root.findByType(View);
270
+ const view = getByTestId(wrapper, "WrapperView");
296
271
 
297
272
  it("sets the data to that route", () => {
298
273
  act(() => view.props.navigator.replace(rivers.A1234));
@@ -303,24 +278,22 @@ describe("<NavigationProvider />", () => {
303
278
  "/river/A1234"
304
279
  );
305
280
 
306
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
307
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(1);
281
+ expect(view.props.navigator.screenData).toEqual({
282
+ ...rivers.A1234,
283
+ targetScreen: rivers.A1234,
284
+ });
285
+
286
+ expect(view.props.state.stack.mainStack).toHaveLength(1);
308
287
  });
309
288
  });
310
289
 
311
290
  describe("going back", () => {
312
291
  describe("when there is no previous route", () => {
313
292
  act(() => {
314
- wrapper = create(
315
- <Provider store={store}>
316
- <NavigationProvider>
317
- <ContextConsumer />
318
- </NavigationProvider>
319
- </Provider>
320
- );
293
+ wrapper = renderContextConsumer();
321
294
  });
322
295
 
323
- const view = wrapper.root.findByType(View);
296
+ const view = getByTestId(wrapper, "WrapperView");
324
297
 
325
298
  it("returns false when calling canGoBack", () => {
326
299
  let result;
@@ -345,23 +318,21 @@ describe("<NavigationProvider />", () => {
345
318
  "/river/B4567"
346
319
  );
347
320
 
348
- expect(view.props.navigator.screenData).toEqual(rivers.B4567);
349
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(1);
321
+ expect(view.props.navigator.screenData).toEqual({
322
+ ...rivers.B4567,
323
+ targetScreen: rivers.B4567,
324
+ });
325
+
326
+ expect(view.props.state.stack.mainStack).toHaveLength(1);
350
327
  });
351
328
  });
352
329
 
353
330
  describe("when there is one route and we're going in a hook", () => {
354
331
  act(() => {
355
- wrapper = create(
356
- <Provider store={store}>
357
- <NavigationProvider>
358
- <ContextConsumer />
359
- </NavigationProvider>
360
- </Provider>
361
- );
332
+ wrapper = renderContextConsumer();
362
333
  });
363
334
 
364
- const view = wrapper.root.findByType(View);
335
+ const view = getByTestId(wrapper, "WrapperView");
365
336
  act(() => view.props.navigator.replace(rivers.A1234));
366
337
 
367
338
  it("returns true when calling goBack()", () => {
@@ -387,25 +358,20 @@ describe("<NavigationProvider />", () => {
387
358
  );
388
359
 
389
360
  expect(view.props.navigator.screenData).toEqual(rivers.A1234);
390
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(1);
361
+ expect(view.props.state.stack.mainStack).toHaveLength(1);
391
362
  });
392
363
  });
393
364
 
394
365
  describe("when there is a previous route", () => {
395
366
  act(() => {
396
- wrapper = create(
397
- <Provider store={store}>
398
- <NavigationProvider>
399
- <ContextConsumer />
400
- </NavigationProvider>
401
- </Provider>
402
- );
367
+ wrapper = renderContextConsumer();
403
368
  });
404
369
 
405
- const view = wrapper.root.findByType(View);
370
+ const view = getByTestId(wrapper, "WrapperView");
406
371
 
407
372
  act(() => view.props.navigator.push(rivers.A1234));
408
- act(() => view.props.navigator.push(rivers.B4567));
373
+
374
+ act(() => view.props.navigator.push({ ...rivers.B4567, id: "B4567-1" }));
409
375
 
410
376
  it("returns true when calling canGoBack", () => {
411
377
  let result;
@@ -414,11 +380,27 @@ describe("<NavigationProvider />", () => {
414
380
  result = view.props.navigator.canGoBack();
415
381
  });
416
382
 
417
- expect(result).toBe(true);
383
+ expect(result).toBeTruthy();
384
+ });
385
+
386
+ it("returns true when calling canGoBack(false, pathname)", () => {
387
+ let result;
388
+
389
+ act(() => {
390
+ result = view.props.navigator.canGoBack(false, "B4567-1");
391
+ });
392
+
393
+ expect(result).toBeTruthy();
394
+
395
+ act(() => {
396
+ result = view.props.navigator.canGoBack(false, "A1234");
397
+ });
398
+
399
+ expect(result).toBeTruthy();
418
400
  });
419
401
 
420
402
  it("returns to the previous route", () => {
421
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(3);
403
+ expect(view.props.state.stack.mainStack).toHaveLength(3);
422
404
 
423
405
  act(() => view.props.navigator.goBack());
424
406
 
@@ -432,141 +414,71 @@ describe("<NavigationProvider />", () => {
432
414
  "/river/B4567/river/A1234"
433
415
  );
434
416
 
435
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
436
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(2);
417
+ expect(view.props.navigator.screenData).toEqual({
418
+ ...rivers.A1234,
419
+ targetScreen: rivers.A1234,
420
+ });
421
+
422
+ expect(view.props.state.stack.mainStack).toHaveLength(2);
437
423
  });
438
424
  });
439
425
 
440
426
  describe("when there is a previous route and there are hooks", () => {
441
427
  act(() => {
442
- wrapper = create(
443
- <Provider store={store}>
444
- <NavigationProvider>
445
- <ContextConsumer />
446
- </NavigationProvider>
447
- </Provider>
448
- );
428
+ wrapper = renderContextConsumer();
449
429
  });
450
430
 
451
- const view = wrapper.root.findByType(View);
431
+ const view = getByTestId(wrapper, "WrapperView");
452
432
  act(() => view.props.navigator.push(rivers.A1234));
453
433
  act(() => view.props.navigator.push(rivers.C0987));
454
434
 
455
435
  it("returns to the previous entry in the stack which is not a hook", () => {
456
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(5);
436
+ expect(view.props.state.stack.mainStack).toHaveLength(3);
457
437
 
458
438
  expect(view.props.navigator).toHaveProperty(
459
439
  "currentRoute",
460
440
  "/river/B4567/river/A1234/river/C0987"
461
441
  );
462
442
 
463
- expect(view.props.navigator.screenData).toEqual(rivers.C0987);
443
+ expect(view.props.navigator.screenData).toMatchObject({
444
+ ...rivers.C0987,
445
+ targetScreen: rivers.C0987,
446
+ });
464
447
 
465
448
  act(() => view.props.navigator.goBack());
466
449
 
467
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(2);
450
+ expect(view.props.state.stack.mainStack).toHaveLength(2);
468
451
 
469
452
  expect(view.props.navigator).toHaveProperty(
470
453
  "currentRoute",
471
454
  "/river/B4567/river/A1234"
472
455
  );
473
456
 
474
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
457
+ expect(view.props.navigator.screenData).toMatchObject({
458
+ ...rivers.A1234,
459
+ targetScreen: rivers.A1234,
460
+ });
475
461
  });
476
462
  });
477
463
  });
478
464
 
479
- describe("when changing navBar visibility", () => {
480
- act(() => {
481
- wrapper = create(
482
- <Provider store={store}>
483
- <NavigationProvider>
484
- <ContextConsumer />
485
- </NavigationProvider>
486
- </Provider>
487
- );
488
- });
489
-
490
- const view = wrapper.root.findByType(View);
491
-
492
- it("updates the navbar visibility attribute", () => {
493
- act(() => view.props.navigator.hideNavBar());
494
- expect(view.props.state.options.navBar.visible).toBe(false);
495
- expect(view.props.navigator.isNavBarVisible).toBe(false);
496
- });
497
- });
498
-
499
- describe("set the navbar title", () => {
500
- act(() => {
501
- wrapper = create(
502
- <Provider store={store}>
503
- <NavigationProvider>
504
- <ContextConsumer />
505
- </NavigationProvider>
506
- </Provider>
507
- );
508
- });
509
-
510
- const view = wrapper.root.findByType(View);
511
-
512
- it("updates the navbar title attribute", () => {
513
- const screenTitle = "Screen Title";
514
- act(() => view.props.navigator.setScreenTitle(screenTitle));
515
- expect(view.props.state.options.navBar.title).toBe(screenTitle);
516
- expect(view.props.navigator.screenTitle).toBe(screenTitle);
517
- });
518
- });
519
-
520
- describe("set the navbar summary", () => {
521
- act(() => {
522
- wrapper = create(
523
- <Provider store={store}>
524
- <NavigationProvider>
525
- <ContextConsumer />
526
- </NavigationProvider>
527
- </Provider>
528
- );
529
- });
530
-
531
- const view = wrapper.root.findByType(View);
532
-
533
- it("updates the navbar summary attribute", () => {
534
- const screenSummary = "Screen Summary";
535
- act(() => view.props.navigator.setScreenSummary(screenSummary));
536
- expect(view.props.state.options.navBar.summary).toBe(screenSummary);
537
- expect(view.props.navigator.screenSummary).toBe(screenSummary);
538
- });
539
- });
540
-
541
- describe.only("modal feature", () => {
465
+ describe("modal feature", () => {
542
466
  it("sets the modalState when opening a modal", () => {
543
467
  act(() => {
544
- wrapper = create(
545
- <Provider store={store}>
546
- <NavigationProvider>
547
- <ContextConsumer />
548
- </NavigationProvider>
549
- </Provider>
550
- );
468
+ wrapper = renderContextConsumer();
551
469
  });
552
470
 
553
- const view = wrapper.root.findByType(View);
471
+ const view = getByTestId(wrapper, "WrapperView");
554
472
  act(() => view.props.navigator.openModal({ item: rivers.A1234 }));
555
473
  expect(view.props.navigator.get).toMatchSnapshot();
556
474
  });
557
475
 
558
476
  it("removes the visible flag when dismissing a modal", () => {
559
477
  act(() => {
560
- wrapper = create(
561
- <Provider store={store}>
562
- <NavigationProvider>
563
- <ContextConsumer />
564
- </NavigationProvider>
565
- </Provider>
566
- );
478
+ wrapper = renderContextConsumer();
567
479
  });
568
480
 
569
- const view = wrapper.root.findByType(View);
481
+ const view = getByTestId(wrapper, "WrapperView");
570
482
  act(() => view.props.navigator.openModal({ item: rivers.A1234 }));
571
483
  expect(view.props.navigator.getModalState()).toMatchSnapshot();
572
484
  act(() => view.props.navigator.dismissModal());
@@ -576,16 +488,10 @@ describe("<NavigationProvider />", () => {
576
488
 
577
489
  it("should reset state to initial when dismissing a modal ( closeModalBottomSheet ) opened by openModalBottomSheet", () => {
578
490
  act(() => {
579
- wrapper = create(
580
- <Provider store={store}>
581
- <NavigationProvider>
582
- <ContextConsumer />
583
- </NavigationProvider>
584
- </Provider>
585
- );
491
+ wrapper = renderContextConsumer();
586
492
  });
587
493
 
588
- const view = wrapper.root.findByType(View);
494
+ const view = getByTestId(wrapper, "WrapperView");
589
495
 
590
496
  act(() =>
591
497
  view.props.navigator.openModalBottomSheet({
@@ -3,7 +3,10 @@ import * as R from "ramda";
3
3
 
4
4
  import { NetInfoState } from "@react-native-community/netinfo";
5
5
  import { NETWORK_HOOKS_KEYS } from "./const";
6
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
6
+ import {
7
+ isVizioPlatform,
8
+ platformSelect,
9
+ } from "@applicaster/zapp-react-native-utils/reactUtils";
7
10
  import { Platform } from "react-native";
8
11
 
9
12
  type ConnectionStatus = boolean;
@@ -203,6 +206,18 @@ export const subscribeToDeviceNetworkChanges = (callback: NetCb) => {
203
206
  registeredListener = webapis.network.addNetworkStateChangeListener(
204
207
  samsungNetworkChangeHandler(callback)
205
208
  );
209
+
210
+ return;
211
+ }
212
+
213
+ if (isVizioPlatform()) {
214
+ window.addEventListener("online", function () {
215
+ callback({ online: true });
216
+ });
217
+
218
+ window.addEventListener("offline", function () {
219
+ callback({ online: false });
220
+ });
206
221
  }
207
222
  };
208
223
 
@@ -214,5 +229,12 @@ export const subscribeToDeviceNetworkChanges = (callback: NetCb) => {
214
229
  export const unsubscribeToDeviceNetworkChanges = (id = registeredListener) => {
215
230
  if (hasTizenAPIs()) {
216
231
  webapis.network.removeNetworkStateChangeListener(id);
232
+
233
+ return;
234
+ }
235
+
236
+ if (isVizioPlatform()) {
237
+ window.removeEventListener("online", function () {});
238
+ window.removeEventListener("offline", function () {});
217
239
  }
218
240
  };
@@ -1,13 +1,19 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<RouteManager /> renders correctly 1`] = `
4
- <WithProvider
5
- screenData={
6
- Object {
7
- "id": "A1234",
8
- }
4
+ <RNCSafeAreaProvider
5
+ onInsetsChange={[Function]}
6
+ style={
7
+ Array [
8
+ Object {
9
+ "flex": 1,
10
+ },
11
+ undefined,
12
+ ]
9
13
  }
10
- screenId="A1234"
11
- screenType="river"
12
- />
14
+ >
15
+ <View
16
+ testID="river"
17
+ />
18
+ </RNCSafeAreaProvider>
13
19
  `;
@@ -1,31 +1,42 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
3
- import { shallowToJson } from "enzyme-to-json";
4
2
 
5
- import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
3
+ const {
4
+ ScreenResolver,
5
+ } = require("@applicaster/zapp-react-native-ui-components/Components/ScreenResolver");
6
+
7
+ import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
6
8
 
7
9
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
8
10
  useNavigation: jest.fn(() => ({
9
11
  screenId: { id: "A1234" },
10
12
  currentRoute: "/river/A1234",
11
13
  screenData: { id: "A1234" },
14
+ videoModalState: { mode: "WINDOWED" },
15
+ })),
16
+ useRoute: jest.fn(() => ({
17
+ pathname: "/river/A1234",
18
+ screenData: { id: "A1234-screenData" },
12
19
  })),
13
20
  }));
14
21
 
15
22
  const { RouteManager } = require("../");
16
23
 
17
24
  describe("<RouteManager />", () => {
18
- const wrapper = shallow(<RouteManager />);
25
+ let wrapper;
26
+
27
+ beforeEach(() => {
28
+ wrapper = renderWithProviders(<RouteManager />);
29
+ });
19
30
 
20
31
  it("renders correctly", () => {
21
- expect(shallowToJson(wrapper)).toMatchSnapshot();
32
+ expect(wrapper.toJSON()).toMatchSnapshot();
22
33
  });
23
34
 
24
35
  it("passes the correct props to ScreenResolver", () => {
25
- expect(wrapper.find(ScreenResolver).props()).toEqual({
36
+ expect(wrapper.UNSAFE_getByType(ScreenResolver).props).toEqual({
26
37
  screenType: "river",
27
38
  screenId: "A1234",
28
- screenData: { id: "A1234" },
39
+ screenData: { id: "A1234-screenData" },
29
40
  });
30
41
  });
31
42
  });
@@ -4,7 +4,7 @@ import * as R from "ramda";
4
4
  import { getPathAttributes } from "@applicaster/zapp-react-native-utils/navigationUtils";
5
5
  import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
6
6
 
7
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
7
+ import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
8
 
9
9
  type Props = any;
10
10
 
@@ -14,7 +14,8 @@ type Props = any;
14
14
  * @param {Props}: see props above
15
15
  */
16
16
  export const RouteManager = React.memo(function RouteManager(props: Props) {
17
- const { currentRoute: pathname, screenData } = useNavigation();
17
+ const { pathname, screenData } = useRoute();
18
+
18
19
  const pathAttributes = getPathAttributes({ pathname });
19
20
 
20
21
  if (!pathAttributes.length) {
@@ -15,6 +15,11 @@ jest.mock(
15
15
  // This is meant to silence errors with react-native-gesture-handler
16
16
  jest.mock("../ModalProvider/ModalBottomSheet", () => () => null);
17
17
 
18
+ jest.mock(
19
+ "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation",
20
+ () => () => null
21
+ );
22
+
18
23
  jest.mock("react-native-safe-area-context", () => ({
19
24
  SafeAreaProvider: jest.fn(
20
25
  () =>
package/App/index.tsx CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
3
  import {
4
- SafeAreaProvider,
5
4
  initialWindowMetrics,
5
+ SafeAreaProvider,
6
6
  } from "react-native-safe-area-context";
7
7
 
8
8
  import { ErrorBoundary } from "./ErrorBoundary";
@@ -27,6 +27,7 @@ import {
27
27
  import { withURLSchemeContextProvider } from "./DeepLinking/URLSchemeListener/URLSchemeContextProvider";
28
28
  import { appRemoteDataLoader } from "./appRemoteDataLoader";
29
29
  import { withActionExecutor } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
30
+ import { withScreenDataContextProvider } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
30
31
 
31
32
  /**
32
33
  * @typedef {Object} AppOptions
@@ -99,6 +100,7 @@ export function createQuickBrickApp(options): ZappApp {
99
100
  withURLSchemeContextProvider,
100
101
  withNetworkStatusProvider,
101
102
  withNavigationProvider,
103
+ withScreenDataContextProvider,
102
104
  ZappPipesSearchContext.withProvider,
103
105
  InteractionManager,
104
106
  withActionExecutor,
package/const/index.ts CHANGED
@@ -34,3 +34,7 @@ export const requiredSessionKeys = [
34
34
  "userAgent",
35
35
  "version_name",
36
36
  ];
37
+
38
+ export const QUICK_BRICK_NAVBAR = "quick-brick-navbar";
39
+
40
+ export const QUICK_BRICK_CONTENT = "quick-brick-content";
@@ -20,7 +20,6 @@ Object {
20
20
  "isAvailable": null,
21
21
  "nextState": null,
22
22
  },
23
- "isTransitioning": false,
24
23
  },
25
24
  "cellStyles": Object {},
26
25
  "components": Object {
@@ -7,6 +7,10 @@
7
7
  import * as React from "react";
8
8
  import * as R from "ramda";
9
9
  import { Dimensions } from "react-native";
10
+ import {
11
+ isNotEmpty,
12
+ isNotNil,
13
+ } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
10
14
 
11
15
  import {
12
16
  createZappReduxStore,
@@ -27,6 +31,9 @@ import { remoteDataLoader } from "../App/appRemoteDataLoader/remoteDataLoader";
27
31
  import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickBrick";
28
32
  import { isAndroidPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
29
33
 
34
+ const isNotEmptyObject = (value: unknown) =>
35
+ isNotNil(value) && R.is(Object, value) && isNotEmpty(value);
36
+
30
37
  /**
31
38
  * Creates a Zapp App with the provided options
32
39
  * @export
@@ -55,8 +62,8 @@ export function createZappApp(zappAppConfig: ZappAppConfig) {
55
62
 
56
63
  const useTabletLayout =
57
64
  isTablet({ width, height }, width > height ? "landscape" : "portrait") &&
58
- tabletLayout &&
59
- tabletCellStyles;
65
+ isNotEmptyObject(tabletLayout) &&
66
+ isNotEmptyObject(tabletCellStyles);
60
67
 
61
68
  function fetchPluginConfiguration(plugin) {
62
69
  const configuration = R.compose(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/quick-brick-core",
3
- "version": "12.0.0-alpha.5251355865",
3
+ "version": "12.0.0-alpha.5335460000",
4
4
  "description": "Core package for Applicaster's Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -30,13 +30,13 @@
30
30
  },
31
31
  "homepage": "https://github.com/applicaster/quickbrick#readme",
32
32
  "dependencies": {
33
- "@applicaster/applicaster-types": "12.0.0-alpha.5251355865",
34
- "@applicaster/quick-brick-core-plugins": "12.0.0-alpha.5251355865",
35
- "@applicaster/zapp-pipes-v2-client": "12.0.0-alpha.5251355865",
36
- "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5251355865",
37
- "@applicaster/zapp-react-native-redux": "12.0.0-alpha.5251355865",
38
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.5251355865",
39
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.5251355865",
33
+ "@applicaster/applicaster-types": "12.0.0-alpha.5335460000",
34
+ "@applicaster/quick-brick-core-plugins": "12.0.0-alpha.5335460000",
35
+ "@applicaster/zapp-pipes-v2-client": "12.0.0-alpha.5335460000",
36
+ "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5335460000",
37
+ "@applicaster/zapp-react-native-redux": "12.0.0-alpha.5335460000",
38
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.5335460000",
39
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.5335460000",
40
40
  "atob": "^2.1.2",
41
41
  "axios": "^0.28.0",
42
42
  "btoa": "^1.2.1",