@applicaster/zapp-react-native-utils 15.0.0-alpha.1257410812 → 15.0.0-alpha.1283350001
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/adsUtils/__tests__/createVMAP.test.ts +419 -0
- package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
- package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
- package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
- 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 +2 -4
- package/appUtils/focusManagerAux/utils/utils.ios.ts +6 -3
- package/appUtils/localizationsHelper.ts +4 -0
- package/appUtils/playerManager/playerNative.ts +2 -1
- package/cloudEventsUtils/__tests__/index.test.ts +529 -0
- package/cloudEventsUtils/index.ts +65 -1
- package/dateUtils/__tests__/dayjs.test.ts +330 -0
- package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
- package/errorUtils/__tests__/GeneralError.test.ts +97 -0
- package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
- package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
- package/errorUtils/__tests__/NetworkError.test.ts +202 -0
- package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
- package/errorUtils/__tests__/invariant.test.ts +112 -0
- package/headersUtils/__tests__/headersUtils.test.js +11 -1
- package/headersUtils/index.ts +2 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +6 -16
- package/manifestUtils/platformIsTV.js +13 -0
- package/numberUtils/__tests__/toNumber.test.ts +27 -0
- package/numberUtils/__tests__/toPositiveNumber.test.ts +193 -0
- package/numberUtils/index.ts +23 -1
- package/package.json +2 -2
- package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
- package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
- package/reactHooks/device/useIsTablet.tsx +14 -19
- package/reactHooks/events/index.ts +20 -0
- package/reactHooks/feed/index.ts +0 -2
- package/reactHooks/feed/useInflatedUrl.ts +1 -1
- package/reactHooks/index.ts +2 -0
- package/reactHooks/resolvers/useComponentResolver.ts +11 -1
- package/reactHooks/state/__tests__/useComponentScreenState.test.ts +246 -0
- package/reactHooks/state/index.ts +2 -0
- package/reactHooks/state/useComponentScreenState.ts +45 -0
- package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
- package/rectUtils/__tests__/index.test.ts +549 -0
- package/rectUtils/index.ts +2 -2
- package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +161 -0
- package/refreshUtils/RefreshCoordinator/index.ts +216 -0
- package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
- package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
- package/screenPickerUtils/__tests__/index.test.ts +333 -0
- package/screenPickerUtils/index.ts +5 -0
- package/screenUtils/index.ts +3 -0
- package/time/__tests__/BackgroundTimer.test.ts +156 -0
- package/time/__tests__/Timer.test.ts +236 -0
- package/typeGuards/__tests__/isString.test.ts +21 -0
- package/typeGuards/index.ts +4 -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/componentsMap/index.ts +0 -55
- package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
- package/reactHooks/feed/useFeedRefresh.tsx +0 -65
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { getParsedResponse } from "../index";
|
|
2
|
+
import { RESPONSES } from "../errorCodes";
|
|
3
|
+
|
|
4
|
+
describe("getParsedResponse", () => {
|
|
5
|
+
it("should parse error with response status code from response.data", () => {
|
|
6
|
+
const err = {
|
|
7
|
+
response: {
|
|
8
|
+
data: {
|
|
9
|
+
statusCode: 404,
|
|
10
|
+
message: "Resource not found",
|
|
11
|
+
},
|
|
12
|
+
config: {
|
|
13
|
+
url: "https://api.example.com/data",
|
|
14
|
+
params: { id: 123 },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
name: "AxiosError",
|
|
18
|
+
context: { userId: "user123" },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const result = getParsedResponse(err);
|
|
22
|
+
|
|
23
|
+
expect(result.message).toBe("Error: Resource not found");
|
|
24
|
+
expect(result.data.statusCode).toBe("404");
|
|
25
|
+
expect(result.data.url).toBe("https://api.example.com/data");
|
|
26
|
+
expect(result.data.params).toEqual({ id: 123 });
|
|
27
|
+
expect(result.data.context).toEqual({ userId: "user123" });
|
|
28
|
+
expect(result.data.name).toBe("AxiosError");
|
|
29
|
+
expect(result.jsOnly).toBe(false);
|
|
30
|
+
expect(result.exception).toBe(result.message);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should parse error with response status code from response.status", () => {
|
|
34
|
+
const err = {
|
|
35
|
+
response: {
|
|
36
|
+
status: 500,
|
|
37
|
+
config: {
|
|
38
|
+
url: "https://api.example.com/data",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const result = getParsedResponse(err);
|
|
44
|
+
|
|
45
|
+
expect(result.message).toBe(`Error: ${RESPONSES[500]}`);
|
|
46
|
+
expect(result.data.statusCode).toBe("500");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should handle error with request but no response", () => {
|
|
50
|
+
const err = {
|
|
51
|
+
request: {},
|
|
52
|
+
message: "Network timeout",
|
|
53
|
+
config: {
|
|
54
|
+
url: "https://api.example.com/data",
|
|
55
|
+
params: { test: "value" },
|
|
56
|
+
},
|
|
57
|
+
name: "NetworkError",
|
|
58
|
+
context: { app: "test" },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const result = getParsedResponse(err);
|
|
62
|
+
|
|
63
|
+
expect(result.message).toBe("Error: Network timeout");
|
|
64
|
+
expect(result.data.url).toBe("https://api.example.com/data");
|
|
65
|
+
expect(result.data.params).toEqual({ test: "value" });
|
|
66
|
+
expect(result.data.name).toBe("NetworkError");
|
|
67
|
+
expect(result.data.context).toEqual({ app: "test" });
|
|
68
|
+
expect(result.jsOnly).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should handle error with request but no response and no message", () => {
|
|
72
|
+
const err = {
|
|
73
|
+
request: {},
|
|
74
|
+
config: {
|
|
75
|
+
url: "https://api.example.com/data",
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const result = getParsedResponse(err);
|
|
80
|
+
|
|
81
|
+
expect(result.message).toBe(`Error: ${RESPONSES.noResponse}`);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should handle error with neither response nor request", () => {
|
|
85
|
+
const err = {
|
|
86
|
+
message: "Failed to set up request",
|
|
87
|
+
config: {
|
|
88
|
+
url: "https://api.example.com/data",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const result = getParsedResponse(err);
|
|
93
|
+
|
|
94
|
+
expect(result.message).toBe("Error: Failed to set up request");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should handle error with neither response nor request and no message", () => {
|
|
98
|
+
const err = {
|
|
99
|
+
config: {
|
|
100
|
+
url: "https://api.example.com/data",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const result = getParsedResponse(err);
|
|
105
|
+
|
|
106
|
+
expect(result.message).toBe(`Error: ${RESPONSES.unknown}`);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should handle null error", () => {
|
|
110
|
+
const err = null;
|
|
111
|
+
|
|
112
|
+
const result = getParsedResponse(err);
|
|
113
|
+
|
|
114
|
+
expect(result.message).toBe(`Error: ${RESPONSES.unknown}`);
|
|
115
|
+
|
|
116
|
+
expect(result.data).toEqual({
|
|
117
|
+
context: undefined,
|
|
118
|
+
name: undefined,
|
|
119
|
+
params: undefined,
|
|
120
|
+
url: undefined,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should handle undefined error", () => {
|
|
125
|
+
const err = undefined;
|
|
126
|
+
|
|
127
|
+
const result = getParsedResponse(err);
|
|
128
|
+
|
|
129
|
+
expect(result.message).toBe(`Error: ${RESPONSES.unknown}`);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should extract params from err.config when response is not present", () => {
|
|
133
|
+
const err = {
|
|
134
|
+
request: {},
|
|
135
|
+
message: "Request failed",
|
|
136
|
+
config: {
|
|
137
|
+
url: "https://api.example.com/data",
|
|
138
|
+
params: { key: "value" },
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const result = getParsedResponse(err);
|
|
143
|
+
|
|
144
|
+
expect(result.data.params).toEqual({ key: "value" });
|
|
145
|
+
expect(result.data.url).toBe("https://api.example.com/data");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should prioritize response config over error config", () => {
|
|
149
|
+
const err = {
|
|
150
|
+
response: {
|
|
151
|
+
status: 404,
|
|
152
|
+
config: {
|
|
153
|
+
url: "https://api.example.com/response-url",
|
|
154
|
+
params: { from: "response" },
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
config: {
|
|
158
|
+
url: "https://api.example.com/error-url",
|
|
159
|
+
params: { from: "error" },
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const result = getParsedResponse(err);
|
|
164
|
+
|
|
165
|
+
expect(result.data.url).toBe("https://api.example.com/response-url");
|
|
166
|
+
expect(result.data.params).toEqual({ from: "response" });
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should handle response with custom status codes", () => {
|
|
170
|
+
const err = {
|
|
171
|
+
response: {
|
|
172
|
+
data: {
|
|
173
|
+
statusCode: 418,
|
|
174
|
+
message: "I'm a teapot",
|
|
175
|
+
},
|
|
176
|
+
status: 418,
|
|
177
|
+
config: {
|
|
178
|
+
url: "https://api.example.com/coffee",
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const result = getParsedResponse(err);
|
|
184
|
+
|
|
185
|
+
expect(result.message).toBe("Error: I'm a teapot");
|
|
186
|
+
expect(result.data.statusCode).toBe("418");
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { invariant } from "../index";
|
|
2
|
+
|
|
3
|
+
// Mock __DEV__ global
|
|
4
|
+
declare global {
|
|
5
|
+
var __DEV__: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
describe("invariant", () => {
|
|
9
|
+
const originalDev = global.__DEV__;
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
global.__DEV__ = originalDev;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("in development mode", () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
global.__DEV__ = true;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should not throw when condition is true", () => {
|
|
21
|
+
expect(() => {
|
|
22
|
+
invariant(true, "This should not throw");
|
|
23
|
+
}).not.toThrow();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should throw when condition is false", () => {
|
|
27
|
+
expect(() => {
|
|
28
|
+
invariant(false, "This should throw");
|
|
29
|
+
}).toThrow("This should throw");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should throw with correct error message", () => {
|
|
33
|
+
const errorMessage = "Custom error message";
|
|
34
|
+
|
|
35
|
+
expect(() => {
|
|
36
|
+
invariant(false, errorMessage);
|
|
37
|
+
}).toThrow(errorMessage);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should not throw when condition is truthy value", () => {
|
|
41
|
+
expect(() => {
|
|
42
|
+
invariant(1 as any, "Should not throw");
|
|
43
|
+
}).not.toThrow();
|
|
44
|
+
|
|
45
|
+
expect(() => {
|
|
46
|
+
invariant("string" as any, "Should not throw");
|
|
47
|
+
}).not.toThrow();
|
|
48
|
+
|
|
49
|
+
expect(() => {
|
|
50
|
+
invariant({} as any, "Should not throw");
|
|
51
|
+
}).not.toThrow();
|
|
52
|
+
|
|
53
|
+
expect(() => {
|
|
54
|
+
invariant([] as any, "Should not throw");
|
|
55
|
+
}).not.toThrow();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should throw when condition is falsy value", () => {
|
|
59
|
+
expect(() => {
|
|
60
|
+
invariant(0 as any, "Should throw for 0");
|
|
61
|
+
}).toThrow("Should throw for 0");
|
|
62
|
+
|
|
63
|
+
expect(() => {
|
|
64
|
+
invariant("" as any, "Should throw for empty string");
|
|
65
|
+
}).toThrow("Should throw for empty string");
|
|
66
|
+
|
|
67
|
+
expect(() => {
|
|
68
|
+
invariant(null as any, "Should throw for null");
|
|
69
|
+
}).toThrow("Should throw for null");
|
|
70
|
+
|
|
71
|
+
expect(() => {
|
|
72
|
+
invariant(undefined as any, "Should throw for undefined");
|
|
73
|
+
}).toThrow("Should throw for undefined");
|
|
74
|
+
|
|
75
|
+
expect(() => {
|
|
76
|
+
invariant(NaN as any, "Should throw for NaN");
|
|
77
|
+
}).toThrow("Should throw for NaN");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("in production mode", () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
global.__DEV__ = false;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should not throw when condition is true", () => {
|
|
87
|
+
expect(() => {
|
|
88
|
+
invariant(true, "This should not throw");
|
|
89
|
+
}).not.toThrow();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should not throw when condition is false", () => {
|
|
93
|
+
expect(() => {
|
|
94
|
+
invariant(false, "This should not throw in production");
|
|
95
|
+
}).not.toThrow();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should not throw for any condition", () => {
|
|
99
|
+
expect(() => {
|
|
100
|
+
invariant(0 as any, "Should not throw in production");
|
|
101
|
+
}).not.toThrow();
|
|
102
|
+
|
|
103
|
+
expect(() => {
|
|
104
|
+
invariant(null as any, "Should not throw in production");
|
|
105
|
+
}).not.toThrow();
|
|
106
|
+
|
|
107
|
+
expect(() => {
|
|
108
|
+
invariant(undefined as any, "Should not throw in production");
|
|
109
|
+
}).not.toThrow();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
2
2
|
import { getAppDataHeaders } from "../index";
|
|
3
3
|
|
|
4
|
+
const mockUILanguage = "en-US";
|
|
5
|
+
|
|
6
|
+
jest.mock(
|
|
7
|
+
"@applicaster/zapp-react-native-utils/appUtils/localizationsHelper",
|
|
8
|
+
() => ({
|
|
9
|
+
getUILanguage: jest.fn(() => mockUILanguage),
|
|
10
|
+
})
|
|
11
|
+
);
|
|
12
|
+
|
|
4
13
|
describe("getAppDataHeaders", () => {
|
|
5
14
|
const mockAppData = {
|
|
6
15
|
riversConfigurationId: "test-layout",
|
|
@@ -25,7 +34,7 @@ describe("getAppDataHeaders", () => {
|
|
|
25
34
|
const expectedHeaders = {
|
|
26
35
|
"x-applicaster-layout-id": mockAppData.riversConfigurationId,
|
|
27
36
|
"x-applicaster-screen-id": screenId,
|
|
28
|
-
"x-applicaster-language-code":
|
|
37
|
+
"x-applicaster-language-code": mockUILanguage,
|
|
29
38
|
"x-applicaster-version-number": mockAppData.version_name,
|
|
30
39
|
"x-applicaster-platform": mockAppData.platform,
|
|
31
40
|
"x-applicaster-country-code": mockAppData.countryCode,
|
|
@@ -33,6 +42,7 @@ describe("getAppDataHeaders", () => {
|
|
|
33
42
|
mockAppData.signedDeviceInfoToken,
|
|
34
43
|
"x-applicaster-device-make": mockAppData.deviceMake,
|
|
35
44
|
"x-applicaster-device-model": mockAppData.deviceModel,
|
|
45
|
+
"x-applicaster-uuid": undefined,
|
|
36
46
|
};
|
|
37
47
|
|
|
38
48
|
const headers = getAppDataHeaders(screenId);
|
package/headersUtils/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
2
2
|
import { getPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
3
3
|
import { utilsLogger } from "../logger";
|
|
4
|
+
import { getUILanguage } from "../localizationUtils";
|
|
4
5
|
|
|
5
6
|
const logger = utilsLogger.addSubsystem("headersUtils");
|
|
6
7
|
|
|
@@ -21,7 +22,7 @@ export const getAppDataHeaders = (screenId: string) => {
|
|
|
21
22
|
"x-applicaster-layout-id":
|
|
22
23
|
appData.riversConfigurationId || appData.rivers_configuration_id,
|
|
23
24
|
"x-applicaster-screen-id": screenId,
|
|
24
|
-
"x-applicaster-language-code":
|
|
25
|
+
"x-applicaster-language-code": getUILanguage(),
|
|
25
26
|
"x-applicaster-version-number": appData.version_name || appData.versionName,
|
|
26
27
|
"x-applicaster-platform": (platform || appData.platform).toLowerCase(),
|
|
27
28
|
"x-applicaster-country-code": appData.countryCode,
|
|
@@ -123,6 +123,12 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
123
123
|
key: "skip_button_localization_text_skip_intro",
|
|
124
124
|
initial_value: "Skip Intro",
|
|
125
125
|
},
|
|
126
|
+
{
|
|
127
|
+
type: "text_input",
|
|
128
|
+
label: "Stream error message",
|
|
129
|
+
key: "stream_error_message",
|
|
130
|
+
initial_value: "Cannot play stream",
|
|
131
|
+
},
|
|
126
132
|
{
|
|
127
133
|
type: "text_input",
|
|
128
134
|
label: "Locked message",
|
|
@@ -707,22 +713,6 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
707
713
|
}
|
|
708
714
|
|
|
709
715
|
if (isMobile(platform)) {
|
|
710
|
-
localizations.fields.push(
|
|
711
|
-
{
|
|
712
|
-
type: "text_input",
|
|
713
|
-
label: "Restrict playback on mobile networks alert title",
|
|
714
|
-
key: "mobile_connection_restricted_alert_title",
|
|
715
|
-
initial_value: "Restricted Connection Type",
|
|
716
|
-
},
|
|
717
|
-
{
|
|
718
|
-
type: "text_input",
|
|
719
|
-
label: "Restrict playback on mobile networks alert message",
|
|
720
|
-
key: "mobile_connection_restricted_alert_message",
|
|
721
|
-
initial_value:
|
|
722
|
-
"This content can only be viewed over a Wi-Fi or LAN network.",
|
|
723
|
-
}
|
|
724
|
-
);
|
|
725
|
-
|
|
726
716
|
general.fields.push(
|
|
727
717
|
{
|
|
728
718
|
section: "Default Timestamp Type",
|
|
@@ -24,6 +24,8 @@ describe("toNumber", () => {
|
|
|
24
24
|
it("return undefined if input is not a number", () => {
|
|
25
25
|
const inputs = [
|
|
26
26
|
"vfdvf",
|
|
27
|
+
"5n",
|
|
28
|
+
"-5n",
|
|
27
29
|
null,
|
|
28
30
|
undefined,
|
|
29
31
|
NaN,
|
|
@@ -41,4 +43,29 @@ describe("toNumber", () => {
|
|
|
41
43
|
expect(output).toBeUndefined();
|
|
42
44
|
});
|
|
43
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
|
+
});
|
|
44
71
|
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { toPositiveNumber } from "..";
|
|
2
|
+
|
|
3
|
+
describe("toPositiveNumber", () => {
|
|
4
|
+
describe("valid positive numbers", () => {
|
|
5
|
+
it("returns the number for positive integers", () => {
|
|
6
|
+
expect(toPositiveNumber(5)).toBe(5);
|
|
7
|
+
expect(toPositiveNumber(1000)).toBe(1000);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("returns the number for positive floats", () => {
|
|
11
|
+
expect(toPositiveNumber(0.1)).toBe(0.1);
|
|
12
|
+
expect(toPositiveNumber(3.14159)).toBe(3.14159);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("returns the number for very small positive numbers", () => {
|
|
16
|
+
expect(toPositiveNumber(1e-300)).toBe(1e-300);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("returns the number for very large positive numbers", () => {
|
|
20
|
+
expect(toPositiveNumber(1e300)).toBe(1e300);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("returns Infinity for positive infinity", () => {
|
|
24
|
+
expect(toPositiveNumber(Infinity)).toBe(Infinity);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("converts valid positive strings to numbers", () => {
|
|
28
|
+
expect(toPositiveNumber("5")).toBe(5);
|
|
29
|
+
expect(toPositiveNumber("3.14")).toBe(3.14);
|
|
30
|
+
expect(toPositiveNumber(" 100 ")).toBe(100);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("converts boolean true to undefined", () => {
|
|
34
|
+
expect(toPositiveNumber(true)).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("converts single-element arrays to undefined", () => {
|
|
38
|
+
expect(toPositiveNumber([5])).toBeUndefined();
|
|
39
|
+
expect(toPositiveNumber(["10"])).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("invalid cases (return undefined)", () => {
|
|
44
|
+
describe("zero values", () => {
|
|
45
|
+
it("returns undefined for zero", () => {
|
|
46
|
+
expect(toPositiveNumber(0)).toBeUndefined();
|
|
47
|
+
expect(toPositiveNumber(-0)).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("returns undefined for string zero", () => {
|
|
51
|
+
expect(toPositiveNumber("0")).toBeUndefined();
|
|
52
|
+
expect(toPositiveNumber(" 0 ")).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("returns undefined for boolean false", () => {
|
|
56
|
+
expect(toPositiveNumber(false)).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("returns undefined for empty arrays", () => {
|
|
60
|
+
expect(toPositiveNumber([])).toBeUndefined();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("returns undefined for empty strings", () => {
|
|
64
|
+
expect(toPositiveNumber("")).toBeUndefined();
|
|
65
|
+
expect(toPositiveNumber(" ")).toBeUndefined();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe("negative values", () => {
|
|
70
|
+
it("returns undefined for negative numbers", () => {
|
|
71
|
+
expect(toPositiveNumber(-5)).toBeUndefined();
|
|
72
|
+
expect(toPositiveNumber(-0.1)).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("returns undefined for negative strings", () => {
|
|
76
|
+
expect(toPositiveNumber("-5")).toBeUndefined();
|
|
77
|
+
expect(toPositiveNumber(" -10 ")).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("returns undefined for negative infinity", () => {
|
|
81
|
+
expect(toPositiveNumber(-Infinity)).toBeUndefined();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe("non-convertible values", () => {
|
|
86
|
+
it("returns undefined for null", () => {
|
|
87
|
+
expect(toPositiveNumber(null)).toBeUndefined();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("returns undefined for undefined", () => {
|
|
91
|
+
expect(toPositiveNumber(undefined)).toBeUndefined();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("returns undefined for objects", () => {
|
|
95
|
+
expect(toPositiveNumber({})).toBeUndefined();
|
|
96
|
+
expect(toPositiveNumber({ a: 1 })).toBeUndefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("returns undefined for multi-element arrays", () => {
|
|
100
|
+
expect(toPositiveNumber([1, 2])).toBeUndefined();
|
|
101
|
+
expect(toPositiveNumber(["a", "b"])).toBeUndefined();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("returns undefined for non-numeric strings", () => {
|
|
105
|
+
expect(toPositiveNumber("abc")).toBeUndefined();
|
|
106
|
+
expect(toPositiveNumber("5px")).toBeUndefined();
|
|
107
|
+
expect(toPositiveNumber("123.45.67")).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("returns undefined for NaN", () => {
|
|
111
|
+
expect(toPositiveNumber(NaN)).toBeUndefined();
|
|
112
|
+
expect(toPositiveNumber(Number("abc"))).toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("special cases", () => {
|
|
118
|
+
it("handles exponential notation correctly", () => {
|
|
119
|
+
expect(toPositiveNumber("1e5")).toBe(100000);
|
|
120
|
+
expect(toPositiveNumber("1e-5")).toBe(0.00001);
|
|
121
|
+
expect(toPositiveNumber("-1e5")).toBeUndefined();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("preserves precision for decimal numbers", () => {
|
|
125
|
+
expect(toPositiveNumber(0.1 + 0.2)).toBeCloseTo(0.3);
|
|
126
|
+
expect(toPositiveNumber("0.1")).toBe(0.1);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("handles numeric strings with leading zeros", () => {
|
|
130
|
+
expect(toPositiveNumber("005")).toBe(5);
|
|
131
|
+
expect(toPositiveNumber("0.5")).toBe(0.5);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("returns undefined for numeric strings with trailing non-numeric characters", () => {
|
|
135
|
+
expect(toPositiveNumber("5px")).toBeUndefined();
|
|
136
|
+
expect(toPositiveNumber("10%")).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("handles scientific notation correctly", () => {
|
|
140
|
+
expect(toPositiveNumber("1.5e2")).toBe(150);
|
|
141
|
+
expect(toPositiveNumber("-2.5e3")).toBeUndefined();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("type conversion behavior", () => {
|
|
146
|
+
it("converts Date objects correctly", () => {
|
|
147
|
+
const date = new Date(2026, 1, 17);
|
|
148
|
+
expect(toPositiveNumber(date)).toBeUndefined();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("converts functions to NaN (returns undefined)", () => {
|
|
152
|
+
expect(toPositiveNumber(() => {})).toBeUndefined();
|
|
153
|
+
expect(toPositiveNumber(Math.sqrt)).toBeUndefined();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("handles Symbol values", () => {
|
|
157
|
+
expect(toPositiveNumber(Symbol("test"))).toBeUndefined();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
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
|
+
}
|
|
192
|
+
});
|
|
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;
|
|
@@ -69,6 +73,24 @@ export const isMinusZero = (value: number) => {
|
|
|
69
73
|
return 1 / value === -Infinity;
|
|
70
74
|
};
|
|
71
75
|
|
|
76
|
+
export const toPositiveNumber = (value: unknown): number | undefined => {
|
|
77
|
+
const possibleNumber = toNumber(value);
|
|
78
|
+
|
|
79
|
+
if (R.isNil(possibleNumber)) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (possibleNumber < 0) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (isZero(possibleNumber)) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return possibleNumber;
|
|
92
|
+
};
|
|
93
|
+
|
|
72
94
|
export const toPositiveNumberWithDefault = (
|
|
73
95
|
defaultValue: number,
|
|
74
96
|
value: unknown
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "15.0.0-alpha.
|
|
3
|
+
"version": "15.0.0-alpha.1283350001",
|
|
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": "15.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "15.0.0-alpha.1283350001",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|