@applicaster/zapp-react-native-ui-components 14.0.0-rc.37 → 14.0.0-rc.39
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/River/TV/River.tsx +2 -17
- package/Components/River/TV/index.tsx +3 -1
- package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
- package/Components/River/TV/withRiverDataLoader.tsx +17 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +24 -8
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
- package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
- package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
- package/Decorators/ZappPipesDataConnector/index.tsx +26 -293
- package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +241 -0
- package/Decorators/ZappPipesDataConnector/types.ts +29 -0
- package/package.json +5 -5
|
@@ -4,10 +4,6 @@ import * as React from "react";
|
|
|
4
4
|
import { Text } from "react-native";
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
useFeedLoader,
|
|
9
|
-
useLayoutVersion,
|
|
10
|
-
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
11
7
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
12
8
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
13
9
|
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
@@ -21,6 +17,7 @@ type Props = {
|
|
|
21
17
|
screenId: string;
|
|
22
18
|
screenData: ZappRiver | ZappEntry;
|
|
23
19
|
feedUrl?: string;
|
|
20
|
+
feedData?: PipesDataObject["data"];
|
|
24
21
|
extraProps?: any;
|
|
25
22
|
screenResolverExtraProps?: any;
|
|
26
23
|
componentsMapExtraProps?: any;
|
|
@@ -32,7 +29,7 @@ type Props = {
|
|
|
32
29
|
export const River = (props: Props) => {
|
|
33
30
|
const {
|
|
34
31
|
screenId,
|
|
35
|
-
|
|
32
|
+
feedData,
|
|
36
33
|
extraProps,
|
|
37
34
|
screenResolverExtraProps,
|
|
38
35
|
componentsMapExtraProps,
|
|
@@ -46,7 +43,6 @@ export const River = (props: Props) => {
|
|
|
46
43
|
useSetNavbarState();
|
|
47
44
|
|
|
48
45
|
const rivers = useRivers();
|
|
49
|
-
const isV2 = useLayoutVersion({ isV2: true });
|
|
50
46
|
|
|
51
47
|
const river = React.useMemo(() => rivers?.[screenId], [screenId]);
|
|
52
48
|
|
|
@@ -55,17 +51,6 @@ export const River = (props: Props) => {
|
|
|
55
51
|
[screenId]
|
|
56
52
|
);
|
|
57
53
|
|
|
58
|
-
const connectedScreenUrl = React.useMemo(() => {
|
|
59
|
-
// Avoid using feedUrl or content.src on layouts v2
|
|
60
|
-
if (isV2) return null;
|
|
61
|
-
|
|
62
|
-
return feedUrl || R.path(["content", "src"], screenData);
|
|
63
|
-
}, [feedUrl, screenData]);
|
|
64
|
-
|
|
65
|
-
const { data: feedData } = useFeedLoader({
|
|
66
|
-
feedUrl: connectedScreenUrl,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
54
|
const stringOrEmpty = (value: string | number | undefined): string =>
|
|
70
55
|
R.isNil(value) ? "" : String(value);
|
|
71
56
|
|
|
@@ -2,8 +2,10 @@ import { compose } from "ramda";
|
|
|
2
2
|
import { River as RiverComponent } from "./River";
|
|
3
3
|
import { withTvEventHandler } from "./withTVEventHandler";
|
|
4
4
|
import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
|
|
5
|
+
import { withRiverDataLoader } from "./withRiverDataLoader";
|
|
5
6
|
|
|
6
7
|
export const River = compose(
|
|
7
8
|
withTvEventHandler,
|
|
8
|
-
withComponentsMapOffsetContext
|
|
9
|
+
withComponentsMapOffsetContext,
|
|
10
|
+
withRiverDataLoader
|
|
9
11
|
)(RiverComponent);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { path } from "ramda";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
useFeedLoader,
|
|
6
|
+
useRivers,
|
|
7
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
screenId: string;
|
|
11
|
+
screenData: ZappRiver | ZappEntry;
|
|
12
|
+
feedUrl?: string;
|
|
13
|
+
river?: ZappRiver | ZappEntry;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const withPipesV1DataLoader = (
|
|
17
|
+
WrappedComponent: React.ComponentType<any>
|
|
18
|
+
) => {
|
|
19
|
+
return function WithPipesV1DataLoaderComponent(props: Props) {
|
|
20
|
+
const { screenId, feedUrl } = props;
|
|
21
|
+
|
|
22
|
+
const rivers = useRivers();
|
|
23
|
+
|
|
24
|
+
const river = React.useMemo(() => rivers?.[screenId], [screenId]);
|
|
25
|
+
|
|
26
|
+
const screenData = React.useMemo(
|
|
27
|
+
() => props.screenData || props.river || river,
|
|
28
|
+
[screenId]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const connectedScreenUrl = useMemo(() => {
|
|
32
|
+
// Avoid using feedUrl or content.src on layouts v2
|
|
33
|
+
|
|
34
|
+
return feedUrl || path(["content", "src"], screenData);
|
|
35
|
+
}, [feedUrl, screenData]);
|
|
36
|
+
|
|
37
|
+
const { data: feedData } = useFeedLoader({
|
|
38
|
+
feedUrl: connectedScreenUrl,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return <WrappedComponent {...props} feedData={feedData} />;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useLayoutVersion } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { withPipesV1DataLoader } from "./withPipesV1DataLoader";
|
|
4
|
+
|
|
5
|
+
export const withRiverDataLoader = (
|
|
6
|
+
WrappedComponent: React.ComponentType<any>
|
|
7
|
+
) => {
|
|
8
|
+
return function WithRiverDataLoaderComponent(props) {
|
|
9
|
+
const isV2 = useLayoutVersion({ isV2: true });
|
|
10
|
+
|
|
11
|
+
if (isV2) {
|
|
12
|
+
return <WrappedComponent {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return withPipesV1DataLoader(WrappedComponent)(props);
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -11,6 +11,7 @@ import { isLive } from "@applicaster/zapp-react-native-utils/playerUtils";
|
|
|
11
11
|
|
|
12
12
|
import { PROGRESS_BAR_HEIGHT } from "./utils";
|
|
13
13
|
import { useConfiguration } from "../utils";
|
|
14
|
+
import { useIsTabletLandscape } from "@applicaster/zapp-react-native-utils/reactHooks/device/useMemoizedIsTablet";
|
|
14
15
|
|
|
15
16
|
export enum PlayerAnimationStateEnum {
|
|
16
17
|
minimize = "minimize",
|
|
@@ -102,14 +103,6 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
102
103
|
setStartComponentsAnimation(false);
|
|
103
104
|
}, []);
|
|
104
105
|
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
// Reset player animation state when video modal is closed
|
|
107
|
-
if (!visible) {
|
|
108
|
-
resetPlayerAnimationState();
|
|
109
|
-
yTranslate.current?.setValue(Dimensions.get("window").height);
|
|
110
|
-
}
|
|
111
|
-
}, [visible, resetPlayerAnimationState]);
|
|
112
|
-
|
|
113
106
|
// Animated values
|
|
114
107
|
const lastScrollY = React.useRef(new Animated.Value(0)).current;
|
|
115
108
|
const dragScrollY = React.useRef(new Animated.Value(0)).current;
|
|
@@ -122,6 +115,29 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
122
115
|
const { bottom: bottomSafeArea } = useSafeAreaInsets();
|
|
123
116
|
const bottomTabBarHeight = useGetBottomTabBarHeight();
|
|
124
117
|
const startComponentsAnimationDistance = Math.round((height * 60) / 100);
|
|
118
|
+
const isTabletLandscape = useIsTabletLandscape();
|
|
119
|
+
const windowDimensions = Dimensions.get("window");
|
|
120
|
+
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
// Reset player animation state when video modal is closed
|
|
123
|
+
if (!visible) {
|
|
124
|
+
resetPlayerAnimationState();
|
|
125
|
+
|
|
126
|
+
if (!isTabletLandscape) {
|
|
127
|
+
// restore to portrait ( in portrait mode height is bigger)
|
|
128
|
+
if (windowDimensions.height > windowDimensions.width) {
|
|
129
|
+
yTranslate.current?.setValue(windowDimensions.height);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
yTranslate.current?.setValue(windowDimensions.height);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}, [
|
|
136
|
+
visible,
|
|
137
|
+
resetPlayerAnimationState,
|
|
138
|
+
windowDimensions.height,
|
|
139
|
+
isTabletLandscape,
|
|
140
|
+
]);
|
|
125
141
|
|
|
126
142
|
React.useEffect(() => {
|
|
127
143
|
if (visible && mode === "MAXIMIZED" && height !== safeAreaFrameHeight) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// ResolverSelector.tsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ComponentDataSourceContext, ZappPipesDataProps } from "./types";
|
|
4
|
+
import { StaticFeedResolver } from "./resolvers/StaticFeedResolver";
|
|
5
|
+
import { UrlFeedResolver } from "./resolvers/UrlFeedResolver";
|
|
6
|
+
import { NullFeedResolver } from "./resolvers/NullFeedResolver";
|
|
7
|
+
|
|
8
|
+
type ResolverSelectorProps = ComponentDataSourceContext & {
|
|
9
|
+
children: (dataProps: ZappPipesDataProps) => React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function ResolverSelector(props: ResolverSelectorProps) {
|
|
13
|
+
const { getStaticComponentFeed, component, feedUrl, children } = props;
|
|
14
|
+
|
|
15
|
+
// Determine which resolver to use
|
|
16
|
+
if (getStaticComponentFeed) {
|
|
17
|
+
return <StaticFeedResolver {...props}>{children}</StaticFeedResolver>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (feedUrl || component?.data?.source) {
|
|
21
|
+
return <UrlFeedResolver {...props}>{children}</UrlFeedResolver>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return <NullFeedResolver>{children}</NullFeedResolver>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { NullFeedResolver } from "../resolvers/NullFeedResolver";
|
|
5
|
+
import { ReloadDataFunction } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useFeedLoader";
|
|
6
|
+
|
|
7
|
+
type MockChildrenArgs = {
|
|
8
|
+
zappPipesData?: {
|
|
9
|
+
loading: boolean;
|
|
10
|
+
data?: any;
|
|
11
|
+
error?: Error | null;
|
|
12
|
+
};
|
|
13
|
+
reloadData?: ReloadDataFunction;
|
|
14
|
+
loadNextData?: () => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
describe("NullFeedResolver", () => {
|
|
18
|
+
it("should render children with correct default props", () => {
|
|
19
|
+
const mockChildren = jest.fn((_args: MockChildrenArgs) => (
|
|
20
|
+
<View testID="mock-children" />
|
|
21
|
+
));
|
|
22
|
+
|
|
23
|
+
render(<NullFeedResolver>{mockChildren}</NullFeedResolver>);
|
|
24
|
+
|
|
25
|
+
expect(mockChildren).toHaveBeenCalledWith(
|
|
26
|
+
expect.objectContaining({
|
|
27
|
+
zappPipesData: {
|
|
28
|
+
url: "",
|
|
29
|
+
loading: false,
|
|
30
|
+
data: null,
|
|
31
|
+
error: null,
|
|
32
|
+
},
|
|
33
|
+
reloadData: expect.any(Function),
|
|
34
|
+
loadNextData: undefined,
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should render children component", () => {
|
|
40
|
+
const { getByTestId } = render(
|
|
41
|
+
<NullFeedResolver>{() => <View testID="test-child" />}</NullFeedResolver>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(getByTestId("test-child")).toBeTruthy();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should create a memoized data object that doesn't change on re-renders", () => {
|
|
48
|
+
const mockChildren = jest.fn(() => <View testID="mock-children" />);
|
|
49
|
+
|
|
50
|
+
const { rerender } = render(
|
|
51
|
+
<NullFeedResolver>{mockChildren}</NullFeedResolver>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
expect(mockChildren).toHaveBeenCalled();
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
const firstCallDataProps = mockChildren.mock.calls[0][0];
|
|
57
|
+
|
|
58
|
+
rerender(<NullFeedResolver>{mockChildren}</NullFeedResolver>);
|
|
59
|
+
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
const secondCallDataProps = mockChildren.mock.calls[1][0];
|
|
62
|
+
|
|
63
|
+
expect(firstCallDataProps).toBe(secondCallDataProps);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should have reloadData function that returns null", () => {
|
|
67
|
+
const mockChildren = jest.fn(() => <View testID="mock-children" />);
|
|
68
|
+
|
|
69
|
+
render(<NullFeedResolver>{mockChildren}</NullFeedResolver>);
|
|
70
|
+
|
|
71
|
+
expect(mockChildren).toHaveBeenCalled();
|
|
72
|
+
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
const { reloadData } = mockChildren.mock.calls[0][0];
|
|
75
|
+
|
|
76
|
+
expect(reloadData()).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { ResolverSelector } from "../ResolverSelector";
|
|
5
|
+
import { StaticFeedResolver } from "../resolvers/StaticFeedResolver";
|
|
6
|
+
import { UrlFeedResolver } from "../resolvers/UrlFeedResolver";
|
|
7
|
+
import { NullFeedResolver } from "../resolvers/NullFeedResolver";
|
|
8
|
+
|
|
9
|
+
jest.mock("../resolvers/StaticFeedResolver", () => ({
|
|
10
|
+
StaticFeedResolver: jest.fn(() => null),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock("../resolvers/UrlFeedResolver", () => ({
|
|
14
|
+
UrlFeedResolver: jest.fn(() => null),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
jest.mock("../resolvers/NullFeedResolver", () => ({
|
|
18
|
+
NullFeedResolver: jest.fn(() => null),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
const testPlugin = {
|
|
22
|
+
identifier: "test-plugin",
|
|
23
|
+
name: "test",
|
|
24
|
+
type: "general" as PluginType,
|
|
25
|
+
module: jest.fn(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe("ResolverSelector", () => {
|
|
29
|
+
const mockChildren = jest.fn(() => <View testID="mock-children" />);
|
|
30
|
+
|
|
31
|
+
const mockComponent = {
|
|
32
|
+
id: "test-component",
|
|
33
|
+
type: "vertical_list",
|
|
34
|
+
styles: {},
|
|
35
|
+
} as any;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
jest.clearAllMocks();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should render StaticFeedResolver when getStaticComponentFeed is provided", () => {
|
|
42
|
+
const props = {
|
|
43
|
+
getStaticComponentFeed: jest.fn(),
|
|
44
|
+
component: mockComponent,
|
|
45
|
+
children: mockChildren,
|
|
46
|
+
riverId: "test-river",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
render(<ResolverSelector {...props} />);
|
|
50
|
+
|
|
51
|
+
expect(StaticFeedResolver).toHaveBeenCalledWith(
|
|
52
|
+
expect.objectContaining({
|
|
53
|
+
getStaticComponentFeed: props.getStaticComponentFeed,
|
|
54
|
+
component: mockComponent,
|
|
55
|
+
children: mockChildren,
|
|
56
|
+
}),
|
|
57
|
+
expect.anything()
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(UrlFeedResolver).not.toHaveBeenCalled();
|
|
61
|
+
expect(NullFeedResolver).not.toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should render UrlFeedResolver when feedUrl is provided", () => {
|
|
65
|
+
const props = {
|
|
66
|
+
feedUrl: "https://example.com/feed",
|
|
67
|
+
component: mockComponent,
|
|
68
|
+
children: mockChildren,
|
|
69
|
+
riverId: "test-river",
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
render(<ResolverSelector {...props} />);
|
|
73
|
+
|
|
74
|
+
expect(UrlFeedResolver).toHaveBeenCalledWith(
|
|
75
|
+
expect.objectContaining({
|
|
76
|
+
feedUrl: props.feedUrl,
|
|
77
|
+
component: mockComponent,
|
|
78
|
+
children: mockChildren,
|
|
79
|
+
}),
|
|
80
|
+
expect.anything()
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(StaticFeedResolver).not.toHaveBeenCalled();
|
|
84
|
+
expect(NullFeedResolver).not.toHaveBeenCalled();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should render UrlFeedResolver when component.data.source is provided", () => {
|
|
88
|
+
const componentWithSource = {
|
|
89
|
+
...mockComponent,
|
|
90
|
+
data: {
|
|
91
|
+
source: "data-source",
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const props = {
|
|
96
|
+
component: componentWithSource,
|
|
97
|
+
children: mockChildren,
|
|
98
|
+
riverId: "test-river",
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
render(<ResolverSelector {...props} />);
|
|
102
|
+
|
|
103
|
+
expect(UrlFeedResolver).toHaveBeenCalledWith(
|
|
104
|
+
expect.objectContaining({
|
|
105
|
+
component: componentWithSource,
|
|
106
|
+
children: mockChildren,
|
|
107
|
+
}),
|
|
108
|
+
expect.anything()
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
expect(StaticFeedResolver).not.toHaveBeenCalled();
|
|
112
|
+
expect(NullFeedResolver).not.toHaveBeenCalled();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should render NullFeedResolver when no data source is provided", () => {
|
|
116
|
+
const props = {
|
|
117
|
+
component: mockComponent,
|
|
118
|
+
children: mockChildren,
|
|
119
|
+
riverId: "test-river",
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
render(<ResolverSelector {...props} />);
|
|
123
|
+
|
|
124
|
+
expect(NullFeedResolver).toHaveBeenCalledWith(
|
|
125
|
+
expect.objectContaining({
|
|
126
|
+
children: mockChildren,
|
|
127
|
+
}),
|
|
128
|
+
expect.anything()
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
expect(StaticFeedResolver).not.toHaveBeenCalled();
|
|
132
|
+
expect(UrlFeedResolver).not.toHaveBeenCalled();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should pass all props to StaticFeedResolver", () => {
|
|
136
|
+
const props = {
|
|
137
|
+
getStaticComponentFeed: jest.fn(),
|
|
138
|
+
component: mockComponent,
|
|
139
|
+
children: mockChildren,
|
|
140
|
+
riverId: "test-river",
|
|
141
|
+
isLast: true,
|
|
142
|
+
componentIndex: 1,
|
|
143
|
+
isScreenWrappedInContainer: true,
|
|
144
|
+
entryContext: { entry: "test" },
|
|
145
|
+
screenContext: { screen: "test" },
|
|
146
|
+
searchContext: "search",
|
|
147
|
+
screenData: { data: "test" },
|
|
148
|
+
plugins: [testPlugin],
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
render(<ResolverSelector {...props} />);
|
|
152
|
+
|
|
153
|
+
expect(StaticFeedResolver).toHaveBeenCalledWith(
|
|
154
|
+
expect.objectContaining(props),
|
|
155
|
+
expect.anything()
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should pass all props to UrlFeedResolver", () => {
|
|
160
|
+
const props = {
|
|
161
|
+
feedUrl: "https://example.com/feed",
|
|
162
|
+
component: mockComponent,
|
|
163
|
+
children: mockChildren,
|
|
164
|
+
riverId: "test-river",
|
|
165
|
+
isLast: true,
|
|
166
|
+
componentIndex: 1,
|
|
167
|
+
isScreenWrappedInContainer: true,
|
|
168
|
+
entryContext: { entry: "test" },
|
|
169
|
+
screenContext: { screen: "test" },
|
|
170
|
+
searchContext: "search",
|
|
171
|
+
screenData: { data: "test" },
|
|
172
|
+
plugins: [testPlugin],
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
render(<ResolverSelector {...props} />);
|
|
176
|
+
|
|
177
|
+
expect(UrlFeedResolver).toHaveBeenCalledWith(
|
|
178
|
+
expect.objectContaining(props),
|
|
179
|
+
expect.anything()
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should prioritize StaticFeedResolver over UrlFeedResolver when both conditions are met", () => {
|
|
184
|
+
const componentWithSource = {
|
|
185
|
+
...mockComponent,
|
|
186
|
+
data: {
|
|
187
|
+
source: "data-source",
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const props = {
|
|
192
|
+
getStaticComponentFeed: jest.fn(),
|
|
193
|
+
feedUrl: "https://example.com/feed",
|
|
194
|
+
component: componentWithSource,
|
|
195
|
+
children: mockChildren,
|
|
196
|
+
riverId: "test-river",
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
render(<ResolverSelector {...props} />);
|
|
200
|
+
|
|
201
|
+
expect(StaticFeedResolver).toHaveBeenCalled();
|
|
202
|
+
expect(UrlFeedResolver).not.toHaveBeenCalled();
|
|
203
|
+
expect(NullFeedResolver).not.toHaveBeenCalled();
|
|
204
|
+
});
|
|
205
|
+
});
|