@applicaster/zapp-react-native-utils 14.0.0-alpha.1054425138 → 14.0.0-alpha.1216545755
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/actionsExecutor/ActionExecutorContext.tsx +3 -3
- package/actionsExecutor/ScreenActions.ts +6 -4
- package/actionsExecutor/StorageActions.ts +1 -1
- package/actionsExecutor/feedDecorator.ts +171 -0
- package/actionsExecutor/screenResolver.ts +11 -0
- package/appUtils/accessibilityManager/index.ts +4 -1
- package/appUtils/contextKeysManager/contextResolver.ts +2 -3
- package/arrayUtils/__tests__/isEmptyArray.test.ts +63 -0
- package/arrayUtils/__tests__/isFilledArray.test.ts +1 -1
- package/arrayUtils/index.ts +7 -2
- package/audioPlayerUtils/__tests__/getArtworkImage.test.ts +144 -0
- package/audioPlayerUtils/__tests__/getBackgroundImage.test.ts +72 -0
- package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +110 -0
- package/audioPlayerUtils/assets/index.ts +2 -0
- package/audioPlayerUtils/index.ts +242 -0
- package/conf/player/__tests__/selectors.test.ts +34 -0
- package/conf/player/selectors.ts +10 -0
- package/configurationUtils/__tests__/configurationUtils.test.js +0 -31
- package/configurationUtils/__tests__/getMediaItems.test.ts +65 -0
- package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +34 -0
- package/configurationUtils/index.ts +63 -34
- package/manifestUtils/_internals/getDefaultConfiguration.js +28 -0
- package/manifestUtils/{_internals.js → _internals/index.js} +2 -25
- package/manifestUtils/createConfig.js +4 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +1231 -200
- package/manifestUtils/progressBar/__tests__/mobileProgressBar.test.js +0 -30
- package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +1 -2
- package/package.json +2 -2
- package/playerUtils/__tests__/configurationUtils.test.ts +1 -65
- package/playerUtils/__tests__/getPlayerActionButtons.test.ts +54 -0
- package/playerUtils/_internals/__tests__/utils.test.ts +71 -0
- package/playerUtils/_internals/index.ts +1 -0
- package/playerUtils/_internals/utils.ts +31 -0
- package/playerUtils/configurationUtils.ts +0 -44
- package/playerUtils/getPlayerActionButtons.ts +17 -0
- package/playerUtils/index.ts +8 -0
- package/playerUtils/useValidatePlayerConfig.tsx +22 -19
- package/reactHooks/cell-click/index.ts +3 -0
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +20 -0
- package/reactHooks/feed/useBatchLoading.ts +2 -2
- package/reactHooks/feed/useFeedLoader.tsx +3 -3
- package/reactHooks/navigation/useRoute.ts +7 -2
- package/reactHooks/navigation/useScreenStateStore.ts +11 -0
- package/storage/ScreenSingleValueProvider.ts +198 -0
- package/storage/ScreenStateMultiSelectProvider.ts +293 -0
- package/storage/StorageMultiSelectProvider.ts +192 -0
- package/storage/StorageSingleSelectProvider.ts +108 -0
- package/utils/index.ts +12 -1
- package/playerUtils/configurationGenerator.ts +0 -2572
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
sessionStorageToggleFlag,
|
|
37
37
|
} from "./StorageActions";
|
|
38
38
|
|
|
39
|
-
import { ScreenSingleValueProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/ScreenSingleValueProvider";
|
|
40
39
|
import { screenSetVariable, screenToggleFlag } from "./ScreenActions";
|
|
41
40
|
|
|
42
41
|
export const { log_error, log_info, log_debug } = createLogger({
|
|
@@ -169,8 +168,7 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
169
168
|
|
|
170
169
|
const entry = context?.entry || {};
|
|
171
170
|
const entryResolver = new EntryResolver(entry);
|
|
172
|
-
const
|
|
173
|
-
const screenData = ScreenSingleValueProvider.getState(route) as any;
|
|
171
|
+
const screenData = context?.screenStateStore.getState().data || {};
|
|
174
172
|
const screenResolver = new EntryResolver(screenData || {});
|
|
175
173
|
|
|
176
174
|
const data =
|
|
@@ -253,9 +251,11 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
253
251
|
context?: Record<string, any>
|
|
254
252
|
): Promise<ActionResult> => {
|
|
255
253
|
const screenRoute = context?.screenRoute;
|
|
254
|
+
const screenStateStore = context?.screenStateStore;
|
|
256
255
|
|
|
257
256
|
await screenToggleFlag(
|
|
258
257
|
screenRoute,
|
|
258
|
+
screenStateStore,
|
|
259
259
|
{ entry: context?.entry, options: action.options },
|
|
260
260
|
action
|
|
261
261
|
);
|
|
@@ -4,8 +4,8 @@ import { log_error, log_info } from "./ActionExecutorContext";
|
|
|
4
4
|
import { ActionResult } from "./ActionExecutor";
|
|
5
5
|
import { get } from "lodash";
|
|
6
6
|
|
|
7
|
-
import { ScreenMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/ScreenStateMultiSelectProvider";
|
|
8
7
|
import { onMaxTagsReached } from "./StorageActions";
|
|
8
|
+
import { ScreenMultiSelectProvider } from "../storage/ScreenStateMultiSelectProvider";
|
|
9
9
|
|
|
10
10
|
export const screenSetVariable = (
|
|
11
11
|
_screenRoute: string,
|
|
@@ -15,11 +15,12 @@ export const screenSetVariable = (
|
|
|
15
15
|
|
|
16
16
|
export const screenToggleFlag = async (
|
|
17
17
|
screenRoute: string,
|
|
18
|
+
screenStateStore: ScreenStateStore,
|
|
18
19
|
context: Record<string, any>,
|
|
19
20
|
action: ActionType
|
|
20
21
|
) => {
|
|
21
22
|
if (!context) {
|
|
22
|
-
log_error("handleAction:
|
|
23
|
+
log_error("handleAction: screenToggleFlag action missing context");
|
|
23
24
|
|
|
24
25
|
return ActionResult.Error;
|
|
25
26
|
}
|
|
@@ -28,7 +29,7 @@ export const screenToggleFlag = async (
|
|
|
28
29
|
|
|
29
30
|
if (!entry) {
|
|
30
31
|
log_error(
|
|
31
|
-
"handleAction:
|
|
32
|
+
"handleAction: screenToggleFlag action missing entry. Entry is required to get the tag."
|
|
32
33
|
);
|
|
33
34
|
|
|
34
35
|
return ActionResult.Error;
|
|
@@ -43,7 +44,8 @@ export const screenToggleFlag = async (
|
|
|
43
44
|
if (keyNamespace && tag) {
|
|
44
45
|
const multiSelectProvider = ScreenMultiSelectProvider.getProvider(
|
|
45
46
|
keyNamespace,
|
|
46
|
-
screenRoute
|
|
47
|
+
screenRoute,
|
|
48
|
+
screenStateStore
|
|
47
49
|
);
|
|
48
50
|
|
|
49
51
|
const selectedItems = await multiSelectProvider.getSelectedAsync();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ActionResult } from "./ActionExecutor";
|
|
2
2
|
import { get } from "lodash";
|
|
3
|
-
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-
|
|
3
|
+
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-utils/storage/StorageMultiSelectProvider";
|
|
4
4
|
import { log_error, log_info } from "./ActionExecutorContext";
|
|
5
5
|
import { postEvent } from "../reactHooks/useSubscriberFor";
|
|
6
6
|
import { TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT } from "./consts";
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as R from "ramda";
|
|
2
|
+
import { getNamespaceAndKey } from "../appUtils/contextKeysManager/utils";
|
|
3
|
+
import { createLogger } from "../logger";
|
|
4
|
+
|
|
5
|
+
const { log_error, log_verbose } = createLogger({
|
|
6
|
+
subsystem: "FeedDecorator",
|
|
7
|
+
category: "General",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
function getScope(scope) {
|
|
11
|
+
if (scope === "screen") {
|
|
12
|
+
return scope;
|
|
13
|
+
} else if (!scope || scope === "ctx") {
|
|
14
|
+
return "ctx";
|
|
15
|
+
} else {
|
|
16
|
+
log_verbose(
|
|
17
|
+
`decorateFeed: Unsupported scope "${scope}" provided in preference_editor_options. Defaulting to "ctx".`
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
return "ctx";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function makeMultiSelect(feed: ZappFeed, key, decoratedFeed) {
|
|
25
|
+
const scope = getScope(
|
|
26
|
+
decoratedFeed.extensions?.preference_editor_options?.scope
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const behavior = {
|
|
30
|
+
...feed.extensions?.["behavior"],
|
|
31
|
+
select_mode: "multi",
|
|
32
|
+
current_selection: `@{${scope}/${key}}`,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (!feed.extensions) {
|
|
36
|
+
decoratedFeed.extensions = {
|
|
37
|
+
behavior,
|
|
38
|
+
};
|
|
39
|
+
} else {
|
|
40
|
+
decoratedFeed.extensions.behavior = behavior;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const actionType =
|
|
44
|
+
decoratedFeed.extensions?.preference_editor_options?.scope === "screen"
|
|
45
|
+
? "screenToggleFlag"
|
|
46
|
+
: decoratedFeed.extensions?.preference_editor_options?.scope === "session"
|
|
47
|
+
? "sessionStorageToggleFlag"
|
|
48
|
+
: "localStorageToggleFlag";
|
|
49
|
+
|
|
50
|
+
decoratedFeed.entry?.forEach((entry: ZappEntry) => {
|
|
51
|
+
entry.type.value = "action";
|
|
52
|
+
entry.id = entry.extensions?.tag || entry.id;
|
|
53
|
+
|
|
54
|
+
entry.extensions = {
|
|
55
|
+
...(entry.extensions || {}),
|
|
56
|
+
tap_actions: {
|
|
57
|
+
actions: [
|
|
58
|
+
{
|
|
59
|
+
type: actionType,
|
|
60
|
+
options: {
|
|
61
|
+
key,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return decoratedFeed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function makeSingleSelect(feed: ZappFeed, key, decoratedFeed) {
|
|
73
|
+
const scope = getScope(
|
|
74
|
+
decoratedFeed.extensions?.preference_editor_options?.scope
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const behavior = {
|
|
78
|
+
...feed.extensions?.["behavior"],
|
|
79
|
+
select_mode: "single",
|
|
80
|
+
current_selection: `@{${scope}/${key}}`,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (!feed.extensions) {
|
|
84
|
+
decoratedFeed.extensions = {
|
|
85
|
+
behavior,
|
|
86
|
+
};
|
|
87
|
+
} else {
|
|
88
|
+
decoratedFeed.extensions.behavior = behavior;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const localStorageProducer = (entry: ZappFeed) => {
|
|
92
|
+
entry.id = entry.extensions?.tag || entry.id;
|
|
93
|
+
const { key: keyName, namespace } = getNamespaceAndKey(key);
|
|
94
|
+
|
|
95
|
+
const action =
|
|
96
|
+
decoratedFeed.extensions?.preference_editor_options?.scope === "session"
|
|
97
|
+
? "sessionStorageSet"
|
|
98
|
+
: "localStorageSet";
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
type: action,
|
|
102
|
+
options: {
|
|
103
|
+
content: {
|
|
104
|
+
[namespace]: {
|
|
105
|
+
[keyName]: entry.id,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const screenStateProducer = (entry: ZappFeed) => {
|
|
113
|
+
entry.id = entry.extensions?.tag || entry.id;
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
type: "screenSetVariable",
|
|
117
|
+
options: {
|
|
118
|
+
key: `@{screen/${key}}`,
|
|
119
|
+
value: entry.id,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const producer =
|
|
125
|
+
decoratedFeed.extensions?.preference_editor_options?.scope === "screen"
|
|
126
|
+
? screenStateProducer
|
|
127
|
+
: localStorageProducer;
|
|
128
|
+
|
|
129
|
+
decoratedFeed.entry?.forEach((entry: ZappEntry) => {
|
|
130
|
+
entry.type.value = "action";
|
|
131
|
+
|
|
132
|
+
entry.extensions = {
|
|
133
|
+
...(entry.extensions || {}),
|
|
134
|
+
tap_actions: {
|
|
135
|
+
actions: [producer(entry)],
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return decoratedFeed;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const decorateFeed = (feed: ZappFeed) => {
|
|
144
|
+
if (!(feed.extensions?.["role"] === "preference_editor")) {
|
|
145
|
+
return feed;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const key = feed.extensions?.["preference_editor_options"]?.["key"];
|
|
149
|
+
|
|
150
|
+
if (!key) {
|
|
151
|
+
log_error(
|
|
152
|
+
`decorateFeed: No 'key' provided in feed titled "${feed.title}" with id "${feed.id}" in preference_editor_options. The preference_editor role requires a key for local storage.`
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
throw new Error(
|
|
156
|
+
"decorateFeed: No 'key' provided in feed preference_editor_options"
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const decoratedFeed = R.clone(feed);
|
|
161
|
+
|
|
162
|
+
const isSingleSelect =
|
|
163
|
+
(feed.extensions?.["preference_editor_options"]?.select_mode ||
|
|
164
|
+
feed.extensions?.["behavior"]?.select_mode) === "single";
|
|
165
|
+
|
|
166
|
+
if (isSingleSelect) {
|
|
167
|
+
return makeSingleSelect(feed, key, decoratedFeed);
|
|
168
|
+
} else {
|
|
169
|
+
return makeMultiSelect(feed, key, decoratedFeed);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { ScreenStateResolver } from "../appUtils/contextKeysManager/contextResolver";
|
|
3
|
+
import { useScreenStateStore } from "../reactHooks/navigation/useScreenStateStore";
|
|
4
|
+
|
|
5
|
+
export const useScreenResolvers = () => {
|
|
6
|
+
const screenStateStore = useScreenStateStore();
|
|
7
|
+
|
|
8
|
+
return useMemo(() => {
|
|
9
|
+
return { screen: new ScreenStateResolver(screenStateStore) };
|
|
10
|
+
}, [screenStateStore]);
|
|
11
|
+
};
|
|
@@ -3,6 +3,7 @@ import { accessibilityManagerLogger as logger } from "./logger";
|
|
|
3
3
|
import { TTSManager } from "../platform/platformUtils";
|
|
4
4
|
import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
|
|
5
5
|
import { AccessibilityRole } from "react-native";
|
|
6
|
+
import _ from "lodash";
|
|
6
7
|
|
|
7
8
|
export class AccessibilityManager {
|
|
8
9
|
private static _instance: AccessibilityManager | null = null;
|
|
@@ -135,7 +136,9 @@ export class AccessibilityManager {
|
|
|
135
136
|
});
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
public getButtonAccessibilityProps(
|
|
139
|
+
public getButtonAccessibilityProps(name: string): AccessibilityProps {
|
|
140
|
+
const buttonName = _.toString(name);
|
|
141
|
+
|
|
139
142
|
const buttonConfig = BUTTON_ACCESSIBILITY_KEYS[buttonName];
|
|
140
143
|
|
|
141
144
|
if (!buttonConfig) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ContextKeysManager } from "./index";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { screenStates } from "@applicaster/zapp-react-native-bridge/ZappStorage/ScreenSingleValueProvider";
|
|
4
3
|
|
|
5
4
|
export interface IResolver {
|
|
6
5
|
resolve: (string) => Promise<string | number | object>;
|
|
@@ -26,10 +25,10 @@ export class EntryResolver implements IResolver {
|
|
|
26
25
|
// TODO: Move to proper place
|
|
27
26
|
|
|
28
27
|
export class ScreenStateResolver implements IResolver {
|
|
29
|
-
constructor(private
|
|
28
|
+
constructor(private screenStateStore: ScreenStateStore) {}
|
|
30
29
|
|
|
31
30
|
async resolve(key: string) {
|
|
32
|
-
const screenState =
|
|
31
|
+
const screenState = this.screenStateStore.getState().data;
|
|
33
32
|
|
|
34
33
|
return screenState?.[key];
|
|
35
34
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { isEmptyArray } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isEmptyArray", () => {
|
|
4
|
+
it("non-empty array is not empty", () => {
|
|
5
|
+
const value = [1, 2, 3];
|
|
6
|
+
|
|
7
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("empty array is empty", () => {
|
|
11
|
+
const value = [];
|
|
12
|
+
|
|
13
|
+
expect(isEmptyArray(value)).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("number is not array", () => {
|
|
17
|
+
const value = 123;
|
|
18
|
+
|
|
19
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("string is not array", () => {
|
|
23
|
+
const value = "vfnjdk";
|
|
24
|
+
|
|
25
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("empty string is not array", () => {
|
|
29
|
+
const value = "";
|
|
30
|
+
|
|
31
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("NaN is not array", () => {
|
|
35
|
+
const value = NaN;
|
|
36
|
+
|
|
37
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("object is not array", () => {
|
|
41
|
+
const value = { test: 1 };
|
|
42
|
+
|
|
43
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("empty object is not array", () => {
|
|
47
|
+
const value = {};
|
|
48
|
+
|
|
49
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("undefined is not array", () => {
|
|
53
|
+
const value = undefined;
|
|
54
|
+
|
|
55
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("null is not array", () => {
|
|
59
|
+
const value = null;
|
|
60
|
+
|
|
61
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
package/arrayUtils/index.ts
CHANGED
|
@@ -99,12 +99,17 @@ export const makeListOf = (value: unknown, size: number): number[] => {
|
|
|
99
99
|
|
|
100
100
|
/** Checks if a value is a non-empty array */
|
|
101
101
|
export function isFilledArray(value: unknown): boolean {
|
|
102
|
-
return
|
|
102
|
+
return Array.isArray(value) && value.length > 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Checks if a value is a empty array */
|
|
106
|
+
export function isEmptyArray(value: unknown): boolean {
|
|
107
|
+
return Array.isArray(value) && value.length === 0;
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
// get random item from the list
|
|
106
111
|
export const sample = (xs: unknown[]): unknown => {
|
|
107
|
-
invariant(
|
|
112
|
+
invariant(Array.isArray(xs), `input value is not an array: ${xs}`);
|
|
108
113
|
invariant(isFilledArray(xs), `input array is empty: ${xs}`);
|
|
109
114
|
|
|
110
115
|
const index = Math.floor(Math.random() * xs.length);
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { getArtworkImage } from "..";
|
|
2
|
+
import { DEFAULT_IMAGE } from "../assets";
|
|
3
|
+
|
|
4
|
+
describe("getArtworkImage", () => {
|
|
5
|
+
const entryWithImage = {
|
|
6
|
+
media_group: [
|
|
7
|
+
{
|
|
8
|
+
type: "image",
|
|
9
|
+
media_item: [
|
|
10
|
+
{ key: "artwork_key", src: "image_from_entry" },
|
|
11
|
+
{ key: "other_key", src: "other_image" },
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
extensions: {
|
|
16
|
+
artwork_key: "artwork_key",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const entryWithoutImage = {
|
|
21
|
+
media_group: [
|
|
22
|
+
{
|
|
23
|
+
type: "image",
|
|
24
|
+
media_item: [{ key: "other_key", src: "other_image" }],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
extensions: {
|
|
28
|
+
artwork_key: "artwork_key",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const pluginConfigWithImage = {
|
|
33
|
+
artwork_key: "plugin_artwork_key",
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
it("returns image from entry extensions key", () => {
|
|
37
|
+
const result = getArtworkImage({
|
|
38
|
+
key: "artwork_key",
|
|
39
|
+
entry: entryWithImage,
|
|
40
|
+
plugin_configuration: {},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(result).toBe("image_from_entry");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns image from plugin configuration key if not in entry", () => {
|
|
47
|
+
const entryNoMatch = {
|
|
48
|
+
...entryWithoutImage,
|
|
49
|
+
extensions: { artwork_key: "not_found_key" },
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const pluginConfig = {
|
|
53
|
+
artwork_key: "plugin_artwork_key",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const entryWithPluginImage = {
|
|
57
|
+
...entryNoMatch,
|
|
58
|
+
media_group: [
|
|
59
|
+
{
|
|
60
|
+
type: "image",
|
|
61
|
+
media_item: [{ key: "plugin_artwork_key", src: "image_from_plugin" }],
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const result = getArtworkImage({
|
|
67
|
+
key: "artwork_key",
|
|
68
|
+
entry: entryWithPluginImage,
|
|
69
|
+
plugin_configuration: pluginConfig,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(result).toBe("image_from_plugin");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("returns DEFAULT_IMAGE if neither entry nor plugin configuration has image", () => {
|
|
76
|
+
const entryNoImage = {
|
|
77
|
+
media_group: [
|
|
78
|
+
{
|
|
79
|
+
type: "image",
|
|
80
|
+
media_item: [{ key: "other_key", src: "other_image" }],
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
extensions: { artwork_key: "not_found_key" },
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const pluginConfig = { artwork_key: "not_found_key" };
|
|
87
|
+
|
|
88
|
+
const result = getArtworkImage({
|
|
89
|
+
key: "artwork_key",
|
|
90
|
+
entry: entryNoImage,
|
|
91
|
+
plugin_configuration: pluginConfig,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(result).toBe(DEFAULT_IMAGE);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("handles undefined key gracefully", () => {
|
|
98
|
+
const result = getArtworkImage({
|
|
99
|
+
key: undefined,
|
|
100
|
+
entry: entryWithImage,
|
|
101
|
+
plugin_configuration: pluginConfigWithImage,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(result).toBe(DEFAULT_IMAGE);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("handles missing entry or plugin_configuration gracefully", () => {
|
|
108
|
+
const result = getArtworkImage({
|
|
109
|
+
key: "artwork_key",
|
|
110
|
+
entry: undefined,
|
|
111
|
+
plugin_configuration: undefined,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(result).toBe(DEFAULT_IMAGE);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("handles empty media_group", () => {
|
|
118
|
+
const entryEmptyMedia = {
|
|
119
|
+
media_group: [],
|
|
120
|
+
extensions: { artwork_key: "artwork_key" },
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const result = getArtworkImage({
|
|
124
|
+
key: "artwork_key",
|
|
125
|
+
entry: entryEmptyMedia,
|
|
126
|
+
plugin_configuration: pluginConfigWithImage,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(result).toBe(DEFAULT_IMAGE);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("handles missing extensions/config keys", () => {
|
|
133
|
+
const entryNoExt = { media_group: [], extensions: {} };
|
|
134
|
+
const pluginConfig = {};
|
|
135
|
+
|
|
136
|
+
const result = getArtworkImage({
|
|
137
|
+
key: "artwork_key",
|
|
138
|
+
entry: entryNoExt,
|
|
139
|
+
plugin_configuration: pluginConfig,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
expect(result).toBe(DEFAULT_IMAGE);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { getBackgroundImage } from "..";
|
|
2
|
+
import { DEFAULT_IMAGE } from "../assets";
|
|
3
|
+
|
|
4
|
+
describe("getBackgroundImage", () => {
|
|
5
|
+
const entryBase = {
|
|
6
|
+
media_group: [
|
|
7
|
+
{
|
|
8
|
+
media_item: [
|
|
9
|
+
{ key: "image_key_1", src: "image_src_1" },
|
|
10
|
+
{ key: "image_key_2", src: "image_src_2" },
|
|
11
|
+
],
|
|
12
|
+
type: "image",
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
extensions: {},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const pluginConfigBase = {};
|
|
19
|
+
|
|
20
|
+
it("returns image from entry.extensions.image_key if present", () => {
|
|
21
|
+
const entry = {
|
|
22
|
+
...entryBase,
|
|
23
|
+
extensions: { image_key: "image_key_2" },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const result = getBackgroundImage({
|
|
27
|
+
entry,
|
|
28
|
+
plugin_configuration: pluginConfigBase,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(result).toBe("image_src_2");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("returns audio_player_background_image from entry.extensions if present and no image_key image", () => {
|
|
35
|
+
const entry = {
|
|
36
|
+
...entryBase,
|
|
37
|
+
extensions: { audio_player_background_image: "audio_img_ext" },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const result = getBackgroundImage({
|
|
41
|
+
entry,
|
|
42
|
+
plugin_configuration: pluginConfigBase,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(result).toBe("audio_img_ext");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("returns image from plugin_configuration.audio_player_image_key if present and not found in entry.extensions", () => {
|
|
49
|
+
const entry = { ...entryBase };
|
|
50
|
+
const plugin_configuration = { audio_player_image_key: "image_key_1" };
|
|
51
|
+
const result = getBackgroundImage({ entry, plugin_configuration });
|
|
52
|
+
expect(result).toBe("image_src_1");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("returns audio_player_background_image from plugin_configuration if present and not found in entry/extensions", () => {
|
|
56
|
+
const entry = { ...entryBase };
|
|
57
|
+
|
|
58
|
+
const plugin_configuration = {
|
|
59
|
+
audio_player_background_image: "audio_img_conf",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const result = getBackgroundImage({ entry, plugin_configuration });
|
|
63
|
+
expect(result).toBe("audio_img_conf");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("returns DEFAULT_IMAGE if nothing is found", () => {
|
|
67
|
+
const entry = { media_group: [], extensions: {} };
|
|
68
|
+
const plugin_configuration = {};
|
|
69
|
+
const result = getBackgroundImage({ entry, plugin_configuration });
|
|
70
|
+
expect(result).toBe(DEFAULT_IMAGE);
|
|
71
|
+
});
|
|
72
|
+
});
|