@applicaster/zapp-react-native-utils 16.0.0-alpha.2899709395 → 16.0.0-alpha.3524654973

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "16.0.0-alpha.2899709395",
3
+ "version": "16.0.0-alpha.3524654973",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "16.0.0-alpha.2899709395",
30
+ "@applicaster/applicaster-types": "16.0.0-alpha.3524654973",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -0,0 +1,55 @@
1
+ import { buildUrlWithQuery } from "../withPipesEndpoint";
2
+
3
+ describe("buildUrlWithQuery", () => {
4
+ it("returns the url unchanged when requestParams is null", () => {
5
+ const url = "https://example.com/path";
6
+
7
+ expect(buildUrlWithQuery(url, null)).toBe(url);
8
+ });
9
+
10
+ it("returns the url unchanged when requestParams is undefined", () => {
11
+ const url = "https://example.com/path";
12
+
13
+ expect(buildUrlWithQuery(url, undefined)).toBe(url);
14
+ });
15
+
16
+ it("returns the url unchanged when requestParams has no params", () => {
17
+ const url = "https://example.com/path";
18
+
19
+ expect(buildUrlWithQuery(url, {})).toBe(url);
20
+ expect(buildUrlWithQuery(url, { params: undefined })).toBe(url);
21
+ expect(buildUrlWithQuery(url, { params: null })).toBe(url);
22
+ });
23
+
24
+ it("appends query params to a url without an existing query string", () => {
25
+ expect(
26
+ buildUrlWithQuery("https://example.com/path", {
27
+ params: { foo: "bar", baz: "qux" },
28
+ })
29
+ ).toBe("https://example.com/path?foo=bar&baz=qux");
30
+ });
31
+
32
+ it("merges query params with existing query string params", () => {
33
+ expect(
34
+ buildUrlWithQuery("https://example.com/path?existing=1", {
35
+ params: { added: "2" },
36
+ })
37
+ ).toBe("https://example.com/path?existing=1&added=2");
38
+ });
39
+
40
+ it("overrides existing query params when keys collide", () => {
41
+ expect(
42
+ buildUrlWithQuery("https://example.com/path?foo=old", {
43
+ params: { foo: "new" },
44
+ })
45
+ ).toBe("https://example.com/path?foo=new");
46
+ });
47
+
48
+ it("preserves url path, host, and hash when adding params", () => {
49
+ expect(
50
+ buildUrlWithQuery("https://example.com:8080/my/path#section", {
51
+ params: { token: "abc" },
52
+ })
53
+ ).toBe("https://example.com:8080/my/path?token=abc#section");
54
+ });
55
+ });
@@ -0,0 +1,95 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import { useBuildPipesUrl } from "@applicaster/zapp-react-native-utils/reactHooks/feed";
4
+ import { withPipesEndpoint } from "../withPipesEndpoint";
5
+
6
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/feed", () => ({
7
+ useBuildPipesUrl: jest.fn(),
8
+ }));
9
+
10
+ describe("withPipesEndpoint", () => {
11
+ let receivedProps: Record<string, unknown> | undefined;
12
+ let receivedRef: React.Ref<unknown> | undefined;
13
+
14
+ const BaseComponent = React.forwardRef((props, ref) => {
15
+ receivedProps = props;
16
+ receivedRef = ref;
17
+
18
+ return null;
19
+ });
20
+
21
+ const Wrapped = withPipesEndpoint(BaseComponent);
22
+
23
+ const defaultUri = "https://example.com/path";
24
+
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ receivedProps = undefined;
28
+ receivedRef = undefined;
29
+ });
30
+
31
+ it("returns null when requestParams is null", () => {
32
+ (useBuildPipesUrl as jest.Mock).mockReturnValue({ requestParams: null });
33
+
34
+ const { toJSON } = render(<Wrapped uri={defaultUri} />);
35
+
36
+ expect(toJSON()).toBeNull();
37
+ });
38
+
39
+ it("calls useBuildPipesUrl with the uri from props", () => {
40
+ (useBuildPipesUrl as jest.Mock).mockReturnValue({ requestParams: null });
41
+
42
+ render(<Wrapped uri={defaultUri} />);
43
+
44
+ expect(useBuildPipesUrl).toHaveBeenCalledWith({ url: defaultUri });
45
+ });
46
+
47
+ it("renders the wrapped component with merged uri and headers when requestParams are available", () => {
48
+ const onLoad = jest.fn();
49
+
50
+ (useBuildPipesUrl as jest.Mock).mockReturnValue({
51
+ requestParams: {
52
+ params: { token: "abc" },
53
+ headers: { Authorization: "Bearer x" },
54
+ },
55
+ });
56
+
57
+ render(<Wrapped uri={defaultUri} onLoad={onLoad} />);
58
+
59
+ expect(receivedProps?.uri).toBe(`${defaultUri}?token=abc`);
60
+ expect(receivedProps?.headers).toEqual({ Authorization: "Bearer x" });
61
+ expect(receivedProps?.onLoad).toBe(onLoad);
62
+ });
63
+
64
+ it("passes empty headers when requestParams has no headers", () => {
65
+ (useBuildPipesUrl as jest.Mock).mockReturnValue({
66
+ requestParams: { params: { token: "abc" } },
67
+ });
68
+
69
+ render(<Wrapped uri={defaultUri} />);
70
+
71
+ expect(receivedProps?.headers).toEqual({});
72
+ });
73
+
74
+ it("keeps uri unchanged when requestParams has no params", () => {
75
+ (useBuildPipesUrl as jest.Mock).mockReturnValue({
76
+ requestParams: {},
77
+ });
78
+
79
+ render(<Wrapped uri={defaultUri} />);
80
+
81
+ expect(receivedProps?.uri).toBe(defaultUri);
82
+ });
83
+
84
+ it("forwards ref to the wrapped component", () => {
85
+ const ref = React.createRef<unknown>();
86
+
87
+ (useBuildPipesUrl as jest.Mock).mockReturnValue({
88
+ requestParams: { params: { token: "abc" } },
89
+ });
90
+
91
+ render(<Wrapped ref={ref} uri={defaultUri} />);
92
+
93
+ expect(receivedRef).toBe(ref);
94
+ });
95
+ });
@@ -0,0 +1 @@
1
+ export { withPipesEndpoint } from "./withPipesEndpoint";
@@ -0,0 +1,42 @@
1
+ import React, { forwardRef, RefObject } from "react";
2
+ import URL from "url";
3
+
4
+ import { useBuildPipesUrl } from "@applicaster/zapp-react-native-utils/reactHooks/feed";
5
+
6
+ export function buildUrlWithQuery(url: string, requestParams) {
7
+ if (!requestParams?.params) return url;
8
+
9
+ const parsedURL = URL.parse(url, true);
10
+
11
+ parsedURL.query = { ...parsedURL.query, ...requestParams.params };
12
+ parsedURL.search = null;
13
+
14
+ return URL.format(parsedURL);
15
+ }
16
+
17
+ type Props = {
18
+ uri: string;
19
+ } & Record<string, unknown>;
20
+
21
+ export function withPipesEndpoint(Component) {
22
+ function WithPipesEndpoint(props: Props, ref: RefObject<unknown>) {
23
+ const { requestParams } = useBuildPipesUrl({ url: props.uri });
24
+
25
+ if (requestParams !== null) {
26
+ const urlWithQuery = buildUrlWithQuery(props.uri, requestParams);
27
+
28
+ return (
29
+ <Component
30
+ ref={ref}
31
+ {...props}
32
+ uri={urlWithQuery}
33
+ headers={requestParams.headers || {}}
34
+ />
35
+ );
36
+ }
37
+
38
+ return null;
39
+ }
40
+
41
+ return forwardRef(WithPipesEndpoint);
42
+ }
@@ -80,9 +80,9 @@ export const getInflatedDataSourceUrl: GetInflatedDataSourceUrl = ({
80
80
  if (!source) {
81
81
  if (__DEV__) {
82
82
  // eslint-disable-next-line no-console
83
- throw new Error(
84
- "getInflatedDataSourceUrl: source is empty while mapping is provided"
85
- );
83
+ // throw new Error(
84
+ // "getInflatedDataSourceUrl: source is empty while mapping is provided"
85
+ // );
86
86
  }
87
87
 
88
88
  return null;
@@ -0,0 +1,114 @@
1
+ import { renderHook } from "@testing-library/react-native";
2
+ import { useIsStandaloneFullscreen } from "../useIsStandaloneFullscreen";
3
+
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
6
+
7
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks");
8
+ jest.mock("@applicaster/zapp-react-native-utils/booleanUtils");
9
+
10
+ const mockUseNavigation = useNavigation as jest.Mock;
11
+ const mockToBoolean = toBooleanWithDefaultFalse as jest.Mock;
12
+
13
+ describe("useIsStandaloneFullscreen", () => {
14
+ beforeEach(() => {
15
+ jest.clearAllMocks();
16
+
17
+ mockUseNavigation.mockReturnValue({
18
+ canGoBack: jest.fn().mockReturnValue(false),
19
+ screenData: {
20
+ general: { allow_screen_plugin_presentation: true },
21
+ },
22
+ });
23
+
24
+ mockToBoolean.mockReturnValue(false);
25
+ });
26
+
27
+ it("returns true when cannot go back and screen plugin presentation is allowed", () => {
28
+ mockToBoolean.mockReturnValue(true);
29
+
30
+ const { result } = renderHook(() => useIsStandaloneFullscreen());
31
+
32
+ expect(mockToBoolean).toHaveBeenCalledWith(true);
33
+ expect(result.current).toBe(true);
34
+ });
35
+
36
+ it("returns false when can go back even if screen plugin presentation is allowed", () => {
37
+ mockUseNavigation.mockReturnValue({
38
+ canGoBack: jest.fn().mockReturnValue(true),
39
+ screenData: {
40
+ general: { allow_screen_plugin_presentation: true },
41
+ },
42
+ });
43
+
44
+ mockToBoolean.mockReturnValue(false);
45
+
46
+ const { result } = renderHook(() => useIsStandaloneFullscreen());
47
+
48
+ expect(mockToBoolean).toHaveBeenCalledWith(false);
49
+ expect(result.current).toBe(false);
50
+ });
51
+
52
+ it("returns false when cannot go back but screen plugin presentation is not allowed", () => {
53
+ mockUseNavigation.mockReturnValue({
54
+ canGoBack: jest.fn().mockReturnValue(false),
55
+ screenData: {
56
+ general: { allow_screen_plugin_presentation: false },
57
+ },
58
+ });
59
+
60
+ mockToBoolean.mockReturnValue(false);
61
+
62
+ const { result } = renderHook(() => useIsStandaloneFullscreen());
63
+
64
+ expect(mockToBoolean).toHaveBeenCalledWith(false);
65
+ expect(result.current).toBe(false);
66
+ });
67
+
68
+ it("returns false when screen plugin presentation flag is undefined", () => {
69
+ mockUseNavigation.mockReturnValue({
70
+ canGoBack: jest.fn().mockReturnValue(false),
71
+ screenData: { general: {} },
72
+ });
73
+
74
+ mockToBoolean.mockReturnValue(false);
75
+
76
+ const { result } = renderHook(() => useIsStandaloneFullscreen());
77
+
78
+ expect(mockToBoolean).toHaveBeenCalledWith(undefined);
79
+ expect(result.current).toBe(false);
80
+ });
81
+
82
+ it("returns false when navigator is undefined", () => {
83
+ mockUseNavigation.mockReturnValue(undefined);
84
+ mockToBoolean.mockReturnValue(false);
85
+
86
+ const { result } = renderHook(() => useIsStandaloneFullscreen());
87
+
88
+ expect(mockToBoolean).toHaveBeenCalledWith(undefined);
89
+ expect(result.current).toBe(false);
90
+ });
91
+
92
+ it("returns false when screenData is undefined", () => {
93
+ mockUseNavigation.mockReturnValue({
94
+ canGoBack: jest.fn().mockReturnValue(false),
95
+ screenData: undefined,
96
+ });
97
+
98
+ mockToBoolean.mockReturnValue(false);
99
+
100
+ const { result } = renderHook(() => useIsStandaloneFullscreen());
101
+
102
+ expect(mockToBoolean).toHaveBeenCalledWith(undefined);
103
+ expect(result.current).toBe(false);
104
+ });
105
+
106
+ it("passes the combined condition through toBooleanWithDefaultFalse", () => {
107
+ mockToBoolean.mockImplementation((val) => Boolean(val));
108
+
109
+ const { result } = renderHook(() => useIsStandaloneFullscreen());
110
+
111
+ expect(mockToBoolean).toHaveBeenCalledWith(true);
112
+ expect(result.current).toBe(true);
113
+ });
114
+ });
@@ -16,3 +16,5 @@ export { useScreenBackgroundColor } from "./useScreenBackgroundColor";
16
16
  export { useCurrentScreenIsHook } from "./useCurrentScreenIsHook";
17
17
 
18
18
  export { useCurrentScreenIsStartupHook } from "./useCurrentScreenIsStartupHook";
19
+
20
+ export { useIsStandaloneFullscreen } from "./useIsStandaloneFullscreen";
@@ -0,0 +1,12 @@
1
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
2
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
3
+
4
+ export const useIsStandaloneFullscreen = (): boolean => {
5
+ const navigator = useNavigation();
6
+
7
+ return toBooleanWithDefaultFalse(
8
+ !navigator?.canGoBack() &&
9
+ // @ts-ignore
10
+ navigator?.screenData?.general?.allow_screen_plugin_presentation
11
+ );
12
+ };
@@ -197,7 +197,7 @@ export const useCallbackNavigationAction = (
197
197
  }
198
198
  }
199
199
 
200
- hookCallback?.({ ...args, success: false, cancelled: true });
200
+ hookCallback?.({ ...args, success: false, abort: true });
201
201
  const currentNavigation = navigationRef.current;
202
202
 
203
203
  switch (data.action) {