@applicaster/quick-brick-core 17.0.0-alpha.1984136194 → 17.0.0-alpha.2451166845

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.
@@ -0,0 +1,103 @@
1
+ import * as React from "react";
2
+ import { Text } from "react-native";
3
+ import { act, render } from "@testing-library/react-native";
4
+
5
+ import { URLSchemeListener } from "../index";
6
+ import { URLSchemeContext } from "../URLSchemeContextProvider";
7
+
8
+ const mockMounts: string[] = [];
9
+ const mockFinishers: Record<string, (callback?: unknown) => void> = {};
10
+
11
+ jest.mock("../../URLSchemeHandler", () => {
12
+ const React = require("react");
13
+
14
+ return {
15
+ URLSchemeHandler: ({ url, onFinish }) => {
16
+ // Mirrors the real scheme handlers: work starts once, on mount.
17
+ React.useEffect(() => {
18
+ mockMounts.push(url);
19
+ mockFinishers[url] = onFinish;
20
+ // eslint-disable-next-line @wogns3623/better-exhaustive-deps/exhaustive-deps
21
+ }, []);
22
+
23
+ return null;
24
+ },
25
+ };
26
+ });
27
+
28
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
29
+ useNavigation: () => ({ startUpHooks: null }),
30
+ }));
31
+
32
+ jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
33
+ useAppSelector: () => true,
34
+ }));
35
+
36
+ const URL_A = "pureflix://open?feed_locator=a&id=1";
37
+ const URL_B = "pureflix://open?feed_locator=b&id=2";
38
+
39
+ const tree = (url: string | null, done: () => void) => (
40
+ <URLSchemeContext.Provider value={{ url, done }}>
41
+ <URLSchemeListener>
42
+ <Text>app</Text>
43
+ </URLSchemeListener>
44
+ </URLSchemeContext.Provider>
45
+ );
46
+
47
+ describe("URLSchemeListener - deep link replaced while being handled", () => {
48
+ beforeEach(() => {
49
+ mockMounts.length = 0;
50
+ Object.keys(mockFinishers).forEach((key) => delete mockFinishers[key]);
51
+ });
52
+
53
+ it("starts a new handler for a new URL", () => {
54
+ const done = jest.fn();
55
+ const { rerender } = render(tree(URL_A, done));
56
+
57
+ rerender(tree(URL_B, done));
58
+
59
+ expect(mockMounts).toEqual([URL_A, URL_B]);
60
+ });
61
+
62
+ it("ignores the finish of a replaced handler and lets the current one finish", () => {
63
+ const done = jest.fn();
64
+ const { rerender } = render(tree(URL_A, done));
65
+
66
+ rerender(tree(URL_B, done));
67
+
68
+ const staleNavigation = jest.fn((d) => d());
69
+
70
+ act(() => mockFinishers[URL_A](staleNavigation));
71
+ act(() => mockFinishers[URL_A]());
72
+
73
+ expect(staleNavigation).not.toHaveBeenCalled();
74
+ expect(done).not.toHaveBeenCalled();
75
+
76
+ const navigation = jest.fn((d) => d());
77
+
78
+ act(() => mockFinishers[URL_B](navigation));
79
+
80
+ expect(navigation).toHaveBeenCalledWith(done);
81
+ expect(done).toHaveBeenCalledTimes(1);
82
+ });
83
+
84
+ it("does not restart the handler when the same URL is set again", () => {
85
+ const done = jest.fn();
86
+ const { rerender } = render(tree(URL_A, done));
87
+
88
+ rerender(tree(URL_A, done));
89
+
90
+ expect(mockMounts).toEqual([URL_A]);
91
+
92
+ act(() => mockFinishers[URL_A]());
93
+
94
+ expect(done).toHaveBeenCalledTimes(1);
95
+ });
96
+
97
+ it("renders the app when there is no URL", () => {
98
+ const { getByText } = render(tree(null, jest.fn()));
99
+
100
+ expect(getByText("app")).toBeTruthy();
101
+ expect(mockMounts).toEqual([]);
102
+ });
103
+ });
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useContext } from "react";
1
+ import React, { useCallback, useContext, useRef } from "react";
2
2
 
3
3
  import { URLSchemeHandler } from "../URLSchemeHandler";
4
4
  import { URLSchemeContext } from "./URLSchemeContextProvider";
@@ -13,19 +13,30 @@ export function URLSchemeListener({ children }: { children: React.ReactNode }) {
13
13
 
14
14
  const appReady = useAppSelector(selectAppReady);
15
15
 
16
+ // The URL currently in the context. A handler compares its own URL with it on finish:
17
+ // a newer deep link may have replaced it while it was still resolving (e.g. loading a feed).
18
+ const latestUrl = useRef(url);
19
+ latestUrl.current = url;
20
+
16
21
  const onFinish = useCallback(
17
22
  (callback) => {
23
+ if (latestUrl.current !== url) {
24
+ // Stale handler: skip its navigation and do not clear the newer URL.
25
+ return;
26
+ }
27
+
18
28
  if (callback && typeof callback === "function") {
19
29
  callback?.(done);
20
30
  } else {
21
31
  done();
22
32
  }
23
33
  },
24
- [url]
34
+ [url, done]
25
35
  );
26
36
 
27
37
  if (url && !navigator.startUpHooks && appReady) {
28
- return <URLSchemeHandler url={url} onFinish={onFinish} />;
38
+ // key: a new URL remounts the handler so that its effects run for that URL.
39
+ return <URLSchemeHandler key={url} url={url} onFinish={onFinish} />;
29
40
  }
30
41
 
31
42
  return children;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/quick-brick-core",
3
- "version": "17.0.0-alpha.1984136194",
3
+ "version": "17.0.0-alpha.2451166845",
4
4
  "description": "Core package for Applicaster's Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -28,13 +28,13 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "17.0.0-alpha.1984136194",
32
- "@applicaster/quick-brick-core-plugins": "17.0.0-alpha.1984136194",
33
- "@applicaster/zapp-pipes-v2-client": "17.0.0-alpha.1984136194",
34
- "@applicaster/zapp-react-native-bridge": "17.0.0-alpha.1984136194",
35
- "@applicaster/zapp-react-native-redux": "17.0.0-alpha.1984136194",
36
- "@applicaster/zapp-react-native-ui-components": "17.0.0-alpha.1984136194",
37
- "@applicaster/zapp-react-native-utils": "17.0.0-alpha.1984136194",
31
+ "@applicaster/applicaster-types": "17.0.0-alpha.2451166845",
32
+ "@applicaster/quick-brick-core-plugins": "17.0.0-alpha.2451166845",
33
+ "@applicaster/zapp-pipes-v2-client": "17.0.0-alpha.2451166845",
34
+ "@applicaster/zapp-react-native-bridge": "17.0.0-alpha.2451166845",
35
+ "@applicaster/zapp-react-native-redux": "17.0.0-alpha.2451166845",
36
+ "@applicaster/zapp-react-native-ui-components": "17.0.0-alpha.2451166845",
37
+ "@applicaster/zapp-react-native-utils": "17.0.0-alpha.2451166845",
38
38
  "atob": "^2.1.2",
39
39
  "axios": "^0.28.0",
40
40
  "btoa": "^1.2.1",