@applicaster/zapp-react-native-utils 15.0.0-rc.99 → 16.0.0-alpha.6593152532
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/README.md +0 -6
- package/actionUtils/index.ts +7 -0
- package/actionsExecutor/ActionExecutorContext.tsx +83 -6
- package/appUtils/HooksManager/index.ts +38 -9
- package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
- package/appUtils/focusManagerAux/utils/index.ts +12 -6
- package/appUtils/focusManagerAux/utils/utils.ios.ts +6 -3
- package/appUtils/localizationsHelper.ts +4 -0
- package/appUtils/platform/platformUtils.ts +11 -0
- package/appUtils/playerManager/index.ts +9 -0
- package/appUtils/playerManager/player.ts +1 -1
- package/appUtils/playerManager/playerNative.ts +2 -1
- package/appUtils/playerManager/usePlayer.tsx +5 -3
- package/cellUtils/__tests__/cellUtils.test.ts +39 -0
- package/cellUtils/index.ts +11 -1
- package/componentsUtils/index.ts +8 -0
- package/dateUtils/__tests__/dayjs.test.ts +0 -3
- package/dateUtils/index.ts +2 -0
- package/manifestUtils/_internals/__tests__/index.test.js +41 -0
- package/manifestUtils/_internals/index.js +33 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +6 -16
- package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +49 -0
- package/manifestUtils/fieldUtils/index.js +54 -0
- package/manifestUtils/index.js +3 -1
- package/manifestUtils/keys.js +228 -0
- package/manifestUtils/mobileAction/button/__tests__/mobileActionButton.test.js +168 -0
- package/manifestUtils/mobileAction/button/index.js +140 -0
- package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +102 -0
- package/manifestUtils/mobileAction/container/index.js +73 -0
- package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +127 -0
- package/manifestUtils/mobileAction/groups/defaults.js +76 -0
- package/manifestUtils/mobileAction/groups/index.js +80 -0
- package/numberUtils/__tests__/toNumber.test.ts +27 -12
- package/numberUtils/__tests__/toPositiveNumber.test.ts +32 -4
- package/numberUtils/index.ts +5 -1
- package/package.json +3 -3
- package/pluginUtils/index.ts +4 -5
- package/reactHooks/casting/index.ts +1 -0
- package/reactHooks/casting/useIsCasting.tsx +57 -0
- package/reactHooks/cell-click/index.ts +2 -1
- package/reactHooks/feed/index.ts +0 -2
- package/reactHooks/feed/useInflatedUrl.ts +1 -1
- package/reactHooks/resolvers/useComponentResolver.ts +13 -3
- package/reactHooks/screen/__tests__/useCurrentScreenIsHook.test.ts +103 -0
- package/reactHooks/screen/__tests__/useCurrentScreenIsStartupHook.test.ts +94 -0
- package/reactHooks/screen/index.ts +4 -0
- package/reactHooks/screen/useCurrentScreenIsHook.ts +9 -0
- package/reactHooks/screen/useCurrentScreenIsStartupHook.ts +8 -0
- package/reactHooks/state/__tests__/useComponentScreenState.test.ts +246 -0
- package/reactHooks/state/index.ts +2 -0
- package/reactHooks/state/useComponentScreenState.ts +45 -0
- package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +206 -0
- package/refreshUtils/RefreshCoordinator/index.ts +245 -0
- package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
- package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
- package/screenPickerUtils/index.ts +5 -0
- package/screenUtils/index.ts +3 -0
- package/utils/__tests__/clone.test.ts +158 -0
- package/utils/__tests__/path.test.ts +7 -0
- package/utils/clone.ts +7 -0
- package/utils/index.ts +2 -1
- package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
- package/reactHooks/feed/useFeedRefresh.tsx +0 -65
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const { mobileActionButtonsContainer } = require("../container");
|
|
2
|
+
const { mobileActionButton } = require("../button");
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
DEFAULT_MOBILE_ACTION_BUTTONS_CONTAINER_DEFAULTS,
|
|
6
|
+
DEFAULT_MOBILE_ACTION_BUTTON_SHARED_DEFAULTS,
|
|
7
|
+
DEFAULT_MOBILE_ACTION_BUTTON_PRESETS,
|
|
8
|
+
} = require("./defaults");
|
|
9
|
+
|
|
10
|
+
const CONTAINER_GROUP_LABEL = "Mobile Buttons Container"; // NOTE: used as key – "Mobile Buttons Container" -> "mobile_buttons_container"
|
|
11
|
+
|
|
12
|
+
const CONTAINER_GROUP_DESCRIPTION =
|
|
13
|
+
"Configuration for mobile action buttons container";
|
|
14
|
+
|
|
15
|
+
const BUTTON_GROUPS = [
|
|
16
|
+
{
|
|
17
|
+
index: 1,
|
|
18
|
+
label: "Mobile Button 1",
|
|
19
|
+
description: "Primary mobile action button",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
index: 2,
|
|
23
|
+
label: "Mobile Button 2",
|
|
24
|
+
description: "Secondary mobile action button",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
index: 3,
|
|
28
|
+
label: "Mobile Button 3",
|
|
29
|
+
description: "Tertiary mobile action button",
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Builds the shared mobile action button manifest groups while letting each
|
|
35
|
+
* plugin supply only its supported insertion positions and explicit overrides.
|
|
36
|
+
*
|
|
37
|
+
* @param {object} options
|
|
38
|
+
* @param {object} [options.containerDefaults={}]
|
|
39
|
+
* @param {object} [options.sharedButtonDefaults={}]
|
|
40
|
+
* @param {Record<number, object>} [options.buttonOverrides={}]
|
|
41
|
+
* @returns {object[]}
|
|
42
|
+
*/
|
|
43
|
+
function buildMobileActionButtonGroups({
|
|
44
|
+
containerDefaults = {},
|
|
45
|
+
sharedButtonDefaults = {},
|
|
46
|
+
buttonOverrides = {},
|
|
47
|
+
}) {
|
|
48
|
+
const groups = [
|
|
49
|
+
mobileActionButtonsContainer({
|
|
50
|
+
label: CONTAINER_GROUP_LABEL,
|
|
51
|
+
description: CONTAINER_GROUP_DESCRIPTION,
|
|
52
|
+
defaults: {
|
|
53
|
+
...DEFAULT_MOBILE_ACTION_BUTTONS_CONTAINER_DEFAULTS,
|
|
54
|
+
...containerDefaults,
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
BUTTON_GROUPS.forEach(({ index, label, description }) => {
|
|
60
|
+
groups.push(
|
|
61
|
+
mobileActionButton({
|
|
62
|
+
isFirstButton: index === 1,
|
|
63
|
+
label,
|
|
64
|
+
description,
|
|
65
|
+
defaults: {
|
|
66
|
+
...DEFAULT_MOBILE_ACTION_BUTTON_SHARED_DEFAULTS,
|
|
67
|
+
...sharedButtonDefaults,
|
|
68
|
+
...DEFAULT_MOBILE_ACTION_BUTTON_PRESETS[index],
|
|
69
|
+
...(buttonOverrides[index] || {}),
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return groups;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
buildMobileActionButtonGroups,
|
|
80
|
+
};
|
|
@@ -11,16 +11,6 @@ describe("toNumber", () => {
|
|
|
11
11
|
});
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it("return number if input is BigInt", () => {
|
|
15
|
-
const inputs = [5n, -5n];
|
|
16
|
-
expect.assertions(inputs.length);
|
|
17
|
-
|
|
18
|
-
inputs.forEach((input) => {
|
|
19
|
-
const output = toNumber(input);
|
|
20
|
-
expect(output).toBe(Number(input));
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
14
|
it("return number if input is string as number", () => {
|
|
25
15
|
const inputs = ["-1", "0", "1", "100", "0.2"];
|
|
26
16
|
expect.assertions(inputs.length);
|
|
@@ -34,6 +24,8 @@ describe("toNumber", () => {
|
|
|
34
24
|
it("return undefined if input is not a number", () => {
|
|
35
25
|
const inputs = [
|
|
36
26
|
"vfdvf",
|
|
27
|
+
"5n",
|
|
28
|
+
"-5n",
|
|
37
29
|
null,
|
|
38
30
|
undefined,
|
|
39
31
|
NaN,
|
|
@@ -42,8 +34,6 @@ describe("toNumber", () => {
|
|
|
42
34
|
{ test: 1 },
|
|
43
35
|
[],
|
|
44
36
|
[1],
|
|
45
|
-
"5n",
|
|
46
|
-
"-5n",
|
|
47
37
|
];
|
|
48
38
|
|
|
49
39
|
expect.assertions(inputs.length);
|
|
@@ -53,4 +43,29 @@ describe("toNumber", () => {
|
|
|
53
43
|
expect(output).toBeUndefined();
|
|
54
44
|
});
|
|
55
45
|
});
|
|
46
|
+
|
|
47
|
+
describe("BigInt support", () => {
|
|
48
|
+
// Conditional test based on BigInt availability
|
|
49
|
+
const isBigIntSupported = typeof BigInt !== "undefined";
|
|
50
|
+
|
|
51
|
+
if (isBigIntSupported) {
|
|
52
|
+
it("converts BigInt to number when BigInt is supported", () => {
|
|
53
|
+
expect(toNumber(BigInt(5))).toBe(5);
|
|
54
|
+
expect(toNumber(BigInt(0))).toBe(0);
|
|
55
|
+
expect(toNumber(BigInt(-10))).toBe(-10);
|
|
56
|
+
expect(toNumber(BigInt(1000))).toBe(1000);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("handles large BigInt values that may lose precision", () => {
|
|
60
|
+
const largeBigInt = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1);
|
|
61
|
+
const result = toNumber(largeBigInt);
|
|
62
|
+
expect(result).toBe(Number(largeBigInt));
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
it("skips BigInt tests when BigInt is not supported", () => {
|
|
66
|
+
// Placeholder test to indicate BigInt is not available
|
|
67
|
+
expect(typeof BigInt).toBe("undefined");
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
56
71
|
});
|
|
@@ -156,10 +156,38 @@ describe("toPositiveNumber", () => {
|
|
|
156
156
|
it("handles Symbol values", () => {
|
|
157
157
|
expect(toPositiveNumber(Symbol("test"))).toBeUndefined();
|
|
158
158
|
});
|
|
159
|
+
});
|
|
159
160
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
describe("BigInt support", () => {
|
|
162
|
+
// Conditional test based on BigInt availability
|
|
163
|
+
const isBigIntSupported = typeof BigInt !== "undefined";
|
|
164
|
+
|
|
165
|
+
if (isBigIntSupported) {
|
|
166
|
+
it("converts positive BigInt values to numbers when BigInt is supported", () => {
|
|
167
|
+
expect(toPositiveNumber(BigInt(5))).toBe(5);
|
|
168
|
+
expect(toPositiveNumber(BigInt(100))).toBe(100);
|
|
169
|
+
expect(toPositiveNumber(BigInt(1000))).toBe(1000);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("returns undefined for zero BigInt", () => {
|
|
173
|
+
expect(toPositiveNumber(BigInt(0))).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("returns undefined for negative BigInt values", () => {
|
|
177
|
+
expect(toPositiveNumber(BigInt(-5))).toBeUndefined();
|
|
178
|
+
expect(toPositiveNumber(BigInt(-100))).toBeUndefined();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("handles large positive BigInt values", () => {
|
|
182
|
+
const largeBigInt = BigInt(Number.MAX_SAFE_INTEGER);
|
|
183
|
+
const result = toPositiveNumber(largeBigInt);
|
|
184
|
+
expect(result).toBe(Number(largeBigInt));
|
|
185
|
+
});
|
|
186
|
+
} else {
|
|
187
|
+
it("skips BigInt tests when BigInt is not supported", () => {
|
|
188
|
+
// Placeholder test to indicate BigInt is not available
|
|
189
|
+
expect(typeof BigInt).toBe("undefined");
|
|
190
|
+
});
|
|
191
|
+
}
|
|
164
192
|
});
|
|
165
193
|
});
|
package/numberUtils/index.ts
CHANGED
|
@@ -8,7 +8,11 @@ export const toNumber = (value: unknown): number | undefined => {
|
|
|
8
8
|
return undefined;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
// Feature-detect BigInt support to avoid ReferenceError on older runtimes
|
|
12
|
+
const isBigIntSupported = typeof BigInt !== "undefined";
|
|
13
|
+
const isBigIntValue = isBigIntSupported && R.is(BigInt, value);
|
|
14
|
+
|
|
15
|
+
if (R.is(Number, value) || isBigIntValue || R.is(String, value)) {
|
|
12
16
|
const numberOrNan = Number(value);
|
|
13
17
|
|
|
14
18
|
return Number.isNaN(numberOrNan) ? undefined : numberOrNan;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0-alpha.6593152532",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "
|
|
30
|
+
"@applicaster/applicaster-types": "16.0.0-alpha.6593152532",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
34
|
-
"handlebars": "4.7.
|
|
34
|
+
"handlebars": "4.7.9",
|
|
35
35
|
"memoizee": "0.4.15",
|
|
36
36
|
"prop-types": "^15.0.0"
|
|
37
37
|
},
|
package/pluginUtils/index.ts
CHANGED
|
@@ -30,10 +30,7 @@ export function getComponentModule({
|
|
|
30
30
|
components: ComponentsMap;
|
|
31
31
|
plugins: Plugin[] | QuickBrickPlugin[];
|
|
32
32
|
}) {
|
|
33
|
-
const component =
|
|
34
|
-
R.prop(R.__, components),
|
|
35
|
-
toPascalCase
|
|
36
|
-
)(componentType);
|
|
33
|
+
const component = components[toPascalCase(componentType)];
|
|
37
34
|
|
|
38
35
|
if (component) {
|
|
39
36
|
return component;
|
|
@@ -60,7 +57,9 @@ export function findComponentByType({
|
|
|
60
57
|
? R.compose(...R.reverse(decorators))
|
|
61
58
|
: decorators;
|
|
62
59
|
|
|
63
|
-
const
|
|
60
|
+
const module = getComponentModule({ componentType, components, plugins });
|
|
61
|
+
|
|
62
|
+
const component = module?.Component || module;
|
|
64
63
|
|
|
65
64
|
return R.unless(R.isNil, applyDecorators)(component);
|
|
66
65
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useIsCasting } from "./useIsCasting";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
3
|
+
import { useAppState } from "@applicaster/zapp-react-native-utils/reactHooks/app";
|
|
4
|
+
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
5
|
+
|
|
6
|
+
const CHROMECAST_IDENTIFIER = "quick-brick-chromecast-action";
|
|
7
|
+
|
|
8
|
+
const fakeEntry: any = {
|
|
9
|
+
title: "Chromecast use is casting fake entry",
|
|
10
|
+
id: "quick-brick-use-is-casting-fake-entry",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Returns the cast action state connection status, does not update when app is in background on Apple platforms
|
|
15
|
+
* On other platforms, it continues to check the cast action state even when the app is in background
|
|
16
|
+
*/
|
|
17
|
+
export const useIsCasting = () => {
|
|
18
|
+
const actionContext = useActions(CHROMECAST_IDENTIFIER);
|
|
19
|
+
const appState = useAppState();
|
|
20
|
+
const isAppInForeground = appState === "active";
|
|
21
|
+
const shouldOnlyUpdateInForeground = isApplePlatform();
|
|
22
|
+
|
|
23
|
+
const [castActionState, setCastActionState] = React.useState(
|
|
24
|
+
!actionContext ? null : actionContext.initialEntryState(fakeEntry)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
if (!shouldOnlyUpdateInForeground || isAppInForeground) {
|
|
29
|
+
if (actionContext && castActionState === null) {
|
|
30
|
+
setCastActionState(actionContext.initialEntryState(fakeEntry));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [
|
|
34
|
+
actionContext,
|
|
35
|
+
setCastActionState,
|
|
36
|
+
isAppInForeground,
|
|
37
|
+
shouldOnlyUpdateInForeground,
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
if (typeof actionContext?.addListener === "function") {
|
|
42
|
+
return actionContext?.addListener(String(fakeEntry.id), (state) => {
|
|
43
|
+
// Only check foreground state on Apple platforms
|
|
44
|
+
if (!shouldOnlyUpdateInForeground || isAppInForeground) {
|
|
45
|
+
setCastActionState(state);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}, [
|
|
50
|
+
setCastActionState,
|
|
51
|
+
actionContext,
|
|
52
|
+
isAppInForeground,
|
|
53
|
+
shouldOnlyUpdateInForeground,
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
return !!castActionState?.connected;
|
|
57
|
+
};
|
|
@@ -54,7 +54,7 @@ export const useCellClick = ({
|
|
|
54
54
|
component?.rules?.component_cells_selectable
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
-
const [
|
|
57
|
+
const [entryContext, setEntryContext] =
|
|
58
58
|
ZappPipesEntryContext.useZappPipesContext(pathname);
|
|
59
59
|
|
|
60
60
|
const logTimestamp = useProfilerLogging();
|
|
@@ -89,6 +89,7 @@ export const useCellClick = ({
|
|
|
89
89
|
screenState,
|
|
90
90
|
screenRoute: pathname,
|
|
91
91
|
screenStateStore,
|
|
92
|
+
entryContext,
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
|
package/reactHooks/feed/index.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/// <reference types="@applicaster/applicaster-types" />
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
|
|
4
|
+
import { coreLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
5
|
+
|
|
4
6
|
import { findComponentByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
5
7
|
import {
|
|
6
|
-
usePlugins,
|
|
7
|
-
useAppSelector,
|
|
8
8
|
selectComponents,
|
|
9
|
+
useAppSelector,
|
|
10
|
+
usePlugins,
|
|
9
11
|
} from "@applicaster/zapp-react-native-redux";
|
|
10
12
|
|
|
11
13
|
type Decorator = (component: React.Component<any>) => React.Component<any>;
|
|
@@ -23,7 +25,7 @@ export function useComponentResolver(
|
|
|
23
25
|
|
|
24
26
|
const components = useAppSelector(selectComponents);
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
const component = React.useMemo(
|
|
27
29
|
() =>
|
|
28
30
|
findComponentByType({
|
|
29
31
|
components,
|
|
@@ -33,4 +35,12 @@ export function useComponentResolver(
|
|
|
33
35
|
}),
|
|
34
36
|
watchers
|
|
35
37
|
);
|
|
38
|
+
|
|
39
|
+
if (!component) {
|
|
40
|
+
coreLogger.warn({
|
|
41
|
+
message: `useComponentResolver: Component of type ${componentType} not found`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return component;
|
|
36
46
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-native";
|
|
2
|
+
import { useCurrentScreenIsHook } from "../useCurrentScreenIsHook";
|
|
3
|
+
|
|
4
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
|
+
import { last } from "@applicaster/zapp-react-native-utils/utils";
|
|
6
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
|
+
|
|
8
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks");
|
|
9
|
+
jest.mock("@applicaster/zapp-react-native-utils/utils");
|
|
10
|
+
jest.mock("@applicaster/zapp-react-native-utils/booleanUtils");
|
|
11
|
+
|
|
12
|
+
const mockUseNavigation = useNavigation as jest.Mock;
|
|
13
|
+
const mockLast = last as jest.Mock;
|
|
14
|
+
const mockToBoolean = toBooleanWithDefaultFalse as jest.Mock;
|
|
15
|
+
|
|
16
|
+
describe("useCurrentScreenIsHook", () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
|
|
20
|
+
// sensible defaults
|
|
21
|
+
mockUseNavigation.mockReturnValue({ mainStack: [] });
|
|
22
|
+
mockLast.mockReturnValue(undefined);
|
|
23
|
+
mockToBoolean.mockReturnValue(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("returns true when last route includes 'hook'", () => {
|
|
27
|
+
const stack = [{ route: "some-hook-screen" }];
|
|
28
|
+
|
|
29
|
+
mockUseNavigation.mockReturnValue({ mainStack: stack });
|
|
30
|
+
mockLast.mockReturnValue(stack[0]);
|
|
31
|
+
mockToBoolean.mockReturnValue(true);
|
|
32
|
+
|
|
33
|
+
const { result } = renderHook(() => useCurrentScreenIsHook());
|
|
34
|
+
|
|
35
|
+
expect(mockLast).toHaveBeenCalledWith(stack);
|
|
36
|
+
expect(mockToBoolean).toHaveBeenCalledWith(true);
|
|
37
|
+
expect(result.current).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("returns false when last route does not include 'hook'", () => {
|
|
41
|
+
const stack = [{ route: "home-screen" }];
|
|
42
|
+
|
|
43
|
+
mockUseNavigation.mockReturnValue({ mainStack: stack });
|
|
44
|
+
mockLast.mockReturnValue(stack[0]);
|
|
45
|
+
mockToBoolean.mockReturnValue(false);
|
|
46
|
+
|
|
47
|
+
const { result } = renderHook(() => useCurrentScreenIsHook());
|
|
48
|
+
|
|
49
|
+
expect(mockToBoolean).toHaveBeenCalledWith(false);
|
|
50
|
+
expect(result.current).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("returns false when route is undefined", () => {
|
|
54
|
+
const stack = [{}];
|
|
55
|
+
|
|
56
|
+
mockUseNavigation.mockReturnValue({ mainStack: stack });
|
|
57
|
+
mockLast.mockReturnValue(stack[0]);
|
|
58
|
+
mockToBoolean.mockReturnValue(false);
|
|
59
|
+
|
|
60
|
+
const { result } = renderHook(() => useCurrentScreenIsHook());
|
|
61
|
+
|
|
62
|
+
expect(mockToBoolean).toHaveBeenCalledWith(undefined);
|
|
63
|
+
expect(result.current).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("returns false when last(mainStack) is undefined (empty stack)", () => {
|
|
67
|
+
mockUseNavigation.mockReturnValue({ mainStack: [] });
|
|
68
|
+
mockLast.mockReturnValue(undefined);
|
|
69
|
+
mockToBoolean.mockReturnValue(false);
|
|
70
|
+
|
|
71
|
+
const { result } = renderHook(() => useCurrentScreenIsHook());
|
|
72
|
+
|
|
73
|
+
expect(mockLast).toHaveBeenCalledWith([]);
|
|
74
|
+
expect(mockToBoolean).toHaveBeenCalledWith(undefined);
|
|
75
|
+
expect(result.current).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("uses default empty array when mainStack is undefined", () => {
|
|
79
|
+
mockUseNavigation.mockReturnValue({});
|
|
80
|
+
mockLast.mockReturnValue(undefined);
|
|
81
|
+
mockToBoolean.mockReturnValue(false);
|
|
82
|
+
|
|
83
|
+
const { result } = renderHook(() => useCurrentScreenIsHook());
|
|
84
|
+
|
|
85
|
+
expect(mockLast).toHaveBeenCalledWith([]);
|
|
86
|
+
expect(result.current).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("passes correct boolean result from includes('hook')", () => {
|
|
90
|
+
const stack = [{ route: "hook" }];
|
|
91
|
+
|
|
92
|
+
mockUseNavigation.mockReturnValue({ mainStack: stack });
|
|
93
|
+
mockLast.mockReturnValue(stack[0]);
|
|
94
|
+
|
|
95
|
+
// simulate actual includes result flowing through
|
|
96
|
+
mockToBoolean.mockImplementation((val) => Boolean(val));
|
|
97
|
+
|
|
98
|
+
const { result } = renderHook(() => useCurrentScreenIsHook());
|
|
99
|
+
|
|
100
|
+
expect(mockToBoolean).toHaveBeenCalledWith(true);
|
|
101
|
+
expect(result.current).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-native";
|
|
2
|
+
import { useCurrentScreenIsStartupHook } from "../useCurrentScreenIsStartupHook";
|
|
3
|
+
|
|
4
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
|
+
import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
6
|
+
|
|
7
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks");
|
|
8
|
+
jest.mock("@applicaster/zapp-react-native-utils/arrayUtils");
|
|
9
|
+
|
|
10
|
+
const mockUseNavigation = useNavigation as jest.Mock;
|
|
11
|
+
const mockIsFilledArray = isFilledArray as jest.Mock;
|
|
12
|
+
|
|
13
|
+
describe("useCurrentScreenIsStartupHook", () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
jest.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("returns true when startUpHooks is a filled array", () => {
|
|
19
|
+
mockUseNavigation.mockReturnValue({
|
|
20
|
+
startUpHooks: ["hook1"],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
mockIsFilledArray.mockReturnValue(true);
|
|
24
|
+
|
|
25
|
+
const { result } = renderHook(() => useCurrentScreenIsStartupHook());
|
|
26
|
+
|
|
27
|
+
expect(result.current).toBe(true);
|
|
28
|
+
expect(mockIsFilledArray).toHaveBeenCalledWith(["hook1"]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('returns true when startUpHooks is "in_process"', () => {
|
|
32
|
+
mockUseNavigation.mockReturnValue({
|
|
33
|
+
startUpHooks: "in_process",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
mockIsFilledArray.mockReturnValue(false);
|
|
37
|
+
|
|
38
|
+
const { result } = renderHook(() => useCurrentScreenIsStartupHook());
|
|
39
|
+
|
|
40
|
+
expect(result.current).toBe(true);
|
|
41
|
+
expect(mockIsFilledArray).toHaveBeenCalledWith("in_process");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("returns false when startUpHooks is empty array", () => {
|
|
45
|
+
mockUseNavigation.mockReturnValue({
|
|
46
|
+
startUpHooks: [],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
mockIsFilledArray.mockReturnValue(false);
|
|
50
|
+
|
|
51
|
+
const { result } = renderHook(() => useCurrentScreenIsStartupHook());
|
|
52
|
+
|
|
53
|
+
expect(result.current).toBe(false);
|
|
54
|
+
expect(mockIsFilledArray).toHaveBeenCalledWith([]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("returns false when startUpHooks is undefined", () => {
|
|
58
|
+
mockUseNavigation.mockReturnValue({
|
|
59
|
+
startUpHooks: undefined,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
mockIsFilledArray.mockReturnValue(false);
|
|
63
|
+
|
|
64
|
+
const { result } = renderHook(() => useCurrentScreenIsStartupHook());
|
|
65
|
+
|
|
66
|
+
expect(result.current).toBe(false);
|
|
67
|
+
expect(mockIsFilledArray).toHaveBeenCalledWith(undefined);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("returns false when startUpHooks is null", () => {
|
|
71
|
+
mockUseNavigation.mockReturnValue({
|
|
72
|
+
startUpHooks: null,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
mockIsFilledArray.mockReturnValue(false);
|
|
76
|
+
|
|
77
|
+
const { result } = renderHook(() => useCurrentScreenIsStartupHook());
|
|
78
|
+
|
|
79
|
+
expect(result.current).toBe(false);
|
|
80
|
+
expect(mockIsFilledArray).toHaveBeenCalledWith(null);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("prioritizes filled array over string comparison", () => {
|
|
84
|
+
mockUseNavigation.mockReturnValue({
|
|
85
|
+
startUpHooks: ["hook1"],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
mockIsFilledArray.mockReturnValue(true);
|
|
89
|
+
|
|
90
|
+
const { result } = renderHook(() => useCurrentScreenIsStartupHook());
|
|
91
|
+
|
|
92
|
+
expect(result.current).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -12,3 +12,7 @@ export {
|
|
|
12
12
|
} from "./useScreenContext";
|
|
13
13
|
|
|
14
14
|
export { useScreenBackgroundColor } from "./useScreenBackgroundColor";
|
|
15
|
+
|
|
16
|
+
export { useCurrentScreenIsHook } from "./useCurrentScreenIsHook";
|
|
17
|
+
|
|
18
|
+
export { useCurrentScreenIsStartupHook } from "./useCurrentScreenIsStartupHook";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
2
|
+
import { last } from "@applicaster/zapp-react-native-utils/utils";
|
|
3
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
4
|
+
|
|
5
|
+
export const useCurrentScreenIsHook = (): boolean => {
|
|
6
|
+
const { mainStack = [] } = useNavigation();
|
|
7
|
+
|
|
8
|
+
return toBooleanWithDefaultFalse(last(mainStack)?.route?.includes("hook"));
|
|
9
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
2
|
+
import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
3
|
+
|
|
4
|
+
export const useCurrentScreenIsStartupHook = (): boolean => {
|
|
5
|
+
const { startUpHooks } = useNavigation();
|
|
6
|
+
|
|
7
|
+
return isFilledArray(startUpHooks) || startUpHooks === "in_process";
|
|
8
|
+
};
|