@applicaster/zapp-react-native-ui-components 15.0.0-rc.12 → 15.0.0-rc.121
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/Components/AnimatedInOut/index.tsx +69 -26
- package/Components/BaseFocusable/index.ios.ts +12 -2
- package/Components/Cell/Cell.tsx +14 -3
- package/Components/Cell/CellWithFocusable.tsx +9 -0
- package/Components/Cell/FocusableWrapper.tsx +47 -0
- package/Components/Cell/TvOSCellComponent.tsx +106 -19
- package/Components/Focusable/Focusable.tsx +4 -2
- package/Components/Focusable/FocusableTvOS.tsx +18 -1
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
- package/Components/FocusableGroup/FocusableTvOS.tsx +32 -1
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
- package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
- package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +22 -6
- package/Components/HandlePlayable/HandlePlayable.tsx +33 -94
- package/Components/HandlePlayable/const.ts +3 -0
- package/Components/HandlePlayable/utils.ts +105 -0
- package/Components/HookRenderer/HookRenderer.tsx +40 -10
- package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
- package/Components/Layout/TV/LayoutBackground.tsx +5 -2
- package/Components/Layout/TV/NavBarContainer.tsx +1 -10
- package/Components/Layout/TV/ScreenContainer.tsx +2 -6
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/index.tsx +3 -4
- package/Components/Layout/TV/index.web.tsx +3 -4
- package/Components/LinkHandler/LinkHandler.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
- package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +43 -22
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
- package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +8 -8
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +233 -11
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +19 -15
- package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
- package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
- package/Components/MasterCell/index.tsx +2 -0
- package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
- package/Components/MasterCell/utils/index.ts +61 -31
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
- package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
- package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
- package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
- package/Components/PlayerContainer/PlayerContainer.tsx +43 -64
- package/Components/PlayerImageBackground/index.tsx +3 -22
- package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
- package/Components/PreloaderWrapper/index.tsx +15 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +16 -0
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +9 -3
- package/Components/River/RiverItem.tsx +26 -20
- package/Components/River/TV/River.tsx +31 -14
- package/Components/River/TV/index.tsx +8 -4
- package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
- package/Components/River/TV/utils/index.ts +4 -0
- package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/River/__tests__/componentsMap.test.js +38 -0
- package/Components/Screen/TV/index.web.tsx +4 -2
- package/Components/Screen/__tests__/Screen.test.tsx +66 -42
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
- package/Components/Screen/hooks.ts +75 -6
- package/Components/Screen/index.tsx +9 -4
- package/Components/Screen/navigationHandler.ts +49 -24
- package/Components/Screen/orientationHandler.ts +10 -13
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
- package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
- package/Components/ScreenFeedLoader/index.ts +1 -0
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
- package/Components/ScreenResolver/hooks/index.ts +3 -0
- package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
- package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
- package/Components/ScreenResolver/index.tsx +15 -111
- package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
- package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
- package/Components/ScreenResolver/utils/index.ts +1 -0
- package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
- package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
- package/Components/ScreenResolverFeedProvider/index.ts +1 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +44 -26
- package/Components/Tabs/TV/Tabs.tsx +20 -3
- package/Components/Tabs/TabContent.tsx +7 -4
- package/Components/Transitioner/Scene.tsx +10 -3
- package/Components/Transitioner/index.js +3 -3
- package/Components/VideoLive/LiveImageManager.ts +199 -54
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +118 -171
- package/Components/VideoModal/ModalAnimation/index.ts +2 -13
- package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
- package/Components/VideoModal/PlayerWrapper.tsx +14 -88
- package/Components/VideoModal/VideoModal.tsx +1 -5
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
- package/Components/VideoModal/hooks/useModalSize.ts +10 -5
- package/Components/VideoModal/playerWrapperStyle.ts +70 -0
- package/Components/VideoModal/playerWrapperUtils.ts +91 -0
- package/Components/VideoModal/utils.ts +19 -9
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
- package/Components/Viewport/ViewportAware/index.tsx +16 -7
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappUIComponent/index.tsx +12 -6
- package/Components/index.js +1 -1
- package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
- package/Contexts/ScreenContext/index.tsx +71 -19
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappHookModalContext/index.tsx +37 -61
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Contexts/index.ts +0 -2
- package/Decorators/Analytics/index.tsx +6 -5
- package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
- package/Decorators/ConfigurationWrapper/const.ts +1 -0
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
- package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
- package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
- package/Helpers/DataSourceHelper/index.ts +19 -0
- package/events/index.ts +3 -0
- package/events/scrollEndReached.ts +15 -0
- package/index.d.ts +7 -0
- package/package.json +6 -5
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
- package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
- package/Components/River/TV/withTVEventHandler.tsx +0 -27
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
- package/Helpers/DataSourceHelper/index.js +0 -19
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { getPluginIdentifier } from "..";
|
|
1
|
+
import { getPluginIdentifier, memoizedGetPluginIdentifier } from "..";
|
|
2
2
|
|
|
3
3
|
describe("getPluginIdentifier", () => {
|
|
4
4
|
const prefix = "tv_buttons";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
memoizedGetPluginIdentifier.clear();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("returns the first valid plugin identifier", () => {
|
|
11
|
+
expect.assertions(2);
|
|
12
|
+
|
|
7
13
|
const configuration = {
|
|
8
14
|
tv_buttons_button_1_other: "value",
|
|
9
15
|
tv_buttons_button_1_assign_action:
|
|
@@ -13,13 +19,21 @@ describe("getPluginIdentifier", () => {
|
|
|
13
19
|
};
|
|
14
20
|
|
|
15
21
|
const index = 0;
|
|
16
|
-
|
|
17
22
|
const result = getPluginIdentifier(configuration, prefix, index);
|
|
18
23
|
|
|
24
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
25
|
+
configuration,
|
|
26
|
+
prefix,
|
|
27
|
+
index
|
|
28
|
+
);
|
|
29
|
+
|
|
19
30
|
expect(result).toEqual(configuration.tv_buttons_button_1_assign_action);
|
|
31
|
+
expect(memoizedResult).toEqual(result);
|
|
20
32
|
});
|
|
21
33
|
|
|
22
|
-
it("
|
|
34
|
+
it("returns the second valid plugin identifier", () => {
|
|
35
|
+
expect.assertions(2);
|
|
36
|
+
|
|
23
37
|
const configuration = {
|
|
24
38
|
tv_buttons_button_1_other: "value_1",
|
|
25
39
|
tv_buttons_button_1_assign_action:
|
|
@@ -30,24 +44,216 @@ describe("getPluginIdentifier", () => {
|
|
|
30
44
|
};
|
|
31
45
|
|
|
32
46
|
const index = 1;
|
|
33
|
-
|
|
34
47
|
const result = getPluginIdentifier(configuration, prefix, index);
|
|
35
48
|
|
|
49
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
50
|
+
configuration,
|
|
51
|
+
prefix,
|
|
52
|
+
index
|
|
53
|
+
);
|
|
54
|
+
|
|
36
55
|
expect(result).toEqual(configuration.tv_buttons_button_2_assign_action);
|
|
56
|
+
expect(memoizedResult).toEqual(result);
|
|
37
57
|
});
|
|
38
58
|
|
|
39
|
-
it("
|
|
59
|
+
it("returns undefined when there are no assign_action keys", () => {
|
|
60
|
+
expect.assertions(2);
|
|
61
|
+
|
|
40
62
|
const configuration = {};
|
|
63
|
+
const index = 0;
|
|
64
|
+
|
|
65
|
+
const result = getPluginIdentifier(configuration, prefix, index);
|
|
66
|
+
|
|
67
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
68
|
+
configuration,
|
|
69
|
+
prefix,
|
|
70
|
+
index
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(result).toBeUndefined();
|
|
74
|
+
expect(memoizedResult).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("skips undefined values and returns the correct plugin identifier", () => {
|
|
78
|
+
expect.assertions(2);
|
|
79
|
+
|
|
80
|
+
const configuration = {
|
|
81
|
+
tv_buttons_button_1_assign_action: "tv_buttons_button_1_assign_action",
|
|
82
|
+
tv_buttons_button_2_assign_action: undefined,
|
|
83
|
+
tv_buttons_button_3_assign_action: "tv_buttons_button_3_assign_action",
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const index = 1;
|
|
87
|
+
const result = getPluginIdentifier(configuration, prefix, index);
|
|
88
|
+
|
|
89
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
90
|
+
configuration,
|
|
91
|
+
prefix,
|
|
92
|
+
index
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
expect(result).toEqual(configuration.tv_buttons_button_3_assign_action);
|
|
96
|
+
expect(memoizedResult).toEqual(result);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("handles missing intermediate keys and returns the correct plugin identifier", () => {
|
|
100
|
+
expect.assertions(2);
|
|
101
|
+
|
|
102
|
+
const configuration = {
|
|
103
|
+
tv_buttons_button_1_assign_action: "tv_buttons_button_1_assign_action",
|
|
104
|
+
tv_buttons_button_3_assign_action: "tv_buttons_button_3_assign_action",
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const index = 1;
|
|
108
|
+
const result = getPluginIdentifier(configuration, prefix, index);
|
|
109
|
+
|
|
110
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
111
|
+
configuration,
|
|
112
|
+
prefix,
|
|
113
|
+
index
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(result).toEqual(configuration.tv_buttons_button_3_assign_action);
|
|
117
|
+
expect(memoizedResult).toEqual(result);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("skips empty string values and returns the first non-empty assign_action", () => {
|
|
121
|
+
expect.assertions(2);
|
|
122
|
+
|
|
123
|
+
const configuration = {
|
|
124
|
+
tv_buttons_button_1_assign_action: "",
|
|
125
|
+
tv_buttons_button_2_assign_action: "tv_buttons_button_2_assign_action",
|
|
126
|
+
};
|
|
41
127
|
|
|
42
128
|
const index = 0;
|
|
129
|
+
const result = getPluginIdentifier(configuration, prefix, index);
|
|
130
|
+
|
|
131
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
132
|
+
configuration,
|
|
133
|
+
prefix,
|
|
134
|
+
index
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
expect(result).toEqual(configuration.tv_buttons_button_2_assign_action);
|
|
138
|
+
expect(memoizedResult).toEqual(result);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("returns undefined for negative index", () => {
|
|
142
|
+
expect.assertions(2);
|
|
143
|
+
|
|
144
|
+
const configuration = {
|
|
145
|
+
tv_buttons_button_1_assign_action: "a",
|
|
146
|
+
tv_buttons_button_2_assign_action: "b",
|
|
147
|
+
};
|
|
43
148
|
|
|
149
|
+
const index = -1;
|
|
44
150
|
const result = getPluginIdentifier(configuration, prefix, index);
|
|
45
151
|
|
|
152
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
153
|
+
configuration,
|
|
154
|
+
prefix,
|
|
155
|
+
index
|
|
156
|
+
);
|
|
157
|
+
|
|
46
158
|
expect(result).toBeUndefined();
|
|
159
|
+
expect(memoizedResult).toBeUndefined();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("returns undefined for out-of-bounds index", () => {
|
|
163
|
+
expect.assertions(2);
|
|
164
|
+
|
|
165
|
+
const configuration = {
|
|
166
|
+
tv_buttons_button_1_assign_action: "a",
|
|
167
|
+
tv_buttons_button_2_assign_action: "b",
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const index = 5;
|
|
171
|
+
const result = getPluginIdentifier(configuration, prefix, index);
|
|
172
|
+
|
|
173
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
174
|
+
configuration,
|
|
175
|
+
prefix,
|
|
176
|
+
index
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
expect(result).toBeUndefined();
|
|
180
|
+
expect(memoizedResult).toBeUndefined();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("ignores keys with wrong prefix or format", () => {
|
|
184
|
+
expect.assertions(2);
|
|
185
|
+
|
|
186
|
+
const configuration = {
|
|
187
|
+
tv_buttons_button_1_assign_action: "a",
|
|
188
|
+
tv_buttons_wrongprefix_2_assign_action: "b",
|
|
189
|
+
tv_buttons_button_x_assign_action: "c",
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const index = 1;
|
|
193
|
+
const result = getPluginIdentifier(configuration, prefix, index);
|
|
194
|
+
|
|
195
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
196
|
+
configuration,
|
|
197
|
+
prefix,
|
|
198
|
+
index
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
expect(result).toBeUndefined();
|
|
202
|
+
expect(memoizedResult).toBeUndefined();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("returns undefined if all assign_actions are null or empty", () => {
|
|
206
|
+
expect.assertions(2);
|
|
207
|
+
|
|
208
|
+
const configuration = {
|
|
209
|
+
tv_buttons_button_1_assign_action: null,
|
|
210
|
+
tv_buttons_button_2_assign_action: undefined,
|
|
211
|
+
tv_buttons_button_3_assign_action: "",
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const index = 0;
|
|
215
|
+
const result = getPluginIdentifier(configuration, prefix, index);
|
|
216
|
+
|
|
217
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
218
|
+
configuration,
|
|
219
|
+
prefix,
|
|
220
|
+
index
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
expect(result).toBeUndefined();
|
|
224
|
+
expect(memoizedResult).toBeUndefined();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("handles non-string values correctly", () => {
|
|
228
|
+
expect.assertions(6);
|
|
229
|
+
|
|
230
|
+
const configuration = {
|
|
231
|
+
tv_buttons_button_1_assign_action: 123,
|
|
232
|
+
tv_buttons_button_2_assign_action: true,
|
|
233
|
+
tv_buttons_button_3_assign_action: { nested: "value" },
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
expect(getPluginIdentifier(configuration, prefix, 0)).toEqual(123);
|
|
237
|
+
expect(getPluginIdentifier(configuration, prefix, 1)).toEqual(true);
|
|
238
|
+
|
|
239
|
+
expect(getPluginIdentifier(configuration, prefix, 2)).toEqual({
|
|
240
|
+
nested: "value",
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
expect(memoizedGetPluginIdentifier(configuration, prefix, 0)).toEqual(123);
|
|
244
|
+
expect(memoizedGetPluginIdentifier(configuration, prefix, 1)).toEqual(true);
|
|
245
|
+
|
|
246
|
+
expect(memoizedGetPluginIdentifier(configuration, prefix, 2)).toEqual({
|
|
247
|
+
nested: "value",
|
|
248
|
+
});
|
|
47
249
|
});
|
|
48
250
|
});
|
|
49
251
|
|
|
50
|
-
describe("getPluginIdentifier - when configuration has
|
|
252
|
+
describe("getPluginIdentifier - when configuration has duplicate values", () => {
|
|
253
|
+
beforeAll(() => {
|
|
254
|
+
memoizedGetPluginIdentifier.clear();
|
|
255
|
+
});
|
|
256
|
+
|
|
51
257
|
const prefix = "tv_buttons";
|
|
52
258
|
|
|
53
259
|
const configuration = {
|
|
@@ -55,19 +261,35 @@ describe("getPluginIdentifier - when configuration has same values for different
|
|
|
55
261
|
tv_buttons_button_2_assign_action: "navigation_action",
|
|
56
262
|
};
|
|
57
263
|
|
|
58
|
-
it("
|
|
59
|
-
|
|
264
|
+
it("returns the first plugin identifier when values are identical", () => {
|
|
265
|
+
expect.assertions(2);
|
|
60
266
|
|
|
267
|
+
const index = 0;
|
|
61
268
|
const result = getPluginIdentifier(configuration, prefix, index);
|
|
62
269
|
|
|
270
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
271
|
+
configuration,
|
|
272
|
+
prefix,
|
|
273
|
+
index
|
|
274
|
+
);
|
|
275
|
+
|
|
63
276
|
expect(result).toEqual(configuration.tv_buttons_button_1_assign_action);
|
|
277
|
+
expect(memoizedResult).toEqual(result);
|
|
64
278
|
});
|
|
65
279
|
|
|
66
|
-
it("
|
|
67
|
-
|
|
280
|
+
it("returns the second plugin identifier when values are identical", () => {
|
|
281
|
+
expect.assertions(2);
|
|
68
282
|
|
|
283
|
+
const index = 1;
|
|
69
284
|
const result = getPluginIdentifier(configuration, prefix, index);
|
|
70
285
|
|
|
286
|
+
const memoizedResult = memoizedGetPluginIdentifier(
|
|
287
|
+
configuration,
|
|
288
|
+
prefix,
|
|
289
|
+
index
|
|
290
|
+
);
|
|
291
|
+
|
|
71
292
|
expect(result).toEqual(configuration.tv_buttons_button_2_assign_action);
|
|
293
|
+
expect(memoizedResult).toEqual(result);
|
|
72
294
|
});
|
|
73
295
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
|
+
import memoizee from "memoizee";
|
|
2
3
|
|
|
3
4
|
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
|
-
import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
5
5
|
|
|
6
6
|
export const getButtonsCount = (
|
|
7
7
|
configuration: Record<string, unknown>,
|
|
@@ -21,23 +21,27 @@ export const getPluginIdentifier = (
|
|
|
21
21
|
configuration: Record<string, unknown>,
|
|
22
22
|
prefix: string,
|
|
23
23
|
index: number
|
|
24
|
-
): string => {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
): string | undefined => {
|
|
25
|
+
const re = new RegExp(`${prefix}_button_\\d_assign_action`);
|
|
26
|
+
let count = 0;
|
|
27
|
+
|
|
28
|
+
for (const [key, value] of Object.entries(configuration)) {
|
|
29
|
+
if (
|
|
30
|
+
key.startsWith(`${prefix}_button`) &&
|
|
31
|
+
re.test(key) &&
|
|
32
|
+
value != null &&
|
|
33
|
+
value !== ""
|
|
34
|
+
) {
|
|
35
|
+
if (count === index) return value as string;
|
|
36
|
+
count++;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
})
|
|
38
|
-
);
|
|
40
|
+
return undefined;
|
|
39
41
|
};
|
|
40
42
|
|
|
43
|
+
export const memoizedGetPluginIdentifier = memoizee(getPluginIdentifier);
|
|
44
|
+
|
|
41
45
|
type Label = {
|
|
42
46
|
name: string;
|
|
43
47
|
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
|
+
import { Text, View } from "react-native";
|
|
4
|
+
import { withAsyncRenderHOC } from "../withAsyncRender";
|
|
5
|
+
|
|
6
|
+
describe("withAsyncRenderHOC", () => {
|
|
7
|
+
// Test component that requires onAsyncRender
|
|
8
|
+
const TestComponent = ({
|
|
9
|
+
onAsyncRender,
|
|
10
|
+
text,
|
|
11
|
+
}: {
|
|
12
|
+
onAsyncRender: () => void;
|
|
13
|
+
text?: string;
|
|
14
|
+
}) => {
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
onAsyncRender();
|
|
17
|
+
}, [onAsyncRender]);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<View>
|
|
21
|
+
<Text>{text || "Test"}</Text>
|
|
22
|
+
</View>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
it("should wrap component and provide onAsyncRender callback", () => {
|
|
27
|
+
const WrappedComponent = withAsyncRenderHOC(TestComponent);
|
|
28
|
+
|
|
29
|
+
const wrapper = render(<WrappedComponent text="Hello" />);
|
|
30
|
+
|
|
31
|
+
expect(wrapper.toJSON()).not.toBeNull();
|
|
32
|
+
expect(wrapper.getByText("Hello")).toBeDefined();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should call emitAsyncElementRegistrate on mount", () => {
|
|
36
|
+
const mockRegistrate = jest.fn();
|
|
37
|
+
const WrappedComponent = withAsyncRenderHOC(TestComponent);
|
|
38
|
+
|
|
39
|
+
render(<WrappedComponent emitAsyncElementRegistrate={mockRegistrate} />);
|
|
40
|
+
|
|
41
|
+
expect(mockRegistrate).toHaveBeenCalledTimes(1);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should call emitAsyncElementLayout when onAsyncRender is called", () => {
|
|
45
|
+
const mockLayout = jest.fn();
|
|
46
|
+
|
|
47
|
+
const ComponentWithAsyncCall = ({
|
|
48
|
+
onAsyncRender,
|
|
49
|
+
}: {
|
|
50
|
+
onAsyncRender: () => void;
|
|
51
|
+
}) => {
|
|
52
|
+
return (
|
|
53
|
+
<View onLayout={onAsyncRender}>
|
|
54
|
+
<Text>Async Component</Text>
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const WrappedComponent = withAsyncRenderHOC(ComponentWithAsyncCall);
|
|
60
|
+
|
|
61
|
+
const wrapper = render(
|
|
62
|
+
<WrappedComponent emitAsyncElementLayout={mockLayout} />
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Trigger onLayout
|
|
66
|
+
const view = wrapper.UNSAFE_getByType(View);
|
|
67
|
+
view.props.onLayout();
|
|
68
|
+
|
|
69
|
+
expect(mockLayout).toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should return unsubscribe function from emitAsyncElementRegistrate", () => {
|
|
73
|
+
const mockUnsubscribe = jest.fn();
|
|
74
|
+
const mockRegistrate = jest.fn(() => mockUnsubscribe);
|
|
75
|
+
const WrappedComponent = withAsyncRenderHOC(TestComponent);
|
|
76
|
+
|
|
77
|
+
const { unmount } = render(
|
|
78
|
+
<WrappedComponent emitAsyncElementRegistrate={mockRegistrate} />
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(mockRegistrate).toHaveBeenCalledTimes(1);
|
|
82
|
+
|
|
83
|
+
// Unmount should trigger cleanup
|
|
84
|
+
unmount();
|
|
85
|
+
|
|
86
|
+
expect(mockUnsubscribe).toHaveBeenCalled();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should work without emitAsyncElementRegistrate prop", () => {
|
|
90
|
+
const WrappedComponent = withAsyncRenderHOC(TestComponent);
|
|
91
|
+
|
|
92
|
+
const wrapper = render(<WrappedComponent text="No Registration" />);
|
|
93
|
+
|
|
94
|
+
expect(wrapper.toJSON()).not.toBeNull();
|
|
95
|
+
expect(wrapper.getByText("No Registration")).toBeDefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should work without emitAsyncElementLayout prop", () => {
|
|
99
|
+
const ComponentWithLayout = ({
|
|
100
|
+
onAsyncRender,
|
|
101
|
+
}: {
|
|
102
|
+
onAsyncRender: () => void;
|
|
103
|
+
}) => {
|
|
104
|
+
return (
|
|
105
|
+
<View onLayout={onAsyncRender}>
|
|
106
|
+
<Text>Test Layout</Text>
|
|
107
|
+
</View>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const WrappedComponent = withAsyncRenderHOC(ComponentWithLayout);
|
|
112
|
+
|
|
113
|
+
const wrapper = render(<WrappedComponent />);
|
|
114
|
+
|
|
115
|
+
// Should not throw when calling onLayout without emitAsyncElementLayout
|
|
116
|
+
const view = wrapper.UNSAFE_getByType(View);
|
|
117
|
+
expect(() => view.props.onLayout()).not.toThrow();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should pass through all other props to wrapped component", () => {
|
|
121
|
+
const ComponentWithProps = ({
|
|
122
|
+
customProp,
|
|
123
|
+
anotherProp,
|
|
124
|
+
}: {
|
|
125
|
+
onAsyncRender: () => void;
|
|
126
|
+
customProp: string;
|
|
127
|
+
anotherProp: number;
|
|
128
|
+
}) => {
|
|
129
|
+
return (
|
|
130
|
+
<View>
|
|
131
|
+
<Text>{customProp}</Text>
|
|
132
|
+
<Text>{anotherProp}</Text>
|
|
133
|
+
</View>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const WrappedComponent = withAsyncRenderHOC(ComponentWithProps);
|
|
138
|
+
|
|
139
|
+
const wrapper = render(
|
|
140
|
+
<WrappedComponent customProp="custom value" anotherProp={42} />
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
expect(wrapper.getByText("custom value")).toBeDefined();
|
|
144
|
+
expect(wrapper.getByText("42")).toBeDefined();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should call emitAsyncElementLayout multiple times if onAsyncRender is called multiple times", () => {
|
|
148
|
+
const mockLayout = jest.fn();
|
|
149
|
+
|
|
150
|
+
const ComponentWithMultipleCalls = ({
|
|
151
|
+
onAsyncRender,
|
|
152
|
+
}: {
|
|
153
|
+
onAsyncRender: () => void;
|
|
154
|
+
}) => {
|
|
155
|
+
return (
|
|
156
|
+
<View>
|
|
157
|
+
<View onLayout={onAsyncRender} testID="view1">
|
|
158
|
+
<Text>First</Text>
|
|
159
|
+
</View>
|
|
160
|
+
<View onLayout={onAsyncRender} testID="view2">
|
|
161
|
+
<Text>Second</Text>
|
|
162
|
+
</View>
|
|
163
|
+
</View>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const WrappedComponent = withAsyncRenderHOC(ComponentWithMultipleCalls);
|
|
168
|
+
|
|
169
|
+
const wrapper = render(
|
|
170
|
+
<WrappedComponent emitAsyncElementLayout={mockLayout} />
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// Trigger both onLayout callbacks
|
|
174
|
+
const view1 = wrapper.getByTestId("view1");
|
|
175
|
+
const view2 = wrapper.getByTestId("view2");
|
|
176
|
+
|
|
177
|
+
view1.props.onLayout();
|
|
178
|
+
view2.props.onLayout();
|
|
179
|
+
|
|
180
|
+
expect(mockLayout).toHaveBeenCalledTimes(2);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should handle components that use onAsyncRender in effects", () => {
|
|
184
|
+
const mockLayout = jest.fn();
|
|
185
|
+
|
|
186
|
+
const ComponentWithEffect = ({
|
|
187
|
+
onAsyncRender,
|
|
188
|
+
}: {
|
|
189
|
+
onAsyncRender: () => void;
|
|
190
|
+
}) => {
|
|
191
|
+
React.useEffect(() => {
|
|
192
|
+
// Simulate async operation completing
|
|
193
|
+
const timer = setTimeout(() => {
|
|
194
|
+
onAsyncRender();
|
|
195
|
+
}, 0);
|
|
196
|
+
|
|
197
|
+
return () => clearTimeout(timer);
|
|
198
|
+
}, [onAsyncRender]);
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<View>
|
|
202
|
+
<Text>Effect Component</Text>
|
|
203
|
+
</View>
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const WrappedComponent = withAsyncRenderHOC(ComponentWithEffect);
|
|
208
|
+
|
|
209
|
+
render(<WrappedComponent emitAsyncElementLayout={mockLayout} />);
|
|
210
|
+
|
|
211
|
+
// The effect should have been triggered
|
|
212
|
+
return new Promise((resolve) => {
|
|
213
|
+
setTimeout(() => {
|
|
214
|
+
expect(mockLayout).toHaveBeenCalled();
|
|
215
|
+
resolve(true);
|
|
216
|
+
}, 10);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|
|
@@ -6,12 +6,12 @@ type withAsyncRenderHOCProps = {
|
|
|
6
6
|
emitAsyncElementLayout?: () => void;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
Component: React.ComponentType<
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
export const withAsyncRenderHOC = <P extends { onAsyncRender: () => void }>(
|
|
10
|
+
Component: React.ComponentType<P>
|
|
11
|
+
): React.FC<Omit<P, "onAsyncRender"> & withAsyncRenderHOCProps> => {
|
|
12
|
+
const WithAsyncRender = (
|
|
13
|
+
props: Omit<P, "onAsyncRender"> & withAsyncRenderHOCProps
|
|
14
|
+
) => {
|
|
15
15
|
const { emitAsyncElementRegistrate = noop, emitAsyncElementLayout = noop } =
|
|
16
16
|
props;
|
|
17
17
|
|
|
@@ -27,7 +27,9 @@ export const withAsyncRenderHOC: withAsyncRenderHOCT = (Component) => {
|
|
|
27
27
|
}
|
|
28
28
|
}, [emitAsyncElementLayout]);
|
|
29
29
|
|
|
30
|
-
return
|
|
30
|
+
return (
|
|
31
|
+
<Component {...(props as unknown as P)} onAsyncRender={onAsyncRender} />
|
|
32
|
+
);
|
|
31
33
|
};
|
|
32
34
|
|
|
33
35
|
return WithAsyncRender;
|