@applicaster/zapp-react-native-utils 15.0.0-alpha.4429053208 → 15.0.0-alpha.4920595583
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/analyticsUtils/analyticsMapper.ts +10 -2
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +1 -1
- package/appUtils/focusManager/index.ios.ts +7 -8
- package/appUtils/focusManagerAux/utils/index.ios.ts +5 -5
- package/appUtils/focusManagerAux/utils/utils.ios.ts +10 -21
- package/navigationUtils/index.ts +15 -5
- package/package.json +4 -4
- 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/configuration/__tests__/index.test.tsx +1 -1
- package/reactHooks/connection/__tests__/index.test.js +1 -1
- 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 +1 -1
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
- package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +1 -1
- package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
- package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
- package/reactHooks/layout/__tests__/index.test.tsx +1 -1
- package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
- package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
- package/reactHooks/navigation/index.ts +15 -4
- package/reactHooks/navigation/useRoute.ts +3 -1
- 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/screen/__tests__/useCurrentScreenData.test.tsx +1 -1
- 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 +1 -1
- package/reactHooks/utils/__tests__/index.test.js +1 -1
- package/screenState/__tests__/index.test.ts +1 -1
- package/stringUtils/index.ts +1 -1
|
@@ -63,10 +63,14 @@ class StateHolder {
|
|
|
63
63
|
return value as string;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
public get analyticsCustomPropertiesConsumed(): boolean {
|
|
67
|
+
return this._cap !== undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
66
70
|
private acp(prefix: string, suffix: string): string | null {
|
|
67
71
|
if (this._cap === undefined) {
|
|
68
|
-
this._cap = this.
|
|
69
|
-
? JSON.parse(this.
|
|
72
|
+
this._cap = this.event.params[prefix]
|
|
73
|
+
? JSON.parse(this.event.params[prefix])
|
|
70
74
|
: null;
|
|
71
75
|
|
|
72
76
|
delete this.pluckedParams[prefix];
|
|
@@ -254,6 +258,10 @@ export class Mapper {
|
|
|
254
258
|
|
|
255
259
|
let params = resultParams.size ? Object.fromEntries(resultParams) : {};
|
|
256
260
|
|
|
261
|
+
if (state.analyticsCustomPropertiesConsumed) {
|
|
262
|
+
delete params[sourceType.analyticsCustomProperties];
|
|
263
|
+
}
|
|
264
|
+
|
|
257
265
|
// deal with the remaining params
|
|
258
266
|
if (!isEmptyOrNil(state.pluckedParams)) {
|
|
259
267
|
if (rule.strategy) {
|
|
@@ -73,7 +73,7 @@ exports[`focusManagerIOS should be defined 1`] = `
|
|
|
73
73
|
"isFocusOn": [Function],
|
|
74
74
|
"isFocusOnContent": [Function],
|
|
75
75
|
"isFocusOnMenu": [Function],
|
|
76
|
-
"
|
|
76
|
+
"isFocusOnTabsScreenContent": [Function],
|
|
77
77
|
"isGroupItemFocused": [Function],
|
|
78
78
|
"moveFocus": [Function],
|
|
79
79
|
"on": [Function],
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
isChildOf as isChildOfUtils,
|
|
7
7
|
isPartOfMenu,
|
|
8
8
|
isPartOfContent,
|
|
9
|
-
|
|
9
|
+
isPartOfTabsScreenContent,
|
|
10
10
|
} from "../focusManagerAux/utils/index.ios";
|
|
11
11
|
|
|
12
12
|
import { Tree } from "./treeDataStructure/Tree";
|
|
@@ -17,7 +17,6 @@ import { findChild } from "./utils";
|
|
|
17
17
|
import {
|
|
18
18
|
emitRegistered,
|
|
19
19
|
emitUnregistered,
|
|
20
|
-
emitWillFocused,
|
|
21
20
|
} from "../focusManagerAux/utils/utils.ios";
|
|
22
21
|
|
|
23
22
|
const { FocusableManagerModule } = NativeModules;
|
|
@@ -292,8 +291,6 @@ export const focusManager = (function () {
|
|
|
292
291
|
blur(direction);
|
|
293
292
|
currentFocus = id;
|
|
294
293
|
|
|
295
|
-
emitWillFocused(id);
|
|
296
|
-
|
|
297
294
|
// Extract groupFocusedChanged with a default value of false
|
|
298
295
|
let groupFocusedChanged = false;
|
|
299
296
|
|
|
@@ -439,12 +436,14 @@ export const focusManager = (function () {
|
|
|
439
436
|
return isPartOfContent(focusableTree, currentFocusable?.props?.id);
|
|
440
437
|
}
|
|
441
438
|
|
|
442
|
-
function
|
|
439
|
+
function isFocusOnTabsScreenContent(
|
|
440
|
+
screenPickerContentContainerId: string
|
|
441
|
+
): boolean {
|
|
443
442
|
const currentFocusable = getCurrentFocus();
|
|
444
443
|
|
|
445
|
-
return
|
|
444
|
+
return isPartOfTabsScreenContent(
|
|
446
445
|
focusableTree,
|
|
447
|
-
|
|
446
|
+
screenPickerContentContainerId,
|
|
448
447
|
currentFocusable?.props?.id
|
|
449
448
|
);
|
|
450
449
|
}
|
|
@@ -477,7 +476,7 @@ export const focusManager = (function () {
|
|
|
477
476
|
isFocusOn,
|
|
478
477
|
isFocusOnMenu,
|
|
479
478
|
isFocusOnContent,
|
|
480
|
-
|
|
479
|
+
isFocusOnTabsScreenContent,
|
|
481
480
|
isChildOf,
|
|
482
481
|
};
|
|
483
482
|
})();
|
|
@@ -9,9 +9,9 @@ const isNavBar = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
|
|
|
9
9
|
const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
|
|
10
10
|
const isRoot = (node) => node?.id === "root";
|
|
11
11
|
|
|
12
|
-
export const
|
|
12
|
+
export const isPartOfTabsScreenContent = (
|
|
13
13
|
focusableTree,
|
|
14
|
-
|
|
14
|
+
screenPickerContentContainerId,
|
|
15
15
|
id
|
|
16
16
|
) => {
|
|
17
17
|
const node = focusableTree.findInTree(id);
|
|
@@ -32,13 +32,13 @@ export const isPartOfTabsScreen = (
|
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (node?.id ===
|
|
35
|
+
if (node?.id === screenPickerContentContainerId) {
|
|
36
36
|
return true;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
return
|
|
39
|
+
return isPartOfTabsScreenContent(
|
|
40
40
|
focusableTree,
|
|
41
|
-
|
|
41
|
+
screenPickerContentContainerId,
|
|
42
42
|
node.parent?.id
|
|
43
43
|
);
|
|
44
44
|
};
|
|
@@ -178,34 +178,27 @@ export const emitNativeRegistered = ({
|
|
|
178
178
|
}
|
|
179
179
|
};
|
|
180
180
|
|
|
181
|
-
//
|
|
182
|
-
const willFocusedSubject$ = new Subject<FocusableID>();
|
|
183
|
-
const didFocusedSubject$ = new Subject<FocusableID>();
|
|
181
|
+
// /////
|
|
184
182
|
|
|
185
|
-
|
|
183
|
+
const focusedSubject$ = new Subject<FocusableID>();
|
|
186
184
|
|
|
187
|
-
|
|
185
|
+
const focused$ = focusedSubject$.asObservable();
|
|
188
186
|
|
|
189
|
-
export const
|
|
190
|
-
|
|
187
|
+
export const emitFocused = (id: FocusableID): void => {
|
|
188
|
+
focusedSubject$.next(id);
|
|
191
189
|
};
|
|
192
190
|
|
|
193
|
-
export const
|
|
194
|
-
didFocusedSubject$.next(id);
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
export const topMenuItemDidFocused$ = didFocused$.pipe(
|
|
191
|
+
export const topMenuItemFocused$ = focused$.pipe(
|
|
198
192
|
filter((id) => id && isPartOfMenu(focusManager.focusableTree, id))
|
|
199
193
|
);
|
|
200
194
|
|
|
201
|
-
export const
|
|
195
|
+
export const contentFocused$ = focused$.pipe(
|
|
202
196
|
filter((id) => {
|
|
203
197
|
const isContent = isPartOfContent(focusManager.focusableTree, id);
|
|
204
198
|
|
|
205
199
|
return id && isContent;
|
|
206
200
|
})
|
|
207
201
|
);
|
|
208
|
-
// Focusable has been focused
|
|
209
202
|
|
|
210
203
|
const createFocusableRegistry = () => {
|
|
211
204
|
const subject$ = new ReplaySubject<FocusableID | undefined>(1);
|
|
@@ -226,17 +219,13 @@ const createFocusableRegistry = () => {
|
|
|
226
219
|
/// HOME_TOP_MENU_ITEM
|
|
227
220
|
export const HomeTopMenuItemRegistry = createFocusableRegistry();
|
|
228
221
|
|
|
229
|
-
export const
|
|
222
|
+
export const homeTopMenuItemFocused$ = topMenuItemFocused$.pipe(
|
|
230
223
|
withLatestFrom(HomeTopMenuItemRegistry.observable$),
|
|
231
224
|
filter(([id, homeId]) => id === homeId)
|
|
232
225
|
);
|
|
233
226
|
|
|
234
|
-
///
|
|
235
|
-
export const
|
|
236
|
-
|
|
237
|
-
export const TabsScreenScreenSelectorContainerRegistry =
|
|
238
|
-
createFocusableRegistry();
|
|
239
|
-
/// TABS SCREEN
|
|
227
|
+
/// SCREEN_PICKER
|
|
228
|
+
export const ScreenPickerContentContainerRegistry = createFocusableRegistry();
|
|
240
229
|
|
|
241
230
|
/// SEARCH_INPUT
|
|
242
231
|
export const SearchInputRegistry = createFocusableRegistry();
|
package/navigationUtils/index.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { layoutV2TypeMatcher } from "./layoutV2TypeMatcher";
|
|
|
5
5
|
import { HOOKS_EVENTS } from "../appUtils/HooksManager/constants";
|
|
6
6
|
import { HooksManager } from "../appUtils/HooksManager";
|
|
7
7
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
import { zappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
|
|
9
10
|
import { logger } from "@applicaster/zapp-react-native-utils/logger";
|
|
10
11
|
import {
|
|
11
12
|
isGeneralPlugin,
|
|
@@ -15,6 +16,8 @@ import {
|
|
|
15
16
|
} from "./itemTypeMatchers";
|
|
16
17
|
import { RootState } from "@applicaster/zapp-react-native-redux/store";
|
|
17
18
|
|
|
19
|
+
import { pick } from "@applicaster/zapp-react-native-utils/utils";
|
|
20
|
+
|
|
18
21
|
type PathAttribute = {
|
|
19
22
|
screenType: string;
|
|
20
23
|
screenId: string;
|
|
@@ -403,15 +406,22 @@ export const mapContentTypesToRivers = (
|
|
|
403
406
|
};
|
|
404
407
|
|
|
405
408
|
export const runZappHooksForEntry = async (
|
|
406
|
-
entry: HookPluginProps["payload"]
|
|
407
|
-
|
|
409
|
+
entry: HookPluginProps["payload"]
|
|
410
|
+
): Promise<{ success: boolean; payload: ZappEntry }> => {
|
|
411
|
+
const {
|
|
408
412
|
setState,
|
|
409
413
|
resetState,
|
|
410
414
|
setIsHooksExecutionInProgress,
|
|
411
415
|
setIsPresentingFullScreen,
|
|
412
416
|
setIsRunningInBackground,
|
|
413
|
-
}
|
|
414
|
-
|
|
417
|
+
} = pick(zappHookModalStore.getState(), [
|
|
418
|
+
"setState",
|
|
419
|
+
"resetState",
|
|
420
|
+
"setIsHooksExecutionInProgress",
|
|
421
|
+
"setIsPresentingFullScreen",
|
|
422
|
+
"setIsRunningInBackground",
|
|
423
|
+
]);
|
|
424
|
+
|
|
415
425
|
resetState?.();
|
|
416
426
|
|
|
417
427
|
let success;
|
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.4920595583",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,13 +27,13 @@
|
|
|
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.4920595583",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
34
|
+
"handlebars": "4.7.8",
|
|
34
35
|
"memoizee": "0.4.15",
|
|
35
|
-
"prop-types": "^15.0.0"
|
|
36
|
-
"react-native-handlebars": "^5.0.0-alpha.1"
|
|
36
|
+
"prop-types": "^15.0.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@applicaster/zapp-pipes-v2-client": "*",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { renderHook } from "@testing-library/react-
|
|
4
|
-
import { act, waitFor } from "@testing-library/react-native";
|
|
3
|
+
import { renderHook, act, waitFor } from "@testing-library/react-native";
|
|
5
4
|
import { Provider } from "react-redux";
|
|
6
5
|
import configureStore from "redux-mock-store";
|
|
7
6
|
import { useTrackedView } from "../useTrackedView";
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { cleanup, renderHook } from "@testing-library/react-
|
|
2
|
+
import { cleanup, renderHook, waitFor } from "@testing-library/react-native";
|
|
3
3
|
import { CellTapContext } from "@applicaster/zapp-react-native-ui-components/Contexts/CellTapContext";
|
|
4
4
|
import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
|
|
5
5
|
|
|
6
|
-
import { waitFor } from "@testing-library/react-native";
|
|
7
|
-
|
|
8
6
|
const mockNavigator = {
|
|
9
7
|
getPathname: () => "pathnameMock",
|
|
10
8
|
push: jest.fn(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable react/prop-types */
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { renderHook, cleanup } from "@testing-library/react-
|
|
3
|
+
import { renderHook, cleanup } from "@testing-library/react-native";
|
|
4
4
|
import { ConfigurationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ConfigutaionContext";
|
|
5
5
|
import { useConfiguration } from "@applicaster/zapp-react-native-utils/reactHooks/configuration";
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { renderHook, cleanup } from "@testing-library/react-
|
|
2
|
+
import { renderHook, cleanup } from "@testing-library/react-native";
|
|
3
3
|
import { NetworkStatusContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NetworkStatusContext";
|
|
4
4
|
|
|
5
5
|
const MockNetInfo = {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react-
|
|
1
|
+
import { renderHook, waitFor } from "@testing-library/react-native";
|
|
2
2
|
import { allFeedsIsReady, useBatchLoading } from "../useBatchLoading";
|
|
3
3
|
import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
4
4
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
5
|
-
import { waitFor } from "@testing-library/react-native";
|
|
6
5
|
|
|
7
6
|
jest.mock("../../navigation");
|
|
8
7
|
|
|
@@ -16,7 +15,11 @@ jest.mock(
|
|
|
16
15
|
})
|
|
17
16
|
);
|
|
18
17
|
|
|
19
|
-
const
|
|
18
|
+
const getWrapper =
|
|
19
|
+
(store) =>
|
|
20
|
+
({ children }) => (
|
|
21
|
+
<WrappedWithProviders store={store}>{children}</WrappedWithProviders>
|
|
22
|
+
);
|
|
20
23
|
|
|
21
24
|
describe("useBatchLoading", () => {
|
|
22
25
|
const data = [
|
|
@@ -63,8 +66,7 @@ describe("useBatchLoading", () => {
|
|
|
63
66
|
const riverId = "123";
|
|
64
67
|
|
|
65
68
|
renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
|
|
66
|
-
wrapper,
|
|
67
|
-
initialProps: { store },
|
|
69
|
+
wrapper: getWrapper(store),
|
|
68
70
|
});
|
|
69
71
|
|
|
70
72
|
const actions = (appStore.getStore() as any).getActions();
|
|
@@ -84,7 +86,7 @@ describe("useBatchLoading", () => {
|
|
|
84
86
|
});
|
|
85
87
|
});
|
|
86
88
|
|
|
87
|
-
it("loadPipesData start loading new feed when 1 feed is done loading and 1 is in loading state", () => {
|
|
89
|
+
it("loadPipesData start loading new feed when 1 feed is done loading and 1 is in loading state", async () => {
|
|
88
90
|
const store = {
|
|
89
91
|
zappPipes: {
|
|
90
92
|
url1: {
|
|
@@ -110,13 +112,14 @@ describe("useBatchLoading", () => {
|
|
|
110
112
|
const riverId = "123";
|
|
111
113
|
|
|
112
114
|
renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
|
|
113
|
-
wrapper,
|
|
114
|
-
initialProps: { store },
|
|
115
|
+
wrapper: getWrapper(store),
|
|
115
116
|
});
|
|
116
117
|
|
|
117
118
|
const actions = (appStore.getStore() as any).getActions();
|
|
118
119
|
|
|
119
|
-
|
|
120
|
+
await waitFor(() => {
|
|
121
|
+
expect(actions).toHaveLength(1);
|
|
122
|
+
});
|
|
120
123
|
|
|
121
124
|
expect(actions[0]).toMatchObject({
|
|
122
125
|
type: "ZAPP_PIPES_REQUEST_START",
|
|
@@ -124,7 +127,7 @@ describe("useBatchLoading", () => {
|
|
|
124
127
|
});
|
|
125
128
|
});
|
|
126
129
|
|
|
127
|
-
it("loadPipesData has been called when no data cached", () => {
|
|
130
|
+
it("loadPipesData has been called when no data cached", async () => {
|
|
128
131
|
const store = {
|
|
129
132
|
zappPipes: {},
|
|
130
133
|
test: "true",
|
|
@@ -134,16 +137,17 @@ describe("useBatchLoading", () => {
|
|
|
134
137
|
const riverId = "123";
|
|
135
138
|
|
|
136
139
|
renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
|
|
137
|
-
wrapper,
|
|
138
|
-
initialProps: { store },
|
|
140
|
+
wrapper: getWrapper(store),
|
|
139
141
|
});
|
|
140
142
|
|
|
141
143
|
const actions = (appStore.getStore() as any).getActions();
|
|
142
144
|
|
|
143
|
-
|
|
145
|
+
await waitFor(() => {
|
|
146
|
+
expect(actions).toHaveLength(3);
|
|
147
|
+
});
|
|
144
148
|
});
|
|
145
149
|
|
|
146
|
-
it("initial batch ready when all initial items loaded", () => {
|
|
150
|
+
it("initial batch ready when all initial items loaded", async () => {
|
|
147
151
|
const store = {
|
|
148
152
|
zappPipes: {
|
|
149
153
|
url1: {
|
|
@@ -169,13 +173,15 @@ describe("useBatchLoading", () => {
|
|
|
169
173
|
|
|
170
174
|
const { result } = renderHook(
|
|
171
175
|
() => useBatchLoading(data, { initialBatchSize, riverId }),
|
|
172
|
-
{ wrapper
|
|
176
|
+
{ wrapper: getWrapper(store) }
|
|
173
177
|
);
|
|
174
178
|
|
|
175
|
-
|
|
179
|
+
await waitFor(() => {
|
|
180
|
+
expect(result.current).toBe(true);
|
|
181
|
+
});
|
|
176
182
|
});
|
|
177
183
|
|
|
178
|
-
it("gallery-qb: loadPipesData should be called only once for first component in the gallery", () => {
|
|
184
|
+
it("gallery-qb: loadPipesData should be called only once for first component in the gallery", async () => {
|
|
179
185
|
const store = {
|
|
180
186
|
zappPipes: {},
|
|
181
187
|
test: "true",
|
|
@@ -198,16 +204,17 @@ describe("useBatchLoading", () => {
|
|
|
198
204
|
];
|
|
199
205
|
|
|
200
206
|
renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
|
|
201
|
-
wrapper,
|
|
202
|
-
initialProps: { store },
|
|
207
|
+
wrapper: getWrapper(store),
|
|
203
208
|
});
|
|
204
209
|
|
|
205
210
|
const actions = (appStore.getStore() as any).getActions();
|
|
206
211
|
|
|
207
|
-
|
|
212
|
+
await waitFor(() => {
|
|
213
|
+
expect(actions).toHaveLength(1);
|
|
214
|
+
});
|
|
208
215
|
});
|
|
209
216
|
|
|
210
|
-
it("gallery-qb: initial batch ready when all initial items loaded", () => {
|
|
217
|
+
it("gallery-qb: initial batch ready when all initial items loaded", async () => {
|
|
211
218
|
const store = {
|
|
212
219
|
zappPipes: {
|
|
213
220
|
url1: {
|
|
@@ -233,10 +240,12 @@ describe("useBatchLoading", () => {
|
|
|
233
240
|
|
|
234
241
|
const { result } = renderHook(
|
|
235
242
|
() => useBatchLoading(data, { initialBatchSize, riverId }),
|
|
236
|
-
{ wrapper
|
|
243
|
+
{ wrapper: getWrapper(store) }
|
|
237
244
|
);
|
|
238
245
|
|
|
239
|
-
|
|
246
|
+
await waitFor(() => {
|
|
247
|
+
expect(result.current).toBe(true);
|
|
248
|
+
});
|
|
240
249
|
});
|
|
241
250
|
});
|
|
242
251
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react-
|
|
1
|
+
import { renderHook, waitFor } from "@testing-library/react-native";
|
|
2
2
|
import { encodeParams } from "@applicaster/zapp-pipes-v2-client/src/utils";
|
|
3
3
|
|
|
4
4
|
const appData = {
|
|
@@ -42,26 +42,26 @@ describe("useBuildPipesUrl", () => {
|
|
|
42
42
|
build: jest.fn(() => Promise.resolve(buildResult)),
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
const { result
|
|
45
|
+
const { result } = renderHook(() =>
|
|
46
46
|
useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
|
|
47
47
|
);
|
|
48
48
|
|
|
49
49
|
expect(result.current.url).toBe("http://foo.com/show/show-1");
|
|
50
50
|
expect(result.current.requestParams).toBeNull();
|
|
51
51
|
|
|
52
|
-
await
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
);
|
|
52
|
+
await waitFor(() => {
|
|
53
|
+
expect(result.current.requestParams).toEqual(
|
|
54
|
+
expect.objectContaining({
|
|
55
|
+
params: {
|
|
56
|
+
version: appData.version_name,
|
|
57
|
+
ctx: encodeParams({ platform: appData.platform }),
|
|
58
|
+
},
|
|
59
|
+
headers: {
|
|
60
|
+
SDK: appData.sdk_version,
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it("returns empty object if url is not in endpoints", async () => {
|
|
@@ -81,15 +81,15 @@ describe("useBuildPipesUrl", () => {
|
|
|
81
81
|
build: jest.fn(() => Promise.resolve(buildResult)),
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
const { result
|
|
84
|
+
const { result } = renderHook(() =>
|
|
85
85
|
useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
|
|
86
86
|
);
|
|
87
87
|
|
|
88
88
|
expect(result.current.url).toBe("http://foobar.com/show-1");
|
|
89
89
|
expect(result.current.requestParams).toBeNull();
|
|
90
90
|
|
|
91
|
-
await
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
await waitFor(() => {
|
|
92
|
+
expect(result.current.requestParams).toEqual({});
|
|
93
|
+
});
|
|
94
94
|
});
|
|
95
95
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react-
|
|
1
|
+
import { renderHook } from "@testing-library/react-native";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import * as zappPipesModule from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
4
4
|
import * as reactReduxModules from "react-redux";
|
|
@@ -50,6 +50,16 @@ const mockZappPipesData = {
|
|
|
50
50
|
url: "test://testfakeurl",
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
+
const createWrapper = (
|
|
54
|
+
getStore: () => any
|
|
55
|
+
): React.FC<{ children: React.ReactNode }> => {
|
|
56
|
+
const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
57
|
+
<WrappedWithProviders store={getStore()}>{children}</WrappedWithProviders>
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return Wrapper;
|
|
61
|
+
};
|
|
62
|
+
|
|
53
63
|
describe("useFeedLoader", () => {
|
|
54
64
|
describe("with cached feed url", () => {
|
|
55
65
|
const store = {
|
|
@@ -57,11 +67,7 @@ describe("useFeedLoader", () => {
|
|
|
57
67
|
zappPipes: { "test://testfakeurl": mockZappPipesData },
|
|
58
68
|
};
|
|
59
69
|
|
|
60
|
-
const wrapper
|
|
61
|
-
<WrappedWithProviders store={props.store || store}>
|
|
62
|
-
{children}
|
|
63
|
-
</WrappedWithProviders>
|
|
64
|
-
);
|
|
70
|
+
const wrapper = createWrapper(() => store);
|
|
65
71
|
|
|
66
72
|
it("returns cached feed", () => {
|
|
67
73
|
const { result } = renderHook(
|
|
@@ -109,12 +115,6 @@ describe("useFeedLoader", () => {
|
|
|
109
115
|
describe("without cached feeds", () => {
|
|
110
116
|
const feedUrl = "test://testfakeurl2";
|
|
111
117
|
|
|
112
|
-
const wrapper: React.FC<any> = ({ children, ...props }) => (
|
|
113
|
-
<WrappedWithProviders store={props.store}>
|
|
114
|
-
{children}
|
|
115
|
-
</WrappedWithProviders>
|
|
116
|
-
);
|
|
117
|
-
|
|
118
118
|
it("It loads data for new url and returns it", () => {
|
|
119
119
|
const useDispatchSpy = jest
|
|
120
120
|
.spyOn(reactReduxModules, "useDispatch")
|
|
@@ -129,9 +129,12 @@ describe("useFeedLoader", () => {
|
|
|
129
129
|
zappPipes: { "test://testfakeurl": "foobar" },
|
|
130
130
|
};
|
|
131
131
|
|
|
132
|
+
let store = initialStore;
|
|
133
|
+
const wrapper = createWrapper(() => store);
|
|
134
|
+
|
|
132
135
|
const { result, rerender } = renderHook(
|
|
133
|
-
() => useFeedLoader({ feedUrl:
|
|
134
|
-
{ wrapper, initialProps: {
|
|
136
|
+
({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
|
|
137
|
+
{ wrapper, initialProps: { feedUrl } }
|
|
135
138
|
);
|
|
136
139
|
|
|
137
140
|
expect(result.current.data).toBeNull();
|
|
@@ -150,7 +153,8 @@ describe("useFeedLoader", () => {
|
|
|
150
153
|
zappPipes: { "test://testfakeurl2": mockZappPipesData },
|
|
151
154
|
};
|
|
152
155
|
|
|
153
|
-
|
|
156
|
+
store = store2;
|
|
157
|
+
rerender({ feedUrl });
|
|
154
158
|
|
|
155
159
|
expect(R.omit(["reloadData", "loadNext"], result.current)).toEqual(
|
|
156
160
|
mockZappPipesData
|
|
@@ -174,9 +178,12 @@ describe("useFeedLoader", () => {
|
|
|
174
178
|
zappPipes: { "test://testfakeurl": "foobar" },
|
|
175
179
|
};
|
|
176
180
|
|
|
181
|
+
let store = initialStore;
|
|
182
|
+
const wrapper = createWrapper(() => store);
|
|
183
|
+
|
|
177
184
|
const { result, rerender } = renderHook(
|
|
178
|
-
() => useFeedLoader({ feedUrl:
|
|
179
|
-
{ wrapper, initialProps: {
|
|
185
|
+
({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
|
|
186
|
+
{ wrapper, initialProps: { feedUrl } }
|
|
180
187
|
);
|
|
181
188
|
|
|
182
189
|
expect(result.current.data).toBeNull();
|
|
@@ -198,7 +205,8 @@ describe("useFeedLoader", () => {
|
|
|
198
205
|
zappPipes: { "test://testfakeurl2": mockZappPipesData },
|
|
199
206
|
};
|
|
200
207
|
|
|
201
|
-
|
|
208
|
+
store = store2;
|
|
209
|
+
rerender({ feedUrl });
|
|
202
210
|
|
|
203
211
|
loadPipesDataSpy.mockRestore();
|
|
204
212
|
useDispatchSpy.mockRestore();
|
|
@@ -209,12 +217,6 @@ describe("useFeedLoader", () => {
|
|
|
209
217
|
const feedUrl = "test://testfakeurl";
|
|
210
218
|
const feedUrlWithNext = "test://withnexttestfakeurl";
|
|
211
219
|
|
|
212
|
-
const wrapper: React.FC<any> = ({ children, ...props }) => (
|
|
213
|
-
<WrappedWithProviders store={props.store || {}}>
|
|
214
|
-
{children}
|
|
215
|
-
</WrappedWithProviders>
|
|
216
|
-
);
|
|
217
|
-
|
|
218
220
|
describe("reloadData", () => {
|
|
219
221
|
it("Tries to reload data in the redux store", () => {
|
|
220
222
|
const loadPipesDataSpy = jest
|
|
@@ -230,10 +232,17 @@ describe("useFeedLoader", () => {
|
|
|
230
232
|
zappPipes: { [feedUrl]: "foobar" },
|
|
231
233
|
};
|
|
232
234
|
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
const store = initialStore;
|
|
236
|
+
|
|
237
|
+
const wrapper = createWrapper(() => store);
|
|
238
|
+
|
|
239
|
+
const { result } = renderHook(
|
|
240
|
+
({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
|
|
241
|
+
{
|
|
242
|
+
wrapper,
|
|
243
|
+
initialProps: { feedUrl },
|
|
244
|
+
}
|
|
245
|
+
);
|
|
237
246
|
|
|
238
247
|
const { reloadData } = result.current;
|
|
239
248
|
|
|
@@ -279,11 +288,14 @@ describe("useFeedLoader", () => {
|
|
|
279
288
|
zappPipes: { [feedUrlWithNext]: { data: { next: nextUrl } } },
|
|
280
289
|
};
|
|
281
290
|
|
|
291
|
+
const store = initialStore;
|
|
292
|
+
const wrapper = createWrapper(() => store);
|
|
293
|
+
|
|
282
294
|
const { result } = renderHook(
|
|
283
|
-
() => useFeedLoader({ feedUrl:
|
|
295
|
+
({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
|
|
284
296
|
{
|
|
285
297
|
wrapper,
|
|
286
|
-
initialProps: {
|
|
298
|
+
initialProps: { feedUrl: feedUrlWithNext },
|
|
287
299
|
}
|
|
288
300
|
);
|
|
289
301
|
|
|
@@ -214,7 +214,7 @@ describe("getSearchContext", () => {
|
|
|
214
214
|
});
|
|
215
215
|
|
|
216
216
|
describe("useGetUrlInflater", () => {
|
|
217
|
-
const { renderHook } = require("@testing-library/react-
|
|
217
|
+
const { renderHook } = require("@testing-library/react-native");
|
|
218
218
|
|
|
219
219
|
it("returns original url when mapping is not provided", () => {
|
|
220
220
|
const { result } = renderHook(() => useGetUrlInflater(), {
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { reactHooksLogger } from "../../logger";
|
|
2
|
-
import {
|
|
2
|
+
import { useZappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
|
|
3
3
|
|
|
4
4
|
const logger = reactHooksLogger.addSubsystem("useHookModalScreenData");
|
|
5
5
|
|
|
6
6
|
type VariousScreenData = LegacyNavigationScreenData | ZappRiver | ZappEntry;
|
|
7
7
|
|
|
8
|
-
export const useHookModalScreenData = (
|
|
9
|
-
|
|
8
|
+
export const useHookModalScreenData = (
|
|
9
|
+
skipSubscription: boolean
|
|
10
|
+
): VariousScreenData | undefined => {
|
|
11
|
+
const hookModalState = useZappHookModalStore((state) =>
|
|
12
|
+
skipSubscription ? undefined : state.state
|
|
13
|
+
);
|
|
10
14
|
|
|
11
|
-
if (!hookModalState
|
|
15
|
+
if (!hookModalState?.screenData) {
|
|
12
16
|
return;
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
try {
|
|
16
|
-
const screenData = hookModalState.
|
|
17
|
-
const hookPlugin = hookModalState.
|
|
20
|
+
const screenData = hookModalState.screenData?.payload;
|
|
21
|
+
const hookPlugin = hookModalState.screenData.hookPlugin;
|
|
18
22
|
|
|
19
23
|
if (hookPlugin?.screen_id) {
|
|
20
24
|
return {
|
|
@@ -23,7 +27,7 @@ export const useHookModalScreenData = (): VariousScreenData | undefined => {
|
|
|
23
27
|
};
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
return hookModalState.
|
|
30
|
+
return hookModalState.screenData?.payload;
|
|
27
31
|
} catch (error) {
|
|
28
32
|
logger.error({
|
|
29
33
|
message: "Hook modal screen data creation failed",
|
|
@@ -34,6 +38,6 @@ export const useHookModalScreenData = (): VariousScreenData | undefined => {
|
|
|
34
38
|
jsOnly: true,
|
|
35
39
|
});
|
|
36
40
|
|
|
37
|
-
return hookModalState.
|
|
41
|
+
return hookModalState.screenData?.payload;
|
|
38
42
|
}
|
|
39
43
|
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
|
|
3
|
-
import { renderHook } from "@testing-library/react-
|
|
3
|
+
import { renderHook } from "@testing-library/react-native";
|
|
4
4
|
import { isNavBarVisible, useRoute } from "../";
|
|
5
5
|
import { Provider } from "react-redux";
|
|
6
6
|
import configureMockStore from "redux-mock-store";
|
|
7
7
|
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
|
|
8
|
-
import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
9
8
|
import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
|
|
10
9
|
import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
|
|
11
10
|
|
|
@@ -83,10 +82,44 @@ const hookModalContextState = {
|
|
|
83
82
|
},
|
|
84
83
|
setState: jest.fn(),
|
|
85
84
|
resetState: jest.fn(),
|
|
85
|
+
hookPresentationMode: null,
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
const hooksModalPathname = `${ROUTE_TYPES.HOOKS_MODAL}/${hookModalContextState.state.screenData.payload.id}`;
|
|
89
89
|
const videoModalPathname = `${ROUTE_TYPES.VIDEO_MODAL}/${videoModalNavigator.videoModalState.item.id}`;
|
|
90
|
+
|
|
91
|
+
jest.mock(
|
|
92
|
+
"@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext",
|
|
93
|
+
() => {
|
|
94
|
+
const mockState = {
|
|
95
|
+
isRunningInBackground: false,
|
|
96
|
+
setIsRunningInBackground: jest.fn(),
|
|
97
|
+
setIsPresentingFullScreen: jest.fn(),
|
|
98
|
+
isPresentationFullScreen: true,
|
|
99
|
+
isHooksExecutionInProgress: true,
|
|
100
|
+
setIsHooksExecutionInProgress: jest.fn(),
|
|
101
|
+
state: {
|
|
102
|
+
path: "/home",
|
|
103
|
+
screenData: { payload: { id: "hookExecutedInModal" } },
|
|
104
|
+
},
|
|
105
|
+
setState: jest.fn(),
|
|
106
|
+
resetState: jest.fn(),
|
|
107
|
+
hookPresentationMode: null,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const mockHook = jest.fn((selector) => {
|
|
111
|
+
return selector ? selector(mockState) : mockState;
|
|
112
|
+
}) as jest.MockedFunction<any> & { getState: () => typeof mockState };
|
|
113
|
+
|
|
114
|
+
mockHook.getState = jest.fn(() => mockState);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
useZappHookModalStore: mockHook,
|
|
118
|
+
zappHookModalStore: mockHook,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
|
|
90
123
|
const mockStore = configureMockStore();
|
|
91
124
|
|
|
92
125
|
const store = mockStore({
|
|
@@ -125,13 +158,11 @@ const videoModalWrapper = ({ children }) => (
|
|
|
125
158
|
|
|
126
159
|
const hookModalWrapper = ({ children }) => (
|
|
127
160
|
<Provider store={store}>
|
|
128
|
-
<
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
</NavigationContext.Provider>
|
|
134
|
-
</ZappHookModalContext.ReactContext.Provider>
|
|
161
|
+
<NavigationContext.Provider value={hookModalNavigator}>
|
|
162
|
+
<PathnameContext.Provider value={hooksModalPathname}>
|
|
163
|
+
{children}
|
|
164
|
+
</PathnameContext.Provider>
|
|
165
|
+
</NavigationContext.Provider>
|
|
135
166
|
</Provider>
|
|
136
167
|
);
|
|
137
168
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
2
2
|
import { BackHandler } from "react-native";
|
|
3
|
+
import { shallow } from "zustand/shallow";
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
useContentTypes,
|
|
@@ -8,13 +9,13 @@ import {
|
|
|
8
9
|
import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
|
|
9
10
|
|
|
10
11
|
import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
|
|
11
|
-
import {
|
|
12
|
-
import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
|
|
12
|
+
import { useZappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
|
|
13
13
|
import { HOOKS_EVENTS } from "../../appUtils/HooksManager/constants";
|
|
14
14
|
import { getRiverFromRoute, getTargetRoute } from "../../navigationUtils";
|
|
15
15
|
import { useConnectionInfo } from "../connection";
|
|
16
16
|
|
|
17
17
|
import { isTV, isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
18
|
+
import { pick } from "@applicaster/zapp-react-native-utils/utils";
|
|
18
19
|
import { useNavbarState } from "../screen";
|
|
19
20
|
import { useRivers } from "../state";
|
|
20
21
|
import { useLayoutVersion } from "../layout";
|
|
@@ -168,7 +169,17 @@ export const useZappHooksForEntry = (
|
|
|
168
169
|
setIsHooksExecutionInProgress,
|
|
169
170
|
setIsPresentingFullScreen,
|
|
170
171
|
setIsRunningInBackground,
|
|
171
|
-
}
|
|
172
|
+
} = useZappHookModalStore(
|
|
173
|
+
(state) =>
|
|
174
|
+
pick(state, [
|
|
175
|
+
"setState",
|
|
176
|
+
"resetState",
|
|
177
|
+
"setIsHooksExecutionInProgress",
|
|
178
|
+
"setIsPresentingFullScreen",
|
|
179
|
+
"setIsRunningInBackground",
|
|
180
|
+
]),
|
|
181
|
+
shallow
|
|
182
|
+
);
|
|
172
183
|
|
|
173
184
|
const plugins = usePlugins();
|
|
174
185
|
const rivers = useRivers();
|
|
@@ -54,7 +54,9 @@ export const useRoute = (
|
|
|
54
54
|
|
|
55
55
|
const modalScreenData = modalState.screen;
|
|
56
56
|
|
|
57
|
-
const hookModalScreenData = useHookModalScreenData(
|
|
57
|
+
const hookModalScreenData = useHookModalScreenData(
|
|
58
|
+
!isHookModalPathname(pathname)
|
|
59
|
+
);
|
|
58
60
|
|
|
59
61
|
const videoModalScreenData =
|
|
60
62
|
navigator?.videoModalState?.item &&
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { act, renderHook } from "@testing-library/react-
|
|
1
|
+
import { act, renderHook } from "@testing-library/react-native";
|
|
2
2
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
3
3
|
|
|
4
4
|
import { ON_HOLD_INTERVAL, SEEK_TYPE, SKIP_TIME_BASE } from "../const";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import { cleanup, renderHook } from "@testing-library/react-
|
|
3
|
+
import { cleanup, renderHook } from "@testing-library/react-native";
|
|
4
4
|
import configureStore from "redux-mock-store";
|
|
5
5
|
import { Provider } from "react-redux";
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Provider } from "react-redux";
|
|
3
|
-
import { renderHook } from "@testing-library/react-
|
|
3
|
+
import { renderHook } from "@testing-library/react-native";
|
|
4
4
|
import configureStore from "redux-mock-store";
|
|
5
5
|
import { thunk } from "redux-thunk";
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Provider } from "react-redux";
|
|
3
|
-
import { renderHook } from "@testing-library/react-
|
|
3
|
+
import { renderHook } from "@testing-library/react-native";
|
|
4
4
|
import configureStore from "redux-mock-store";
|
|
5
5
|
import { thunk } from "redux-thunk";
|
|
6
6
|
|
package/stringUtils/index.ts
CHANGED