@capillarytech/creatives-library 8.0.130 → 8.0.131
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/containers/App/constants.js +1 -0
- package/containers/Login/index.js +1 -2
- package/package.json +1 -1
- package/services/api.js +5 -0
- package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
- package/tests/integration/TemplateCreation/api-response.js +5 -0
- package/tests/integration/TemplateCreation/msw-handler.js +42 -63
- package/utils/common.js +7 -0
- package/utils/commonUtils.js +2 -6
- package/utils/createMobilePushPayload.js +322 -0
- package/utils/tests/createMobilePushPayload.test.js +1054 -0
- package/v2Components/CapDeviceContent/index.js +1 -1
- package/v2Components/CapImageUpload/index.js +57 -44
- package/v2Components/CapInAppCTA/index.js +1 -0
- package/v2Components/CapMpushCTA/constants.js +25 -0
- package/v2Components/CapMpushCTA/index.js +403 -0
- package/v2Components/CapMpushCTA/index.scss +95 -0
- package/v2Components/CapMpushCTA/messages.js +101 -0
- package/v2Components/CapTagList/index.js +178 -121
- package/v2Components/CapVideoUpload/constants.js +3 -0
- package/v2Components/CapVideoUpload/index.js +182 -115
- package/v2Components/CapVideoUpload/messages.js +16 -0
- package/v2Components/Carousel/index.js +15 -13
- package/v2Components/ErrorInfoNote/style.scss +1 -0
- package/v2Components/MobilePushPreviewV2/index.js +57 -12
- package/v2Components/TemplatePreview/_templatePreview.scss +218 -74
- package/v2Components/TemplatePreview/assets/images/Android_With_date_and_time.svg +29 -0
- package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
- package/v2Components/TemplatePreview/assets/images/iOS_With_date_and_time.svg +26 -0
- package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
- package/v2Components/TemplatePreview/index.js +234 -107
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +10 -10
- package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -62
- package/v2Containers/CreativesContainer/index.js +193 -136
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -22
- package/v2Containers/InApp/constants.js +1 -0
- package/v2Containers/InApp/index.js +13 -13
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +4748 -4658
- package/v2Containers/Login/index.js +1 -2
- package/v2Containers/MobilePush/Create/index.js +1 -0
- package/v2Containers/MobilePush/commonMethods.js +7 -14
- package/v2Containers/MobilePush/tests/commonMethods.test.js +401 -0
- package/v2Containers/MobilePushNew/actions.js +116 -0
- package/v2Containers/MobilePushNew/components/CtaButtons.js +183 -0
- package/v2Containers/MobilePushNew/components/MediaUploaders.js +835 -0
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +346 -0
- package/v2Containers/MobilePushNew/components/index.js +5 -0
- package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +565 -0
- package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +3180 -0
- package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +654 -0
- package/v2Containers/MobilePushNew/constants.js +116 -0
- package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1462 -0
- package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1459 -0
- package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +366 -0
- package/v2Containers/MobilePushNew/hooks/useUpload.js +740 -0
- package/v2Containers/MobilePushNew/index.js +2158 -0
- package/v2Containers/MobilePushNew/index.scss +308 -0
- package/v2Containers/MobilePushNew/messages.js +272 -0
- package/v2Containers/MobilePushNew/reducer.js +160 -0
- package/v2Containers/MobilePushNew/sagas.js +193 -0
- package/v2Containers/MobilePushNew/selectors.js +55 -0
- package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
- package/v2Containers/MobilePushNew/tests/sagas.test.js +864 -0
- package/v2Containers/MobilePushNew/tests/selectors.test.js +665 -0
- package/v2Containers/MobilePushNew/tests/utils.test.js +421 -0
- package/v2Containers/MobilePushNew/utils.js +84 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +1176 -976
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +684 -424
- package/v2Containers/TagList/index.js +56 -10
- package/v2Containers/Templates/_templates.scss +100 -1
- package/v2Containers/Templates/index.js +170 -31
- package/v2Containers/Templates/messages.js +8 -0
- package/v2Containers/Templates/sagas.js +1 -0
- package/v2Containers/Whatsapp/constants.js +1 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +3992 -3677
- package/assets/loading_img.gif +0 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, fireEvent } from "@testing-library/react";
|
|
3
|
+
import "@testing-library/jest-dom";
|
|
4
|
+
import { IntlProvider } from "react-intl";
|
|
5
|
+
import PlatformContentFields from "../PlatformContentFields";
|
|
6
|
+
import {
|
|
7
|
+
ANDROID, IOS, DEEP_LINK, EXTERNAL_LINK,
|
|
8
|
+
} from "../../constants";
|
|
9
|
+
|
|
10
|
+
// Simple mock components
|
|
11
|
+
jest.mock("@capillarytech/cap-ui-library/CapRow", () => ({ children }) => <div>{children}</div>);
|
|
12
|
+
jest.mock("@capillarytech/cap-ui-library/CapColumn", () => ({ children }) => <div>{children}</div>);
|
|
13
|
+
jest.mock("@capillarytech/cap-ui-library/CapInput", () => ({
|
|
14
|
+
value, onChange, errorMessage, error, ...props
|
|
15
|
+
}) => (
|
|
16
|
+
<div>
|
|
17
|
+
<input value={value || ""} onChange={onChange} error={error} {...props} />
|
|
18
|
+
{(errorMessage || error) && <div data-testid="error-message">{errorMessage || error}</div>}
|
|
19
|
+
</div>
|
|
20
|
+
));
|
|
21
|
+
jest.mock("@capillarytech/cap-ui-library/CapHeading", () => ({ children }) => <div>{children}</div>);
|
|
22
|
+
jest.mock("@capillarytech/cap-ui-library/CapError", () => ({ children }) => <div data-testid="cap-error">{children}</div>);
|
|
23
|
+
jest.mock("@capillarytech/cap-ui-library/CapDivider", () => () => <div data-testid="divider" />);
|
|
24
|
+
jest.mock("@capillarytech/cap-ui-library/CapSelect", () => ({
|
|
25
|
+
CapCustomSelect: ({ value, onChange, options }) => (
|
|
26
|
+
<select value={value} onChange={(e) => onChange && onChange(e.target.value)}>
|
|
27
|
+
{options?.map((option) => (
|
|
28
|
+
<option key={option.value} value={option.value}>
|
|
29
|
+
{option.label}
|
|
30
|
+
</option>
|
|
31
|
+
))}
|
|
32
|
+
</select>
|
|
33
|
+
),
|
|
34
|
+
}));
|
|
35
|
+
jest.mock("@capillarytech/cap-ui-library/CapCheckbox", () => ({ checked, onChange, children }) => (
|
|
36
|
+
<div>
|
|
37
|
+
<input type="checkbox" checked={checked} onChange={onChange} data-testid="action-checkbox" />
|
|
38
|
+
<span>{children}</span>
|
|
39
|
+
</div>
|
|
40
|
+
));
|
|
41
|
+
jest.mock("@capillarytech/cap-ui-library/CapLabel", () => ({ children }) => <label>{children}</label>);
|
|
42
|
+
jest.mock("@capillarytech/cap-ui-library/CapInfoNote", () => ({ message }) => <div data-testid="info-note">{message}</div>);
|
|
43
|
+
|
|
44
|
+
// Mock child components
|
|
45
|
+
jest.mock("../../../TagList", () => () => <div data-testid="tag-list">TagList</div>);
|
|
46
|
+
jest.mock("../MediaUploaders", () => () => <div data-testid="media-uploaders">MediaUploaders</div>);
|
|
47
|
+
jest.mock("../CtaButtons", () => () => <div data-testid="cta-buttons">CtaButtons</div>);
|
|
48
|
+
|
|
49
|
+
// Mock messages
|
|
50
|
+
jest.mock("../../messages", () => ({
|
|
51
|
+
sameContentNote: { id: "sameContentNote", defaultMessage: "Same content note" },
|
|
52
|
+
title: { id: "title", defaultMessage: "Title" },
|
|
53
|
+
titlePlaceholder: { id: "titlePlaceholder", defaultMessage: "Enter title" },
|
|
54
|
+
message: { id: "message", defaultMessage: "Message" },
|
|
55
|
+
messagePlaceholder: { id: "messagePlaceholder", defaultMessage: "Enter message" },
|
|
56
|
+
mediaType: { id: "mediaType", defaultMessage: "Media Type" },
|
|
57
|
+
buttonsAndLinks: { id: "buttonsAndLinks", defaultMessage: "Buttons and Links" },
|
|
58
|
+
optionalText: { id: "optionalText", defaultMessage: "Optional" },
|
|
59
|
+
actionOnClickBody: { id: "actionOnClickBody", defaultMessage: "Action on click" },
|
|
60
|
+
actionDescription: { id: "actionDescription", defaultMessage: "Action description" },
|
|
61
|
+
linkType: { id: "linkType", defaultMessage: "Link Type" },
|
|
62
|
+
selectDeepLink: { id: "selectDeepLink", defaultMessage: "Select deep link" },
|
|
63
|
+
deepLink: { id: "deepLink", defaultMessage: "Deep Link" },
|
|
64
|
+
externalLink: { id: "externalLink", defaultMessage: "External Link" },
|
|
65
|
+
enterExternalLink: { id: "enterExternalLink", defaultMessage: "Enter external link" },
|
|
66
|
+
deepLinkKeys: { id: "deepLinkKeys", defaultMessage: "Deep Link Keys" },
|
|
67
|
+
deepLinkKeysPlaceholder: { id: "deepLinkKeysPlaceholder", defaultMessage: "Enter {key}" },
|
|
68
|
+
deepLinkKeysRequired: { id: "deepLinkKeysRequired", defaultMessage: "Deep link keys are required" },
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
// Mock constants
|
|
72
|
+
jest.mock("../../constants", () => ({
|
|
73
|
+
ANDROID: "android",
|
|
74
|
+
IOS: "ios",
|
|
75
|
+
CAROUSEL: "CAROUSEL",
|
|
76
|
+
MEDIA_TYPES_OPTIONS: [
|
|
77
|
+
{ value: "IMAGE", label: "Image" },
|
|
78
|
+
{ value: "VIDEO", label: "Video" },
|
|
79
|
+
{ value: "CAROUSEL", label: "Carousel" },
|
|
80
|
+
],
|
|
81
|
+
LINK_TYPE_OPTIONS: [
|
|
82
|
+
{ value: "DEEP_LINK", label: "Deep Link" },
|
|
83
|
+
{ value: "EXTERNAL_LINK", label: "External Link" },
|
|
84
|
+
],
|
|
85
|
+
DEEP_LINK: "DEEP_LINK",
|
|
86
|
+
EXTERNAL_LINK: "EXTERNAL_LINK",
|
|
87
|
+
}));
|
|
88
|
+
|
|
89
|
+
describe("PlatformContentFields", () => {
|
|
90
|
+
const defaultProps = {
|
|
91
|
+
deviceType: ANDROID,
|
|
92
|
+
content: {
|
|
93
|
+
title: "Test Title",
|
|
94
|
+
message: "Test Message",
|
|
95
|
+
mediaType: "IMAGE",
|
|
96
|
+
actionOnClick: false,
|
|
97
|
+
linkType: DEEP_LINK,
|
|
98
|
+
},
|
|
99
|
+
errors: {
|
|
100
|
+
title: "",
|
|
101
|
+
message: "",
|
|
102
|
+
externalLink: "",
|
|
103
|
+
},
|
|
104
|
+
handlers: {
|
|
105
|
+
handleTitleChange: jest.fn(),
|
|
106
|
+
handleMessageChange: jest.fn(),
|
|
107
|
+
handleMediaTypeChange: jest.fn(),
|
|
108
|
+
handleActionOnClickChange: jest.fn(),
|
|
109
|
+
handleLinkTypeChange: jest.fn(),
|
|
110
|
+
handleDeepLinkChange: jest.fn(),
|
|
111
|
+
handleExternalLinkChange: jest.fn(),
|
|
112
|
+
onTagSelect: jest.fn(),
|
|
113
|
+
handleOnTagsContextChange: jest.fn(),
|
|
114
|
+
},
|
|
115
|
+
tagListProps: {
|
|
116
|
+
tags: ["tag1", "tag2"],
|
|
117
|
+
},
|
|
118
|
+
mediaUploaderProps: {
|
|
119
|
+
uploadProps: "test",
|
|
120
|
+
},
|
|
121
|
+
ctaButtonProps: {
|
|
122
|
+
buttons: [],
|
|
123
|
+
},
|
|
124
|
+
linkProps: {
|
|
125
|
+
deepLink: [
|
|
126
|
+
{ value: "link1", label: "Link 1" },
|
|
127
|
+
{ value: "link2", label: "Link 2" },
|
|
128
|
+
],
|
|
129
|
+
deepLinkValue: "link1",
|
|
130
|
+
externalLinkValue: "https://example.com",
|
|
131
|
+
},
|
|
132
|
+
sameContent: false,
|
|
133
|
+
formatMessage: jest.fn((msg) => msg.defaultMessage),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const renderComponent = (props = {}) => render(
|
|
137
|
+
<IntlProvider locale="en">
|
|
138
|
+
<PlatformContentFields {...defaultProps} {...props} />
|
|
139
|
+
</IntlProvider>
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
beforeEach(() => {
|
|
143
|
+
jest.clearAllMocks();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("Basic Rendering", () => {
|
|
147
|
+
it("should render without crashing", () => {
|
|
148
|
+
const { container } = renderComponent();
|
|
149
|
+
expect(container).toBeInTheDocument();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("should render title input with correct value", () => {
|
|
153
|
+
const { container } = renderComponent();
|
|
154
|
+
const titleInput = container.querySelector('input[value="Test Title"]');
|
|
155
|
+
expect(titleInput).toBeInTheDocument();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should render message input with correct value", () => {
|
|
159
|
+
const { container } = renderComponent();
|
|
160
|
+
const messageInput = container.querySelector('input[value="Test Message"]');
|
|
161
|
+
expect(messageInput).toBeInTheDocument();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should render MediaUploaders component", () => {
|
|
165
|
+
const { getByTestId } = renderComponent();
|
|
166
|
+
expect(getByTestId("media-uploaders")).toBeInTheDocument();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should render CtaButtons component", () => {
|
|
170
|
+
const { getByTestId } = renderComponent();
|
|
171
|
+
expect(getByTestId("cta-buttons")).toBeInTheDocument();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("should render TagList components", () => {
|
|
175
|
+
const { getAllByTestId } = renderComponent();
|
|
176
|
+
const tagLists = getAllByTestId("tag-list");
|
|
177
|
+
expect(tagLists).toHaveLength(2);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe("Title Field", () => {
|
|
182
|
+
it("should call title change handler", () => {
|
|
183
|
+
const { container } = renderComponent();
|
|
184
|
+
const titleInput = container.querySelector('input[value="Test Title"]');
|
|
185
|
+
|
|
186
|
+
fireEvent.change(titleInput, { target: { value: "New Title" } });
|
|
187
|
+
|
|
188
|
+
expect(defaultProps.handlers.handleTitleChange).toHaveBeenCalled();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should display title error when present", () => {
|
|
192
|
+
const { getByTestId } = renderComponent({
|
|
193
|
+
errors: { ...defaultProps.errors, title: "Title is required" },
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(getByTestId("cap-error")).toHaveTextContent("Title is required");
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe("Message Field", () => {
|
|
201
|
+
it("should call message change handler", () => {
|
|
202
|
+
const { container } = renderComponent();
|
|
203
|
+
const messageInput = container.querySelector('input[value="Test Message"]');
|
|
204
|
+
|
|
205
|
+
fireEvent.change(messageInput, { target: { value: "New Message" } });
|
|
206
|
+
|
|
207
|
+
expect(defaultProps.handlers.handleMessageChange).toHaveBeenCalled();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should display message error when present", () => {
|
|
211
|
+
const { getByTestId } = renderComponent({
|
|
212
|
+
errors: { ...defaultProps.errors, message: "Message is required" },
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(getByTestId("cap-error")).toHaveTextContent("Message is required");
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe("Media Type Selection", () => {
|
|
220
|
+
it("should call media type change handler", () => {
|
|
221
|
+
const { container } = renderComponent();
|
|
222
|
+
const mediaSelect = container.querySelector('select');
|
|
223
|
+
|
|
224
|
+
fireEvent.change(mediaSelect, { target: { value: "VIDEO" } });
|
|
225
|
+
|
|
226
|
+
expect(defaultProps.handlers.handleMediaTypeChange).toHaveBeenCalled();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("Action on Click", () => {
|
|
231
|
+
it("should call action on click change handler", () => {
|
|
232
|
+
const { getByTestId } = renderComponent();
|
|
233
|
+
const checkbox = getByTestId("action-checkbox");
|
|
234
|
+
|
|
235
|
+
fireEvent.click(checkbox);
|
|
236
|
+
|
|
237
|
+
expect(defaultProps.handlers.handleActionOnClickChange).toHaveBeenCalled();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("should show action controls when actionOnClick is true", () => {
|
|
241
|
+
const { container } = renderComponent({
|
|
242
|
+
content: { ...defaultProps.content, actionOnClick: true },
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
expect(container.textContent).toContain("Link Type");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("should hide action controls when actionOnClick is false", () => {
|
|
249
|
+
const { container } = renderComponent({
|
|
250
|
+
content: { ...defaultProps.content, actionOnClick: false },
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
expect(container.textContent).not.toContain("Link Type");
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe("Device Type Handling", () => {
|
|
258
|
+
it("should render with Android device type", () => {
|
|
259
|
+
const { container } = renderComponent({ deviceType: ANDROID });
|
|
260
|
+
const titleInput = container.querySelector('#mobile-push-title-name-input-android');
|
|
261
|
+
expect(titleInput).toBeInTheDocument();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("should render with iOS device type", () => {
|
|
265
|
+
const { container } = renderComponent({ deviceType: IOS });
|
|
266
|
+
const titleInput = container.querySelector('#mobile-push-title-name-input-ios');
|
|
267
|
+
expect(titleInput).toBeInTheDocument();
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe("External Link Input", () => {
|
|
272
|
+
it("should call external link change handler", () => {
|
|
273
|
+
const { container } = renderComponent({
|
|
274
|
+
content: { ...defaultProps.content, actionOnClick: true, linkType: EXTERNAL_LINK },
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const externalLinkInput = container.querySelector('input[value="https://example.com"]');
|
|
278
|
+
|
|
279
|
+
if (externalLinkInput) {
|
|
280
|
+
fireEvent.change(externalLinkInput, { target: { value: "https://newlink.com" } });
|
|
281
|
+
expect(defaultProps.handlers.handleExternalLinkChange).toHaveBeenCalled();
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("should display external link error when present", () => {
|
|
286
|
+
const { getByTestId } = renderComponent({
|
|
287
|
+
content: { ...defaultProps.content, actionOnClick: true, linkType: EXTERNAL_LINK },
|
|
288
|
+
errors: { ...defaultProps.errors, externalLink: "Invalid URL" },
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
expect(getByTestId("cap-error")).toHaveTextContent("Invalid URL");
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
describe("Carousel Media Type", () => {
|
|
296
|
+
it("should hide action controls when mediaType is CAROUSEL", () => {
|
|
297
|
+
const { container } = renderComponent({
|
|
298
|
+
content: { ...defaultProps.content, mediaType: "CAROUSEL" },
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
expect(container.textContent).not.toContain("Buttons and Links");
|
|
302
|
+
expect(container.textContent).not.toContain("CtaButtons");
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("should show action controls when mediaType is not CAROUSEL", () => {
|
|
306
|
+
const { container } = renderComponent({
|
|
307
|
+
content: { ...defaultProps.content, mediaType: "IMAGE" },
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(container.textContent).toContain("Buttons and Links");
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
describe("formatMessage Integration", () => {
|
|
315
|
+
it("should call formatMessage with correct arguments", () => {
|
|
316
|
+
renderComponent();
|
|
317
|
+
|
|
318
|
+
expect(defaultProps.formatMessage).toHaveBeenCalledWith(
|
|
319
|
+
expect.objectContaining({
|
|
320
|
+
id: "titlePlaceholder",
|
|
321
|
+
defaultMessage: "Enter title",
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
describe("Error Handling", () => {
|
|
328
|
+
it("should handle missing linkProps gracefully", () => {
|
|
329
|
+
const { container } = renderComponent({
|
|
330
|
+
linkProps: {},
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
expect(container).toBeInTheDocument();
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it("should handle undefined values gracefully", () => {
|
|
337
|
+
const { container } = renderComponent({
|
|
338
|
+
content: {
|
|
339
|
+
...defaultProps.content,
|
|
340
|
+
title: undefined,
|
|
341
|
+
message: undefined,
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
expect(container).toBeInTheDocument();
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Deep link keys handling - covering lines 109-120, 134, 297-303
|
|
350
|
+
it('should handle deep link keys with array from selection', () => {
|
|
351
|
+
const mockDeepLink = [
|
|
352
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] }
|
|
353
|
+
];
|
|
354
|
+
const mockLinkProps = {
|
|
355
|
+
deepLink: mockDeepLink,
|
|
356
|
+
deepLinkValue: 'test-deep-link',
|
|
357
|
+
deepLinkKeysValue: ['key1', 'key2'],
|
|
358
|
+
externalLinkValue: '',
|
|
359
|
+
};
|
|
360
|
+
const mockContent = {
|
|
361
|
+
title: 'Test Title',
|
|
362
|
+
message: 'Test Message',
|
|
363
|
+
mediaType: 'IMAGE',
|
|
364
|
+
actionOnClick: true,
|
|
365
|
+
linkType: 'DEEP_LINK',
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const { getByText, getByDisplayValue } = render(
|
|
369
|
+
<PlatformContentFields
|
|
370
|
+
deviceType="ANDROID"
|
|
371
|
+
content={mockContent}
|
|
372
|
+
errors={{}}
|
|
373
|
+
handlers={defaultProps.handlers}
|
|
374
|
+
tagListProps={defaultProps.tagListProps}
|
|
375
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
376
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
377
|
+
linkProps={mockLinkProps}
|
|
378
|
+
sameContent={false}
|
|
379
|
+
formatMessage={defaultProps.formatMessage}
|
|
380
|
+
/>
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
// Check that deep link keys are displayed correctly
|
|
384
|
+
expect(getByText('key1, key2')).toBeInTheDocument();
|
|
385
|
+
expect(getByDisplayValue('key1, key2')).toBeInTheDocument();
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('should handle deep link keys with single key from selection', () => {
|
|
389
|
+
const mockDeepLink = [
|
|
390
|
+
{ value: 'test-deep-link', keys: 'single-key' }
|
|
391
|
+
];
|
|
392
|
+
const mockLinkProps = {
|
|
393
|
+
deepLink: mockDeepLink,
|
|
394
|
+
deepLinkValue: 'test-deep-link',
|
|
395
|
+
deepLinkKeysValue: ['single-key'],
|
|
396
|
+
externalLinkValue: '',
|
|
397
|
+
};
|
|
398
|
+
const mockContent = {
|
|
399
|
+
title: 'Test Title',
|
|
400
|
+
message: 'Test Message',
|
|
401
|
+
mediaType: 'IMAGE',
|
|
402
|
+
actionOnClick: true,
|
|
403
|
+
linkType: 'DEEP_LINK',
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const { getByText, getByDisplayValue } = render(
|
|
407
|
+
<PlatformContentFields
|
|
408
|
+
deviceType="ANDROID"
|
|
409
|
+
content={mockContent}
|
|
410
|
+
errors={{}}
|
|
411
|
+
handlers={defaultProps.handlers}
|
|
412
|
+
tagListProps={defaultProps.tagListProps}
|
|
413
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
414
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
415
|
+
linkProps={mockLinkProps}
|
|
416
|
+
sameContent={false}
|
|
417
|
+
formatMessage={defaultProps.formatMessage}
|
|
418
|
+
/>
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
// Check that single key is displayed correctly
|
|
422
|
+
expect(getByText('single-key')).toBeInTheDocument();
|
|
423
|
+
expect(getByDisplayValue('single-key')).toBeInTheDocument();
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('should handle deep link keys with no keys from selection but existing keys', () => {
|
|
427
|
+
const mockDeepLink = [
|
|
428
|
+
{ value: 'test-deep-link', keys: [] } // No keys from selection
|
|
429
|
+
];
|
|
430
|
+
const mockLinkProps = {
|
|
431
|
+
deepLink: mockDeepLink,
|
|
432
|
+
deepLinkValue: 'test-deep-link',
|
|
433
|
+
deepLinkKeysValue: ['existing-key1', 'existing-key2'], // But existing keys in value
|
|
434
|
+
externalLinkValue: '',
|
|
435
|
+
};
|
|
436
|
+
const mockContent = {
|
|
437
|
+
title: 'Test Title',
|
|
438
|
+
message: 'Test Message',
|
|
439
|
+
mediaType: 'IMAGE',
|
|
440
|
+
actionOnClick: true,
|
|
441
|
+
linkType: 'DEEP_LINK',
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
const { container } = render(
|
|
445
|
+
<PlatformContentFields
|
|
446
|
+
deviceType="ANDROID"
|
|
447
|
+
content={mockContent}
|
|
448
|
+
errors={{}}
|
|
449
|
+
handlers={defaultProps.handlers}
|
|
450
|
+
tagListProps={defaultProps.tagListProps}
|
|
451
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
452
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
453
|
+
linkProps={mockLinkProps}
|
|
454
|
+
sameContent={false}
|
|
455
|
+
formatMessage={defaultProps.formatMessage}
|
|
456
|
+
/>
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
// When no keys from selection, the deep link keys section should not render at all
|
|
460
|
+
expect(container.textContent).not.toContain('Deep Link Keys');
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('should handle deep link keys with no keys at all', () => {
|
|
464
|
+
const mockDeepLink = [
|
|
465
|
+
{ value: 'test-deep-link', keys: [] } // No keys from selection
|
|
466
|
+
];
|
|
467
|
+
const mockLinkProps = {
|
|
468
|
+
deepLink: mockDeepLink,
|
|
469
|
+
deepLinkValue: 'test-deep-link',
|
|
470
|
+
deepLinkKeysValue: [], // But no keys in the value
|
|
471
|
+
externalLinkValue: '',
|
|
472
|
+
};
|
|
473
|
+
const mockContent = {
|
|
474
|
+
title: 'Test Title',
|
|
475
|
+
message: 'Test Message',
|
|
476
|
+
mediaType: 'IMAGE',
|
|
477
|
+
actionOnClick: true,
|
|
478
|
+
linkType: 'DEEP_LINK',
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
const { container } = render(
|
|
482
|
+
<PlatformContentFields
|
|
483
|
+
deviceType="ANDROID"
|
|
484
|
+
content={mockContent}
|
|
485
|
+
errors={{}}
|
|
486
|
+
handlers={defaultProps.handlers}
|
|
487
|
+
tagListProps={defaultProps.tagListProps}
|
|
488
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
489
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
490
|
+
linkProps={mockLinkProps}
|
|
491
|
+
sameContent={false}
|
|
492
|
+
formatMessage={defaultProps.formatMessage}
|
|
493
|
+
/>
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
// When no keys from selection, the deep link keys section should not render at all
|
|
497
|
+
expect(container.textContent).not.toContain('Deep Link Keys');
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('should handle deep link keys with string value instead of array', () => {
|
|
501
|
+
const mockDeepLink = [
|
|
502
|
+
{ value: 'test-deep-link', keys: 'single-key' }
|
|
503
|
+
];
|
|
504
|
+
const mockLinkProps = {
|
|
505
|
+
deepLink: mockDeepLink,
|
|
506
|
+
deepLinkValue: 'test-deep-link',
|
|
507
|
+
deepLinkKeysValue: 'string-key-value',
|
|
508
|
+
externalLinkValue: '',
|
|
509
|
+
};
|
|
510
|
+
const mockContent = {
|
|
511
|
+
title: 'Test Title',
|
|
512
|
+
message: 'Test Message',
|
|
513
|
+
mediaType: 'IMAGE',
|
|
514
|
+
actionOnClick: true,
|
|
515
|
+
linkType: 'DEEP_LINK',
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const { getByDisplayValue } = render(
|
|
519
|
+
<PlatformContentFields
|
|
520
|
+
deviceType="ANDROID"
|
|
521
|
+
content={mockContent}
|
|
522
|
+
errors={{}}
|
|
523
|
+
handlers={defaultProps.handlers}
|
|
524
|
+
tagListProps={defaultProps.tagListProps}
|
|
525
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
526
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
527
|
+
linkProps={mockLinkProps}
|
|
528
|
+
sameContent={false}
|
|
529
|
+
formatMessage={defaultProps.formatMessage}
|
|
530
|
+
/>
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
// Check that string value is displayed correctly
|
|
534
|
+
expect(getByDisplayValue('string-key-value')).toBeInTheDocument();
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
it('should handle deep link keys with undefined deepLinkKeysValue', () => {
|
|
538
|
+
const mockDeepLink = [
|
|
539
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] }
|
|
540
|
+
];
|
|
541
|
+
const mockLinkProps = {
|
|
542
|
+
deepLink: mockDeepLink,
|
|
543
|
+
deepLinkValue: 'test-deep-link',
|
|
544
|
+
deepLinkKeysValue: undefined,
|
|
545
|
+
externalLinkValue: '',
|
|
546
|
+
};
|
|
547
|
+
const mockContent = {
|
|
548
|
+
title: 'Test Title',
|
|
549
|
+
message: 'Test Message',
|
|
550
|
+
mediaType: 'IMAGE',
|
|
551
|
+
actionOnClick: true,
|
|
552
|
+
linkType: 'DEEP_LINK',
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
const { getAllByDisplayValue } = render(
|
|
556
|
+
<PlatformContentFields
|
|
557
|
+
deviceType="ANDROID"
|
|
558
|
+
content={mockContent}
|
|
559
|
+
errors={{}}
|
|
560
|
+
handlers={defaultProps.handlers}
|
|
561
|
+
tagListProps={defaultProps.tagListProps}
|
|
562
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
563
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
564
|
+
linkProps={mockLinkProps}
|
|
565
|
+
sameContent={false}
|
|
566
|
+
formatMessage={defaultProps.formatMessage}
|
|
567
|
+
/>
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
// Check that empty string is displayed when deepLinkKeysValue is undefined
|
|
571
|
+
const emptyInputs = getAllByDisplayValue('');
|
|
572
|
+
expect(emptyInputs.length).toBeGreaterThan(0);
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
it('should handle deep link keys placeholder with fallback', () => {
|
|
576
|
+
const mockDeepLink = [
|
|
577
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] } // Need keys to trigger the section
|
|
578
|
+
];
|
|
579
|
+
const mockLinkProps = {
|
|
580
|
+
deepLink: mockDeepLink,
|
|
581
|
+
deepLinkValue: 'test-deep-link',
|
|
582
|
+
deepLinkKeysValue: [],
|
|
583
|
+
externalLinkValue: '',
|
|
584
|
+
};
|
|
585
|
+
const mockContent = {
|
|
586
|
+
title: 'Test Title',
|
|
587
|
+
message: 'Test Message',
|
|
588
|
+
mediaType: 'IMAGE',
|
|
589
|
+
actionOnClick: true,
|
|
590
|
+
linkType: 'DEEP_LINK',
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
render(
|
|
594
|
+
<PlatformContentFields
|
|
595
|
+
deviceType="ANDROID"
|
|
596
|
+
content={mockContent}
|
|
597
|
+
errors={{}}
|
|
598
|
+
handlers={defaultProps.handlers}
|
|
599
|
+
tagListProps={defaultProps.tagListProps}
|
|
600
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
601
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
602
|
+
linkProps={mockLinkProps}
|
|
603
|
+
sameContent={false}
|
|
604
|
+
formatMessage={defaultProps.formatMessage}
|
|
605
|
+
/>
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
// Verify that formatMessage was called with the fallback placeholder
|
|
609
|
+
expect(defaultProps.formatMessage).toHaveBeenCalledWith(
|
|
610
|
+
expect.any(Object),
|
|
611
|
+
{ key: 'key1, key2' }
|
|
612
|
+
);
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it('should handle deep link keys error display', () => {
|
|
616
|
+
const mockDeepLink = [
|
|
617
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] }
|
|
618
|
+
];
|
|
619
|
+
const mockLinkProps = {
|
|
620
|
+
deepLink: mockDeepLink,
|
|
621
|
+
deepLinkValue: 'test-deep-link',
|
|
622
|
+
deepLinkKeysValue: ['key1', 'key2'],
|
|
623
|
+
externalLinkValue: '',
|
|
624
|
+
};
|
|
625
|
+
const mockContent = {
|
|
626
|
+
title: 'Test Title',
|
|
627
|
+
message: 'Test Message',
|
|
628
|
+
mediaType: 'IMAGE',
|
|
629
|
+
actionOnClick: true,
|
|
630
|
+
linkType: 'DEEP_LINK',
|
|
631
|
+
};
|
|
632
|
+
const mockErrors = {
|
|
633
|
+
deepLinkKeys: 'Deep link keys error message',
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
const { getByText } = render(
|
|
637
|
+
<PlatformContentFields
|
|
638
|
+
deviceType="ANDROID"
|
|
639
|
+
content={mockContent}
|
|
640
|
+
errors={mockErrors}
|
|
641
|
+
handlers={defaultProps.handlers}
|
|
642
|
+
tagListProps={defaultProps.tagListProps}
|
|
643
|
+
mediaUploaderProps={defaultProps.mediaUploaderProps}
|
|
644
|
+
ctaButtonProps={defaultProps.ctaButtonProps}
|
|
645
|
+
linkProps={mockLinkProps}
|
|
646
|
+
sameContent={false}
|
|
647
|
+
formatMessage={defaultProps.formatMessage}
|
|
648
|
+
/>
|
|
649
|
+
);
|
|
650
|
+
|
|
651
|
+
// Check that error message is displayed
|
|
652
|
+
expect(getByText('Deep link keys error message')).toBeInTheDocument();
|
|
653
|
+
});
|
|
654
|
+
});
|