@applicaster/zapp-react-native-utils 15.0.0-rc.14 → 15.0.0-rc.140
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/actionsExecutor/ActionExecutorContext.tsx +86 -12
- package/actionsExecutor/feedDecorator.ts +6 -6
- package/adsUtils/__tests__/createVMAP.test.ts +419 -0
- package/adsUtils/index.ts +2 -2
- package/analyticsUtils/README.md +1 -1
- package/analyticsUtils/analyticsMapper.ts +10 -2
- 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/HooksManager/index.ts +45 -10
- package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
- package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
- package/appUtils/accessibilityManager/const.ts +4 -0
- package/appUtils/accessibilityManager/hooks.ts +20 -13
- package/appUtils/accessibilityManager/index.ts +28 -1
- package/appUtils/accessibilityManager/utils.ts +59 -8
- package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
- package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
- package/appUtils/contextKeysManager/contextResolver.ts +51 -22
- package/appUtils/contextKeysManager/index.ts +65 -10
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
- package/appUtils/focusManager/index.ios.ts +43 -4
- 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.ios.ts +122 -0
- package/appUtils/focusManagerAux/utils/index.ts +13 -7
- package/appUtils/focusManagerAux/utils/utils.ios.ts +202 -3
- package/appUtils/keyCodes/keys/keys.web.ts +1 -4
- package/appUtils/localizationsHelper.ts +4 -0
- package/appUtils/orientationHelper.ts +2 -4
- package/appUtils/platform/platformUtils.ts +117 -18
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
- package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
- package/appUtils/playerManager/index.ts +9 -0
- package/appUtils/playerManager/player.ts +5 -1
- package/appUtils/playerManager/playerNative.ts +31 -17
- package/appUtils/playerManager/usePlayer.tsx +5 -3
- package/appUtils/playerManager/usePlayerState.tsx +14 -2
- package/arrayUtils/__tests__/allTruthy.test.ts +24 -0
- package/arrayUtils/__tests__/anyThruthy.test.ts +24 -0
- package/arrayUtils/index.ts +5 -0
- package/cellUtils/__tests__/cellUtils.test.ts +39 -0
- package/cellUtils/index.ts +43 -1
- package/cloudEventsUtils/__tests__/index.test.ts +529 -0
- package/cloudEventsUtils/index.ts +65 -1
- package/componentsUtils/index.ts +8 -0
- package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +38 -0
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
- package/configurationUtils/index.ts +17 -11
- package/dateUtils/__tests__/dayjs.test.ts +327 -0
- package/dateUtils/index.ts +2 -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/focusManager/aux/index.ts +1 -1
- package/headersUtils/__tests__/headersUtils.test.js +11 -1
- package/headersUtils/index.ts +2 -1
- package/manifestUtils/_internals/__tests__/index.test.js +41 -0
- package/manifestUtils/_internals/index.js +33 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +115 -11
- package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +49 -0
- package/manifestUtils/fieldUtils/index.js +54 -0
- package/manifestUtils/index.js +2 -0
- package/manifestUtils/keys.js +249 -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/manifestUtils/platformIsTV.js +13 -0
- package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
- package/manifestUtils/tvAction/container/index.js +1 -1
- package/navigationUtils/index.ts +15 -5
- 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 +4 -4
- package/playerUtils/usePlayerTTS.ts +8 -3
- package/pluginUtils/index.ts +4 -0
- package/reactHooks/advertising/index.ts +2 -2
- package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
- package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
- package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
- package/reactHooks/cell-click/__tests__/index.test.js +1 -3
- package/reactHooks/cell-click/index.ts +2 -1
- package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
- package/reactHooks/connection/__tests__/index.test.js +1 -1
- package/reactHooks/debugging/__tests__/index.test.js +4 -4
- package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
- package/reactHooks/device/useIsTablet.tsx +14 -19
- package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
- package/reactHooks/events/index.ts +20 -0
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
- package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
- package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
- package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
- package/reactHooks/feed/index.ts +0 -2
- package/reactHooks/feed/useBatchLoading.ts +7 -1
- package/reactHooks/feed/useEntryScreenId.ts +2 -2
- package/reactHooks/feed/useInflatedUrl.ts +44 -18
- package/reactHooks/feed/usePipesCacheReset.ts +3 -1
- package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
- package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
- package/reactHooks/index.ts +2 -0
- package/reactHooks/layout/__tests__/index.test.tsx +1 -1
- package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
- package/reactHooks/layout/index.ts +1 -1
- package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
- package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
- package/reactHooks/navigation/index.ts +27 -11
- package/reactHooks/navigation/useRoute.ts +11 -7
- package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
- package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
- package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
- package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
- package/reactHooks/resolvers/useCellResolver.ts +6 -2
- package/reactHooks/resolvers/useComponentResolver.ts +19 -3
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
- package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
- package/reactHooks/screen/useTargetScreenData.ts +4 -2
- 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/state/useRefWithInitialValue.ts +10 -0
- package/reactHooks/state/useRivers.ts +1 -1
- package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
- package/reactHooks/usePluginConfiguration.ts +2 -2
- package/reactHooks/utils/__tests__/index.test.js +1 -1
- package/rectUtils/__tests__/index.test.ts +549 -0
- package/rectUtils/index.ts +2 -2
- 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/__tests__/index.test.ts +333 -0
- package/screenPickerUtils/index.ts +5 -0
- package/screenState/__tests__/index.test.ts +1 -1
- package/screenUtils/index.ts +3 -0
- package/searchUtils/const.ts +7 -0
- package/searchUtils/index.ts +3 -0
- package/services/storageServiceSync.web.ts +1 -1
- package/stringUtils/index.ts +1 -1
- package/testUtils/index.tsx +30 -21
- 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__/mapAccum.test.ts +73 -0
- package/utils/__tests__/mergeRight.test.ts +48 -0
- package/utils/__tests__/path.test.ts +7 -0
- package/utils/__tests__/selectors.test.ts +124 -0
- package/utils/clone.ts +7 -0
- package/utils/index.ts +21 -1
- package/utils/mapAccum.ts +23 -0
- package/utils/mergeRight.ts +5 -0
- package/utils/path.ts +6 -3
- package/utils/pathOr.ts +5 -1
- package/utils/selectors.ts +46 -0
- package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +49 -12
- package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -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,207 @@
|
|
|
1
|
+
import { getEnumKeyByEnumValue } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("getEnumKeyByEnumValue", () => {
|
|
4
|
+
enum TestEnum {
|
|
5
|
+
First = "FIRST",
|
|
6
|
+
Second = "SECOND",
|
|
7
|
+
Third = "THIRD",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
enum NumericEnum {
|
|
11
|
+
Zero = 0,
|
|
12
|
+
One = 1,
|
|
13
|
+
Two = 2,
|
|
14
|
+
Three = 3,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
enum MixedEnum {
|
|
18
|
+
StringValue = "string",
|
|
19
|
+
NumericValue = 42,
|
|
20
|
+
BooleanValue = "true",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("string enums", () => {
|
|
24
|
+
it("should return key for valid enum value", () => {
|
|
25
|
+
expect(getEnumKeyByEnumValue(TestEnum, "FIRST")).toBe("First");
|
|
26
|
+
expect(getEnumKeyByEnumValue(TestEnum, "SECOND")).toBe("Second");
|
|
27
|
+
expect(getEnumKeyByEnumValue(TestEnum, "THIRD")).toBe("Third");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should return null for invalid enum value", () => {
|
|
31
|
+
expect(getEnumKeyByEnumValue(TestEnum, "INVALID")).toBeNull();
|
|
32
|
+
expect(getEnumKeyByEnumValue(TestEnum, "")).toBeNull();
|
|
33
|
+
expect(getEnumKeyByEnumValue(TestEnum, "first")).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should be case-sensitive", () => {
|
|
37
|
+
expect(getEnumKeyByEnumValue(TestEnum, "first")).toBeNull();
|
|
38
|
+
expect(getEnumKeyByEnumValue(TestEnum, "FIRST")).toBe("First");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("numeric enums", () => {
|
|
43
|
+
it("should return key for valid numeric enum value", () => {
|
|
44
|
+
expect(getEnumKeyByEnumValue(NumericEnum, 0)).toBe("Zero");
|
|
45
|
+
expect(getEnumKeyByEnumValue(NumericEnum, 1)).toBe("One");
|
|
46
|
+
expect(getEnumKeyByEnumValue(NumericEnum, 2)).toBe("Two");
|
|
47
|
+
expect(getEnumKeyByEnumValue(NumericEnum, 3)).toBe("Three");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should return null for invalid numeric value", () => {
|
|
51
|
+
expect(getEnumKeyByEnumValue(NumericEnum, 4)).toBeNull();
|
|
52
|
+
expect(getEnumKeyByEnumValue(NumericEnum, -1)).toBeNull();
|
|
53
|
+
expect(getEnumKeyByEnumValue(NumericEnum, 999)).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should handle numeric strings", () => {
|
|
57
|
+
// When passing string "0", it won't match numeric enum value 0
|
|
58
|
+
expect(getEnumKeyByEnumValue(NumericEnum, "0")).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("mixed enums", () => {
|
|
63
|
+
it("should handle string values in mixed enum", () => {
|
|
64
|
+
expect(getEnumKeyByEnumValue(MixedEnum, "string")).toBe("StringValue");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should handle numeric values in mixed enum", () => {
|
|
68
|
+
expect(getEnumKeyByEnumValue(MixedEnum, 42)).toBe("NumericValue");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should handle boolean-like string values", () => {
|
|
72
|
+
expect(getEnumKeyByEnumValue(MixedEnum, "true")).toBe("BooleanValue");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should not match boolean to string 'true'", () => {
|
|
76
|
+
expect(getEnumKeyByEnumValue(MixedEnum, true)).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("edge cases", () => {
|
|
81
|
+
it("should return null for null value", () => {
|
|
82
|
+
expect(getEnumKeyByEnumValue(TestEnum, null)).toBeNull();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should return null for undefined value", () => {
|
|
86
|
+
expect(getEnumKeyByEnumValue(TestEnum, undefined)).toBeNull();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should handle empty enum", () => {
|
|
90
|
+
const EmptyEnum = {};
|
|
91
|
+
expect(getEnumKeyByEnumValue(EmptyEnum, "anything")).toBeNull();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should handle object values", () => {
|
|
95
|
+
expect(getEnumKeyByEnumValue(TestEnum, {})).toBeNull();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should handle array values", () => {
|
|
99
|
+
expect(getEnumKeyByEnumValue(TestEnum, [])).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should return first matching key if multiple keys have same value", () => {
|
|
103
|
+
enum DuplicateEnum {
|
|
104
|
+
First = "SAME",
|
|
105
|
+
Second = "SAME",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = getEnumKeyByEnumValue(DuplicateEnum, "SAME");
|
|
109
|
+
expect(result).toBeTruthy();
|
|
110
|
+
expect(["First", "Second"]).toContain(result);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("type checking", () => {
|
|
115
|
+
it("should work with const enum-like objects", () => {
|
|
116
|
+
const ConstLikeEnum = {
|
|
117
|
+
KEY_ONE: "value1",
|
|
118
|
+
KEY_TWO: "value2",
|
|
119
|
+
} as const;
|
|
120
|
+
|
|
121
|
+
expect(getEnumKeyByEnumValue(ConstLikeEnum, "value1")).toBe("KEY_ONE");
|
|
122
|
+
expect(getEnumKeyByEnumValue(ConstLikeEnum, "value2")).toBe("KEY_TWO");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should work with plain objects", () => {
|
|
126
|
+
const plainObject = {
|
|
127
|
+
key1: "val1",
|
|
128
|
+
key2: "val2",
|
|
129
|
+
key3: 123,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
expect(getEnumKeyByEnumValue(plainObject, "val1")).toBe("key1");
|
|
133
|
+
expect(getEnumKeyByEnumValue(plainObject, 123)).toBe("key3");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("should return correct TypeScript type", () => {
|
|
137
|
+
const result = getEnumKeyByEnumValue(TestEnum, "FIRST");
|
|
138
|
+
|
|
139
|
+
// Result should be keyof TestEnum | null
|
|
140
|
+
if (result !== null) {
|
|
141
|
+
expect(typeof result).toBe("string");
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("special values", () => {
|
|
147
|
+
enum SpecialEnum {
|
|
148
|
+
EmptyString = "",
|
|
149
|
+
Zero = 0,
|
|
150
|
+
False = "false",
|
|
151
|
+
Null = "null",
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
it("should handle empty string value", () => {
|
|
155
|
+
expect(getEnumKeyByEnumValue(SpecialEnum, "")).toBe("EmptyString");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should handle zero value", () => {
|
|
159
|
+
expect(getEnumKeyByEnumValue(SpecialEnum, 0)).toBe("Zero");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should handle false-like string", () => {
|
|
163
|
+
expect(getEnumKeyByEnumValue(SpecialEnum, "false")).toBe("False");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should handle null-like string", () => {
|
|
167
|
+
expect(getEnumKeyByEnumValue(SpecialEnum, "null")).toBe("Null");
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("performance", () => {
|
|
172
|
+
it("should handle large enums efficiently", () => {
|
|
173
|
+
const largeEnum: Record<string, string> = {};
|
|
174
|
+
|
|
175
|
+
for (let i = 0; i < 1000; i++) {
|
|
176
|
+
largeEnum[`Key${i}`] = `Value${i}`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
expect(getEnumKeyByEnumValue(largeEnum, "Value500")).toBe("Key500");
|
|
180
|
+
expect(getEnumKeyByEnumValue(largeEnum, "Value999")).toBe("Key999");
|
|
181
|
+
expect(getEnumKeyByEnumValue(largeEnum, "NonExistent")).toBeNull();
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe("reverse lookup", () => {
|
|
186
|
+
enum ReverseEnum {
|
|
187
|
+
A = "ValueA",
|
|
188
|
+
B = "ValueB",
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
it("should provide reverse lookup functionality", () => {
|
|
192
|
+
// Forward: get value from key
|
|
193
|
+
expect(ReverseEnum.A).toBe("ValueA");
|
|
194
|
+
|
|
195
|
+
// Reverse: get key from value
|
|
196
|
+
expect(getEnumKeyByEnumValue(ReverseEnum, "ValueA")).toBe("A");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should be consistent with enum access", () => {
|
|
200
|
+
const key = getEnumKeyByEnumValue(TestEnum, "SECOND");
|
|
201
|
+
|
|
202
|
+
if (key) {
|
|
203
|
+
expect(TestEnum[key]).toBe("SECOND");
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { GeneralError } from "../GeneralError";
|
|
2
|
+
|
|
3
|
+
describe("GeneralError", () => {
|
|
4
|
+
it("should create error with message only", () => {
|
|
5
|
+
const message = "Something went wrong";
|
|
6
|
+
const error = new GeneralError(message);
|
|
7
|
+
|
|
8
|
+
expect(error).toBeInstanceOf(Error);
|
|
9
|
+
expect(error).toBeInstanceOf(GeneralError);
|
|
10
|
+
expect(error.message).toBe(message);
|
|
11
|
+
expect(error.statusCode).toBeNull();
|
|
12
|
+
expect(error.localizationKey).toBeNull();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should create error with message and status code", () => {
|
|
16
|
+
const message = "Not found";
|
|
17
|
+
const statusCode = 404;
|
|
18
|
+
const error = new GeneralError(message, statusCode);
|
|
19
|
+
|
|
20
|
+
expect(error.message).toBe(message);
|
|
21
|
+
expect(error.statusCode).toBe(statusCode);
|
|
22
|
+
expect(error.localizationKey).toBeNull();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should create error with all parameters", () => {
|
|
26
|
+
const message = "Forbidden";
|
|
27
|
+
const statusCode = 403;
|
|
28
|
+
const localizationKey = "error.forbidden";
|
|
29
|
+
const error = new GeneralError(message, statusCode, localizationKey);
|
|
30
|
+
|
|
31
|
+
expect(error.message).toBe(message);
|
|
32
|
+
expect(error.statusCode).toBe(statusCode);
|
|
33
|
+
expect(error.localizationKey).toBe(localizationKey);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should create error with null status code explicitly", () => {
|
|
37
|
+
const message = "Error without status";
|
|
38
|
+
const error = new GeneralError(message, null, "error.general");
|
|
39
|
+
|
|
40
|
+
expect(error.message).toBe(message);
|
|
41
|
+
expect(error.statusCode).toBeNull();
|
|
42
|
+
expect(error.localizationKey).toBe("error.general");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should create error with null localization key explicitly", () => {
|
|
46
|
+
const message = "Server error";
|
|
47
|
+
const statusCode = 500;
|
|
48
|
+
const error = new GeneralError(message, statusCode, null);
|
|
49
|
+
|
|
50
|
+
expect(error.message).toBe(message);
|
|
51
|
+
expect(error.statusCode).toBe(statusCode);
|
|
52
|
+
expect(error.localizationKey).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should have error name", () => {
|
|
56
|
+
const error = new GeneralError("Test error");
|
|
57
|
+
|
|
58
|
+
expect(error.name).toBe("Error");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should be throwable and catchable", () => {
|
|
62
|
+
const message = "Test throw";
|
|
63
|
+
const statusCode = 400;
|
|
64
|
+
|
|
65
|
+
expect(() => {
|
|
66
|
+
throw new GeneralError(message, statusCode);
|
|
67
|
+
}).toThrow(GeneralError);
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
throw new GeneralError(message, statusCode);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
expect(error).toBeInstanceOf(GeneralError);
|
|
73
|
+
expect((error as GeneralError).message).toBe(message);
|
|
74
|
+
expect((error as GeneralError).statusCode).toBe(statusCode);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should maintain error stack trace", () => {
|
|
79
|
+
const error = new GeneralError("Stack trace test");
|
|
80
|
+
|
|
81
|
+
expect(error.stack).toBeDefined();
|
|
82
|
+
expect(error.stack).toContain("Stack trace test");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should allow status code to be 0", () => {
|
|
86
|
+
const error = new GeneralError("Zero status", 0);
|
|
87
|
+
|
|
88
|
+
expect(error.statusCode).toBe(0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should allow empty string message", () => {
|
|
92
|
+
const error = new GeneralError("");
|
|
93
|
+
|
|
94
|
+
expect(error.message).toBe("");
|
|
95
|
+
expect(error.statusCode).toBeNull();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { HttpStatusCode, HttpStatusCodeHelper } from "../HttpStatusCode";
|
|
2
|
+
|
|
3
|
+
describe("HttpStatusCode", () => {
|
|
4
|
+
describe("enum values", () => {
|
|
5
|
+
it("should have correct informational status codes", () => {
|
|
6
|
+
expect(HttpStatusCode.Continue).toBe(100);
|
|
7
|
+
expect(HttpStatusCode.SwitchingProtocols).toBe(101);
|
|
8
|
+
expect(HttpStatusCode.Processing).toBe(102);
|
|
9
|
+
expect(HttpStatusCode.EarlyHints).toBe(103);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should have correct success status codes", () => {
|
|
13
|
+
expect(HttpStatusCode.Ok).toBe(200);
|
|
14
|
+
expect(HttpStatusCode.Created).toBe(201);
|
|
15
|
+
expect(HttpStatusCode.Accepted).toBe(202);
|
|
16
|
+
expect(HttpStatusCode.NoContent).toBe(204);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should have correct redirection status codes", () => {
|
|
20
|
+
expect(HttpStatusCode.MovedPermanently).toBe(301);
|
|
21
|
+
expect(HttpStatusCode.Found).toBe(302);
|
|
22
|
+
expect(HttpStatusCode.SeeOther).toBe(303);
|
|
23
|
+
expect(HttpStatusCode.NotModified).toBe(304);
|
|
24
|
+
expect(HttpStatusCode.TemporaryRedirect).toBe(307);
|
|
25
|
+
expect(HttpStatusCode.PermanentRedirect).toBe(308);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should have correct client error status codes", () => {
|
|
29
|
+
expect(HttpStatusCode.BadRequest).toBe(400);
|
|
30
|
+
expect(HttpStatusCode.Unauthorized).toBe(401);
|
|
31
|
+
expect(HttpStatusCode.PaymentRequired).toBe(402);
|
|
32
|
+
expect(HttpStatusCode.Forbidden).toBe(403);
|
|
33
|
+
expect(HttpStatusCode.NotFound).toBe(404);
|
|
34
|
+
expect(HttpStatusCode.MethodNotAllowed).toBe(405);
|
|
35
|
+
expect(HttpStatusCode.RequestTimeout).toBe(408);
|
|
36
|
+
expect(HttpStatusCode.Conflict).toBe(409);
|
|
37
|
+
expect(HttpStatusCode.Gone).toBe(410);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should have correct server error status codes", () => {
|
|
41
|
+
expect(HttpStatusCode.InternalServerError).toBe(500);
|
|
42
|
+
expect(HttpStatusCode.NotImplemented).toBe(501);
|
|
43
|
+
expect(HttpStatusCode.BadGateway).toBe(502);
|
|
44
|
+
expect(HttpStatusCode.ServiceUnavailable).toBe(503);
|
|
45
|
+
expect(HttpStatusCode.GatewayTimeout).toBe(504);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should have special status codes", () => {
|
|
49
|
+
expect(HttpStatusCode.ImATeapot).toBe(418);
|
|
50
|
+
expect(HttpStatusCode.TooManyRequests).toBe(429);
|
|
51
|
+
expect(HttpStatusCode.UnavailableForLegalReasons).toBe(451);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("HttpStatusCodeHelper", () => {
|
|
57
|
+
describe("fromStatusCode", () => {
|
|
58
|
+
it("should return -1 for null status code", () => {
|
|
59
|
+
expect(HttpStatusCodeHelper.fromStatusCode(null as any)).toBe(-1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should return -1 for undefined status code", () => {
|
|
63
|
+
expect(HttpStatusCodeHelper.fromStatusCode(undefined as any)).toBe(-1);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should return -1 for 0 status code", () => {
|
|
67
|
+
expect(HttpStatusCodeHelper.fromStatusCode(0)).toBe(-1);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should return correct HttpStatusCode for valid status codes", () => {
|
|
71
|
+
expect(HttpStatusCodeHelper.fromStatusCode(200)).toBe(HttpStatusCode.Ok);
|
|
72
|
+
|
|
73
|
+
expect(HttpStatusCodeHelper.fromStatusCode(201)).toBe(
|
|
74
|
+
HttpStatusCode.Created
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
expect(HttpStatusCodeHelper.fromStatusCode(400)).toBe(
|
|
78
|
+
HttpStatusCode.BadRequest
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(HttpStatusCodeHelper.fromStatusCode(401)).toBe(
|
|
82
|
+
HttpStatusCode.Unauthorized
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(HttpStatusCodeHelper.fromStatusCode(404)).toBe(
|
|
86
|
+
HttpStatusCode.NotFound
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect(HttpStatusCodeHelper.fromStatusCode(500)).toBe(
|
|
90
|
+
HttpStatusCode.InternalServerError
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should return the status code itself for unknown codes", () => {
|
|
95
|
+
expect(HttpStatusCodeHelper.fromStatusCode(999)).toBe(999);
|
|
96
|
+
expect(HttpStatusCodeHelper.fromStatusCode(123)).toBe(123);
|
|
97
|
+
expect(HttpStatusCodeHelper.fromStatusCode(600)).toBe(600);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should handle all standard HTTP status codes", () => {
|
|
101
|
+
const standardCodes = [
|
|
102
|
+
100, 101, 102, 103, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
|
|
103
|
+
300, 301, 302, 303, 304, 305, 306, 307, 308, 400, 401, 402, 403, 404,
|
|
104
|
+
405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418,
|
|
105
|
+
421, 422, 423, 424, 425, 426, 428, 429, 431, 451, 500, 501, 502, 503,
|
|
106
|
+
504, 505, 506, 507, 508, 510, 511,
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
standardCodes.forEach((code) => {
|
|
110
|
+
const result = HttpStatusCodeHelper.fromStatusCode(code);
|
|
111
|
+
expect(result).toBe(code);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe("informational", () => {
|
|
117
|
+
it("should return true for 1xx status codes", () => {
|
|
118
|
+
expect(HttpStatusCodeHelper.informational(HttpStatusCode.Continue)).toBe(
|
|
119
|
+
true
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
expect(
|
|
123
|
+
HttpStatusCodeHelper.informational(HttpStatusCode.SwitchingProtocols)
|
|
124
|
+
).toBe(true);
|
|
125
|
+
|
|
126
|
+
expect(
|
|
127
|
+
HttpStatusCodeHelper.informational(HttpStatusCode.Processing)
|
|
128
|
+
).toBe(true);
|
|
129
|
+
|
|
130
|
+
expect(
|
|
131
|
+
HttpStatusCodeHelper.informational(HttpStatusCode.EarlyHints)
|
|
132
|
+
).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should return false for non-1xx status codes", () => {
|
|
136
|
+
expect(HttpStatusCodeHelper.informational(HttpStatusCode.Ok)).toBe(false);
|
|
137
|
+
|
|
138
|
+
expect(
|
|
139
|
+
HttpStatusCodeHelper.informational(HttpStatusCode.MovedPermanently)
|
|
140
|
+
).toBe(false);
|
|
141
|
+
|
|
142
|
+
expect(
|
|
143
|
+
HttpStatusCodeHelper.informational(HttpStatusCode.BadRequest)
|
|
144
|
+
).toBe(false);
|
|
145
|
+
|
|
146
|
+
expect(
|
|
147
|
+
HttpStatusCodeHelper.informational(HttpStatusCode.InternalServerError)
|
|
148
|
+
).toBe(false);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("successful", () => {
|
|
153
|
+
it("should return true for 2xx status codes", () => {
|
|
154
|
+
expect(HttpStatusCodeHelper.successful(HttpStatusCode.Ok)).toBe(true);
|
|
155
|
+
|
|
156
|
+
expect(HttpStatusCodeHelper.successful(HttpStatusCode.Created)).toBe(
|
|
157
|
+
true
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
expect(HttpStatusCodeHelper.successful(HttpStatusCode.Accepted)).toBe(
|
|
161
|
+
true
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
expect(HttpStatusCodeHelper.successful(HttpStatusCode.NoContent)).toBe(
|
|
165
|
+
true
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should return false for non-2xx status codes", () => {
|
|
170
|
+
expect(HttpStatusCodeHelper.successful(HttpStatusCode.Continue)).toBe(
|
|
171
|
+
false
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
expect(
|
|
175
|
+
HttpStatusCodeHelper.successful(HttpStatusCode.MovedPermanently)
|
|
176
|
+
).toBe(false);
|
|
177
|
+
|
|
178
|
+
expect(HttpStatusCodeHelper.successful(HttpStatusCode.BadRequest)).toBe(
|
|
179
|
+
false
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
expect(
|
|
183
|
+
HttpStatusCodeHelper.successful(HttpStatusCode.InternalServerError)
|
|
184
|
+
).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("redirection", () => {
|
|
189
|
+
it("should return true for 3xx status codes", () => {
|
|
190
|
+
expect(
|
|
191
|
+
HttpStatusCodeHelper.redirection(HttpStatusCode.MovedPermanently)
|
|
192
|
+
).toBe(true);
|
|
193
|
+
|
|
194
|
+
expect(HttpStatusCodeHelper.redirection(HttpStatusCode.Found)).toBe(true);
|
|
195
|
+
|
|
196
|
+
expect(HttpStatusCodeHelper.redirection(HttpStatusCode.SeeOther)).toBe(
|
|
197
|
+
true
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(HttpStatusCodeHelper.redirection(HttpStatusCode.NotModified)).toBe(
|
|
201
|
+
true
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
expect(
|
|
205
|
+
HttpStatusCodeHelper.redirection(HttpStatusCode.TemporaryRedirect)
|
|
206
|
+
).toBe(true);
|
|
207
|
+
|
|
208
|
+
expect(
|
|
209
|
+
HttpStatusCodeHelper.redirection(HttpStatusCode.PermanentRedirect)
|
|
210
|
+
).toBe(true);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("should return false for non-3xx status codes", () => {
|
|
214
|
+
expect(HttpStatusCodeHelper.redirection(HttpStatusCode.Ok)).toBe(false);
|
|
215
|
+
|
|
216
|
+
expect(HttpStatusCodeHelper.redirection(HttpStatusCode.BadRequest)).toBe(
|
|
217
|
+
false
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
expect(
|
|
221
|
+
HttpStatusCodeHelper.redirection(HttpStatusCode.InternalServerError)
|
|
222
|
+
).toBe(false);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe("clientError", () => {
|
|
227
|
+
it("should return true for 4xx status codes", () => {
|
|
228
|
+
expect(HttpStatusCodeHelper.clientError(HttpStatusCode.BadRequest)).toBe(
|
|
229
|
+
true
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
expect(
|
|
233
|
+
HttpStatusCodeHelper.clientError(HttpStatusCode.Unauthorized)
|
|
234
|
+
).toBe(true);
|
|
235
|
+
|
|
236
|
+
expect(HttpStatusCodeHelper.clientError(HttpStatusCode.Forbidden)).toBe(
|
|
237
|
+
true
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
expect(HttpStatusCodeHelper.clientError(HttpStatusCode.NotFound)).toBe(
|
|
241
|
+
true
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
expect(
|
|
245
|
+
HttpStatusCodeHelper.clientError(HttpStatusCode.TooManyRequests)
|
|
246
|
+
).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("should return false for non-4xx status codes", () => {
|
|
250
|
+
expect(HttpStatusCodeHelper.clientError(HttpStatusCode.Ok)).toBe(false);
|
|
251
|
+
|
|
252
|
+
expect(
|
|
253
|
+
HttpStatusCodeHelper.clientError(HttpStatusCode.MovedPermanently)
|
|
254
|
+
).toBe(false);
|
|
255
|
+
|
|
256
|
+
expect(
|
|
257
|
+
HttpStatusCodeHelper.clientError(HttpStatusCode.InternalServerError)
|
|
258
|
+
).toBe(false);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe("serverError", () => {
|
|
263
|
+
it("should return true for 5xx status codes", () => {
|
|
264
|
+
expect(
|
|
265
|
+
HttpStatusCodeHelper.serverError(HttpStatusCode.InternalServerError)
|
|
266
|
+
).toBe(true);
|
|
267
|
+
|
|
268
|
+
expect(
|
|
269
|
+
HttpStatusCodeHelper.serverError(HttpStatusCode.NotImplemented)
|
|
270
|
+
).toBe(true);
|
|
271
|
+
|
|
272
|
+
expect(HttpStatusCodeHelper.serverError(HttpStatusCode.BadGateway)).toBe(
|
|
273
|
+
true
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
expect(
|
|
277
|
+
HttpStatusCodeHelper.serverError(HttpStatusCode.ServiceUnavailable)
|
|
278
|
+
).toBe(true);
|
|
279
|
+
|
|
280
|
+
expect(
|
|
281
|
+
HttpStatusCodeHelper.serverError(HttpStatusCode.GatewayTimeout)
|
|
282
|
+
).toBe(true);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("should return false for non-5xx status codes", () => {
|
|
286
|
+
expect(HttpStatusCodeHelper.serverError(HttpStatusCode.Ok)).toBe(false);
|
|
287
|
+
|
|
288
|
+
expect(
|
|
289
|
+
HttpStatusCodeHelper.serverError(HttpStatusCode.MovedPermanently)
|
|
290
|
+
).toBe(false);
|
|
291
|
+
|
|
292
|
+
expect(HttpStatusCodeHelper.serverError(HttpStatusCode.BadRequest)).toBe(
|
|
293
|
+
false
|
|
294
|
+
);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
describe("category helpers edge cases", () => {
|
|
299
|
+
it("should handle boundaries correctly", () => {
|
|
300
|
+
// 100 is the first informational code
|
|
301
|
+
expect(HttpStatusCodeHelper.informational(100 as HttpStatusCode)).toBe(
|
|
302
|
+
true
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
expect(HttpStatusCodeHelper.informational(99 as HttpStatusCode)).toBe(
|
|
306
|
+
false
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
// 200 is the first successful code
|
|
310
|
+
expect(HttpStatusCodeHelper.successful(200 as HttpStatusCode)).toBe(true);
|
|
311
|
+
|
|
312
|
+
expect(HttpStatusCodeHelper.successful(199 as HttpStatusCode)).toBe(
|
|
313
|
+
false
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
// 300 is the first redirection code
|
|
317
|
+
expect(HttpStatusCodeHelper.redirection(300 as HttpStatusCode)).toBe(
|
|
318
|
+
true
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
expect(HttpStatusCodeHelper.redirection(299 as HttpStatusCode)).toBe(
|
|
322
|
+
false
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// 400 is the first client error code
|
|
326
|
+
expect(HttpStatusCodeHelper.clientError(400 as HttpStatusCode)).toBe(
|
|
327
|
+
true
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
expect(HttpStatusCodeHelper.clientError(399 as HttpStatusCode)).toBe(
|
|
331
|
+
false
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
// 500 is the first server error code
|
|
335
|
+
expect(HttpStatusCodeHelper.serverError(500 as HttpStatusCode)).toBe(
|
|
336
|
+
true
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
expect(HttpStatusCodeHelper.serverError(499 as HttpStatusCode)).toBe(
|
|
340
|
+
false
|
|
341
|
+
);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|