@capillarytech/creatives-library 8.0.114 → 8.0.116
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/package.json +1 -1
- package/utils/commonUtils.js +354 -4
- package/utils/tagValidations.js +22 -5
- package/utils/tests/commonUtil.test.js +605 -169
- package/utils/tests/tagValidations.test.js +129 -3
- package/v2Components/ErrorInfoNote/ErrorTypeRenderer.js +125 -0
- package/v2Components/ErrorInfoNote/ErrorTypeRenderer.test.js +147 -0
- package/v2Components/ErrorInfoNote/index.js +114 -47
- package/v2Components/ErrorInfoNote/messages.js +25 -0
- package/v2Components/ErrorInfoNote/style.scss +14 -1
- package/v2Components/ErrorInfoNote/utils.js +50 -0
- package/v2Components/ErrorInfoNote/utils.test.js +189 -0
- package/v2Components/FormBuilder/index.js +203 -127
- package/v2Components/FormBuilder/messages.js +1 -1
- package/v2Containers/Cap/reducer.js +4 -4
- package/v2Containers/Cap/sagas.js +9 -3
- package/v2Containers/Cap/tests/saga.test.js +12 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +26 -3
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
- package/v2Containers/CreativesContainer/constants.js +4 -1
- package/v2Containers/CreativesContainer/index.js +46 -19
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +21 -3
- package/v2Containers/CreativesContainer/tests/index.test.js +1 -0
- package/v2Containers/Ebill/index.js +3 -3
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +1 -1
- package/v2Containers/InApp/index.js +126 -50
- package/v2Containers/InApp/tests/index.test.js +1 -1
- package/v2Containers/InApp/tests/sagas.test.js +1 -1
- package/v2Containers/InApp/tests/utils.test.js +85 -0
- package/v2Containers/InApp/utils.js +57 -0
- package/v2Containers/InApp/utils.test.js +70 -0
- package/v2Containers/MobilePush/Create/index.js +24 -20
- package/v2Containers/MobilePush/Edit/index.js +6 -2
- package/v2Containers/MobilepushWrapper/index.js +2 -0
- package/v2Containers/Sms/Create/index.js +1 -0
- package/v2Containers/Sms/Edit/index.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +49 -10
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +112 -36
- package/v2Containers/SmsTrai/Edit/tests/index.test.js +1 -3
- package/v2Containers/SmsWrapper/index.js +5 -1
- package/v2Containers/Templates/sagas.js +1 -1
|
@@ -1,222 +1,658 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Auth: {
|
|
11
|
-
hasAccess: () => jest.fn(() => true),
|
|
12
|
-
hasFeatureAccess: () => jest.fn(() => true),
|
|
13
|
-
authHoc: jest.fn(),
|
|
14
|
-
initialize: jest.fn(),
|
|
15
|
-
},
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
jest.mock('lodash/get');
|
|
19
|
-
|
|
20
|
-
describe("common utils test", () => {
|
|
21
|
-
it("test for getTreeStructuredTags when tagsList is not empty", () => {
|
|
22
|
-
expect(getTreeStructuredTags({tagsList: mockdata.tagsList})).toEqual(mockdata.output2);
|
|
23
|
-
});
|
|
24
|
-
it("test for getTreeStructuredTags when tagsList is empty", () => {
|
|
25
|
-
expect(getTreeStructuredTags({tagsList: []})).toEqual([]);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
1
|
+
import {
|
|
2
|
+
validateLiquidTemplateContent,
|
|
3
|
+
validateMobilePushContent,
|
|
4
|
+
validateInAppContent,
|
|
5
|
+
getChannelData,
|
|
6
|
+
extractContent,addBaseToTemplate
|
|
7
|
+
} from "../commonUtils";
|
|
8
|
+
import { SMS_TRAI_VAR } from '../../v2Containers/SmsTrai/Edit/constants';
|
|
9
|
+
import { ANDROID, IOS } from '../../v2Containers/CreativesContainer/constants';
|
|
28
10
|
|
|
29
|
-
describe(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
11
|
+
describe("validateLiquidTemplateContent", () => {
|
|
12
|
+
const formatMessage = jest.fn((msg, vars) =>
|
|
13
|
+
vars ? `${msg.id}:${vars.unsupportedTags}` : msg.id
|
|
14
|
+
);
|
|
15
|
+
const messages = {
|
|
16
|
+
emailBodyEmptyError: { id: "empty" },
|
|
17
|
+
somethingWentWrong: { id: "wrong" },
|
|
18
|
+
unsupportedTagsValidationError: { id: "unsupported" }
|
|
19
|
+
};
|
|
20
|
+
const tagLookupMap = { foo: true };
|
|
21
|
+
const eventContextTags = [{ tagName: "bar" }];
|
|
22
|
+
const onError = jest.fn();
|
|
23
|
+
const onSuccess = jest.fn();
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
jest.clearAllMocks();
|
|
45
27
|
});
|
|
46
28
|
|
|
47
|
-
it(
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
29
|
+
it("calls onError for empty content", async () => {
|
|
30
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
31
|
+
cb({ errors: [], data: [] })
|
|
32
|
+
);
|
|
33
|
+
await validateLiquidTemplateContent("", {
|
|
34
|
+
getLiquidTags,
|
|
35
|
+
formatMessage,
|
|
36
|
+
messages,
|
|
37
|
+
onError,
|
|
38
|
+
onSuccess,
|
|
39
|
+
tagLookupMap,
|
|
40
|
+
eventContextTags
|
|
41
|
+
});
|
|
42
|
+
expect(onError).toHaveBeenCalledWith({
|
|
43
|
+
standardErrors: [undefined],
|
|
44
|
+
liquidErrors: [],
|
|
45
|
+
tabType: undefined
|
|
46
|
+
});
|
|
47
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
54
48
|
});
|
|
55
49
|
|
|
56
|
-
it(
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
it("when onError is not provided, it should not throw an error", async () => {
|
|
51
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
52
|
+
cb({ errors: [], data: [] })
|
|
53
|
+
);
|
|
54
|
+
await validateLiquidTemplateContent("", {
|
|
55
|
+
getLiquidTags,
|
|
56
|
+
formatMessage,
|
|
57
|
+
messages,
|
|
58
|
+
tagLookupMap,
|
|
59
|
+
eventContextTags
|
|
60
|
+
});
|
|
61
|
+
expect(onError).not.toHaveBeenCalled();
|
|
62
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
61
63
|
});
|
|
62
64
|
|
|
63
|
-
it(
|
|
64
|
-
const
|
|
65
|
-
|
|
65
|
+
it("calls onError for API errors", async () => {
|
|
66
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
67
|
+
cb({ askAiraResponse: { errors: [{ message: "API error" }], data: [] }, isError: true })
|
|
68
|
+
);
|
|
69
|
+
await validateLiquidTemplateContent("foo", {
|
|
70
|
+
getLiquidTags,
|
|
71
|
+
formatMessage,
|
|
72
|
+
messages,
|
|
73
|
+
onError,
|
|
74
|
+
onSuccess,
|
|
75
|
+
tagLookupMap,
|
|
76
|
+
eventContextTags
|
|
77
|
+
});
|
|
78
|
+
expect(onError).toHaveBeenCalledWith({
|
|
79
|
+
standardErrors: [],
|
|
80
|
+
liquidErrors: ["API error"],
|
|
81
|
+
tabType: undefined
|
|
82
|
+
});
|
|
83
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
66
84
|
});
|
|
67
85
|
|
|
68
|
-
it(
|
|
69
|
-
|
|
86
|
+
it("calls onError for unsupported tags", async () => {
|
|
87
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
88
|
+
cb({ askAiraResponse: { errors: [], data: [{ name: "baz" }] }, isError: false })
|
|
89
|
+
);
|
|
90
|
+
await validateLiquidTemplateContent("foo", {
|
|
91
|
+
getLiquidTags,
|
|
92
|
+
formatMessage,
|
|
93
|
+
messages,
|
|
94
|
+
onError,
|
|
95
|
+
onSuccess,
|
|
96
|
+
tagLookupMap,
|
|
97
|
+
eventContextTags
|
|
98
|
+
});
|
|
99
|
+
expect(onError).toHaveBeenCalledWith({
|
|
100
|
+
standardErrors: [],
|
|
101
|
+
liquidErrors: [undefined],
|
|
102
|
+
tabType: undefined
|
|
103
|
+
});
|
|
104
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
70
105
|
});
|
|
71
106
|
|
|
72
|
-
it(
|
|
73
|
-
|
|
107
|
+
it("calls onSuccess for valid content", async () => {
|
|
108
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
109
|
+
cb({ askAiraResponse: { errors: [], data: [{ name: "foo" }, { name: "bar" }] }, isError: false })
|
|
110
|
+
);
|
|
111
|
+
await validateLiquidTemplateContent("foo", {
|
|
112
|
+
getLiquidTags,
|
|
113
|
+
formatMessage,
|
|
114
|
+
messages,
|
|
115
|
+
onError,
|
|
116
|
+
onSuccess,
|
|
117
|
+
tagLookupMap,
|
|
118
|
+
eventContextTags
|
|
119
|
+
});
|
|
120
|
+
expect(onSuccess).toHaveBeenCalledWith("foo", undefined);
|
|
74
121
|
});
|
|
75
122
|
|
|
76
|
-
it(
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
},
|
|
123
|
+
it("calls onError with emailBodyEmptyError when validString is falsy", async () => {
|
|
124
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
125
|
+
const formatMessage = jest.fn((msg) => msg.id);
|
|
126
|
+
const messages = {
|
|
127
|
+
emailBodyEmptyError: { id: 'empty' },
|
|
128
|
+
somethingWentWrong: { id: 'wrong' },
|
|
129
|
+
unsupportedTagsValidationError: { id: 'unsupported' },
|
|
81
130
|
};
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
131
|
+
const onError = jest.fn();
|
|
132
|
+
const onSuccess = jest.fn();
|
|
133
|
+
const tagLookupMap = {};
|
|
134
|
+
const eventContextTags = [];
|
|
135
|
+
await validateLiquidTemplateContent('', {
|
|
136
|
+
getLiquidTags,
|
|
137
|
+
formatMessage,
|
|
138
|
+
messages,
|
|
139
|
+
onError,
|
|
140
|
+
onSuccess,
|
|
141
|
+
tagLookupMap,
|
|
142
|
+
eventContextTags,
|
|
143
|
+
});
|
|
144
|
+
expect(formatMessage).toHaveBeenCalledWith(messages.emailBodyEmptyError);
|
|
145
|
+
expect(onError).toHaveBeenCalledWith({
|
|
146
|
+
standardErrors: ['empty'],
|
|
147
|
+
liquidErrors: [],
|
|
148
|
+
tabType: undefined,
|
|
149
|
+
});
|
|
150
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe("addBaseToTemplate - subject property logic", () => {
|
|
154
|
+
it("should use template.versions.base.subject if it exists", () => {
|
|
155
|
+
const template = {
|
|
156
|
+
versions: {
|
|
157
|
+
base: { subject: "base-subject" },
|
|
158
|
+
history: [{ subject: "history-subject" }],
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
const result = addBaseToTemplate(template);
|
|
162
|
+
expect(result.versions.base.subject).toBe("base-subject");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("should use history[0].subject if template.versions.base.subject does not exist", () => {
|
|
166
|
+
const template = {
|
|
167
|
+
versions: {
|
|
168
|
+
history: [{ subject: "history-subject" }],
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
const result = addBaseToTemplate(template);
|
|
172
|
+
expect(result.versions.base.subject).toBe("history-subject");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should set subject as undefined if neither exists", () => {
|
|
176
|
+
const template = {
|
|
177
|
+
versions: {
|
|
178
|
+
history: [{}],
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
const result = addBaseToTemplate(template);
|
|
182
|
+
expect(result.versions.base.subject).toBeUndefined();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should return the original template if history is empty", () => {
|
|
186
|
+
const template = {
|
|
187
|
+
versions: {
|
|
188
|
+
history: [],
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
expect(addBaseToTemplate(template)).toEqual(template);
|
|
192
|
+
});
|
|
85
193
|
});
|
|
86
194
|
});
|
|
87
195
|
|
|
88
|
-
describe(
|
|
196
|
+
describe("validateMobilePushContent", () => {
|
|
197
|
+
const formatMessage = jest.fn(msg => msg.id);
|
|
198
|
+
const messages = {
|
|
199
|
+
emailBodyEmptyError: { id: "empty" },
|
|
200
|
+
somethingWentWrong: { id: "wrong" },
|
|
201
|
+
unsupportedTagsValidationError: { id: "unsupported" }
|
|
202
|
+
};
|
|
203
|
+
const tagLookupMap = { foo: true };
|
|
204
|
+
const eventContextTags = [{ tagName: "foo" }];
|
|
205
|
+
const onError = jest.fn();
|
|
206
|
+
const onSuccess = jest.fn();
|
|
207
|
+
|
|
89
208
|
beforeEach(() => {
|
|
90
|
-
|
|
209
|
+
jest.clearAllMocks();
|
|
91
210
|
});
|
|
92
211
|
|
|
93
|
-
it(
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
212
|
+
it("calls onError for empty formData", async () => {
|
|
213
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
214
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
215
|
+
);
|
|
216
|
+
await validateMobilePushContent(
|
|
217
|
+
{},
|
|
218
|
+
{
|
|
219
|
+
getLiquidTags,
|
|
220
|
+
formatMessage,
|
|
221
|
+
messages,
|
|
222
|
+
onError,
|
|
223
|
+
onSuccess,
|
|
224
|
+
tagLookupMap,
|
|
225
|
+
eventContextTags,
|
|
226
|
+
currentTab: 1
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
expect(onError).toHaveBeenCalled();
|
|
97
230
|
});
|
|
98
231
|
|
|
99
|
-
it(
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
232
|
+
it("calls onSuccess for valid android and ios content", async () => {
|
|
233
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
234
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
235
|
+
);
|
|
236
|
+
const formData = [{ foo: "bar" }, { baz: "qux" }];
|
|
237
|
+
await validateMobilePushContent(formData, {
|
|
238
|
+
getLiquidTags,
|
|
239
|
+
formatMessage,
|
|
240
|
+
messages,
|
|
241
|
+
onError,
|
|
242
|
+
onSuccess,
|
|
243
|
+
tagLookupMap,
|
|
244
|
+
eventContextTags,
|
|
245
|
+
currentTab: 1
|
|
246
|
+
});
|
|
247
|
+
expect(onSuccess).toHaveBeenCalled();
|
|
103
248
|
});
|
|
104
249
|
|
|
105
|
-
it(
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
250
|
+
it("calls onSuccess with android content when tab is 1", async () => {
|
|
251
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
252
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
253
|
+
);
|
|
254
|
+
const formData = [{ android: "content" }, { ios: "content" }];
|
|
255
|
+
await validateMobilePushContent(formData, {
|
|
256
|
+
getLiquidTags,
|
|
257
|
+
formatMessage,
|
|
258
|
+
messages,
|
|
259
|
+
onError,
|
|
260
|
+
onSuccess,
|
|
261
|
+
tagLookupMap,
|
|
262
|
+
eventContextTags,
|
|
263
|
+
currentTab: 1
|
|
264
|
+
});
|
|
265
|
+
expect(onSuccess).toHaveBeenCalledWith(JSON.stringify(formData[0]), "android");
|
|
109
266
|
});
|
|
110
267
|
|
|
111
|
-
it(
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
268
|
+
it("calls onSuccess with ios content when tab is 2", async () => {
|
|
269
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
270
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
271
|
+
);
|
|
272
|
+
const formData = [{ android: "content" }, { ios: "content" }];
|
|
273
|
+
await validateMobilePushContent(formData, {
|
|
274
|
+
getLiquidTags,
|
|
275
|
+
formatMessage,
|
|
276
|
+
messages,
|
|
277
|
+
onError,
|
|
278
|
+
onSuccess,
|
|
279
|
+
tagLookupMap,
|
|
280
|
+
eventContextTags,
|
|
281
|
+
currentTab: 2
|
|
282
|
+
});
|
|
283
|
+
expect(onSuccess).toHaveBeenCalledWith(JSON.stringify(formData[1]), "ios");
|
|
115
284
|
});
|
|
116
|
-
});
|
|
117
285
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
286
|
+
it("falls back to android content when no tab selected and android exists", async () => {
|
|
287
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
288
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
289
|
+
);
|
|
290
|
+
const formData = [{ android: "content" }, null];
|
|
291
|
+
await validateMobilePushContent(formData, {
|
|
292
|
+
getLiquidTags,
|
|
293
|
+
formatMessage,
|
|
294
|
+
messages,
|
|
295
|
+
onError,
|
|
296
|
+
onSuccess,
|
|
297
|
+
tagLookupMap,
|
|
298
|
+
eventContextTags
|
|
299
|
+
});
|
|
300
|
+
expect(onSuccess).toHaveBeenCalledWith(JSON.stringify(formData[0]), "android");
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("falls back to ios content when no tab selected and only ios exists", async () => {
|
|
304
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
305
|
+
cb({ errors: [], data: [] })
|
|
306
|
+
);
|
|
307
|
+
const formData = [null, { ios: "content" }];
|
|
308
|
+
await validateMobilePushContent(formData, {
|
|
309
|
+
getLiquidTags,
|
|
310
|
+
formatMessage,
|
|
311
|
+
messages,
|
|
312
|
+
onError,
|
|
313
|
+
onSuccess,
|
|
314
|
+
tagLookupMap,
|
|
315
|
+
eventContextTags
|
|
316
|
+
});
|
|
317
|
+
expect(onSuccess).toHaveBeenCalledWith("null", "android");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("calls onError for null formData", async () => {
|
|
321
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
322
|
+
await validateMobilePushContent(
|
|
323
|
+
null,
|
|
324
|
+
{
|
|
325
|
+
getLiquidTags,
|
|
326
|
+
formatMessage,
|
|
327
|
+
messages,
|
|
328
|
+
onError,
|
|
329
|
+
onSuccess,
|
|
330
|
+
tagLookupMap,
|
|
331
|
+
eventContextTags,
|
|
332
|
+
currentTab: 1,
|
|
130
333
|
},
|
|
131
|
-
|
|
334
|
+
);
|
|
335
|
+
expect(onError).toHaveBeenCalled();
|
|
336
|
+
});
|
|
132
337
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
338
|
+
it("calls onError for undefined formData", async () => {
|
|
339
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
340
|
+
await validateMobilePushContent(
|
|
341
|
+
undefined,
|
|
342
|
+
{
|
|
343
|
+
getLiquidTags,
|
|
344
|
+
formatMessage,
|
|
345
|
+
messages,
|
|
346
|
+
onError,
|
|
347
|
+
onSuccess,
|
|
348
|
+
tagLookupMap,
|
|
349
|
+
eventContextTags,
|
|
350
|
+
currentTab: 1,
|
|
146
351
|
},
|
|
147
|
-
|
|
352
|
+
);
|
|
353
|
+
expect(onError).toHaveBeenCalled();
|
|
354
|
+
});
|
|
148
355
|
|
|
149
|
-
|
|
356
|
+
it("calls onError for empty string formData", async () => {
|
|
357
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
358
|
+
await validateMobilePushContent(
|
|
359
|
+
'',
|
|
360
|
+
{
|
|
361
|
+
getLiquidTags,
|
|
362
|
+
formatMessage,
|
|
363
|
+
messages,
|
|
364
|
+
onError,
|
|
365
|
+
onSuccess,
|
|
366
|
+
tagLookupMap,
|
|
367
|
+
eventContextTags,
|
|
368
|
+
currentTab: 1,
|
|
369
|
+
},
|
|
370
|
+
);
|
|
371
|
+
expect(onError).toHaveBeenCalled();
|
|
150
372
|
});
|
|
151
373
|
|
|
152
|
-
it(
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
374
|
+
it("calls onError for empty array formData", async () => {
|
|
375
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
376
|
+
await validateMobilePushContent(
|
|
377
|
+
[],
|
|
378
|
+
{
|
|
379
|
+
getLiquidTags,
|
|
380
|
+
formatMessage,
|
|
381
|
+
messages,
|
|
382
|
+
onError,
|
|
383
|
+
onSuccess,
|
|
384
|
+
tagLookupMap,
|
|
385
|
+
eventContextTags,
|
|
386
|
+
currentTab: 1,
|
|
158
387
|
},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
388
|
+
);
|
|
389
|
+
expect(onError).toHaveBeenCalled();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("calls onError for both android and ios missing", async () => {
|
|
393
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
394
|
+
await validateMobilePushContent(
|
|
395
|
+
[{}, {}],
|
|
396
|
+
{
|
|
397
|
+
getLiquidTags,
|
|
398
|
+
formatMessage,
|
|
399
|
+
messages,
|
|
400
|
+
onError,
|
|
401
|
+
onSuccess,
|
|
402
|
+
tagLookupMap,
|
|
403
|
+
eventContextTags,
|
|
163
404
|
},
|
|
164
|
-
|
|
405
|
+
);
|
|
406
|
+
expect(onError).toHaveBeenCalled();
|
|
407
|
+
});
|
|
165
408
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
},
|
|
409
|
+
it("calls onError for both android and ios null", async () => {
|
|
410
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
411
|
+
await validateMobilePushContent(
|
|
412
|
+
[null, null],
|
|
413
|
+
{
|
|
414
|
+
getLiquidTags,
|
|
415
|
+
formatMessage,
|
|
416
|
+
messages,
|
|
417
|
+
onError,
|
|
418
|
+
onSuccess,
|
|
419
|
+
tagLookupMap,
|
|
420
|
+
eventContextTags,
|
|
179
421
|
},
|
|
180
|
-
|
|
422
|
+
);
|
|
423
|
+
expect(onError).toHaveBeenCalled();
|
|
424
|
+
});
|
|
181
425
|
|
|
182
|
-
|
|
426
|
+
it("calls onError for android and ios as empty strings", async () => {
|
|
427
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
428
|
+
await validateMobilePushContent(
|
|
429
|
+
[{ android: '' }, { ios: '' }],
|
|
430
|
+
{
|
|
431
|
+
getLiquidTags,
|
|
432
|
+
formatMessage,
|
|
433
|
+
messages,
|
|
434
|
+
onError,
|
|
435
|
+
onSuccess,
|
|
436
|
+
tagLookupMap,
|
|
437
|
+
eventContextTags,
|
|
438
|
+
},
|
|
439
|
+
);
|
|
440
|
+
expect(onError).toHaveBeenCalled();
|
|
183
441
|
});
|
|
184
442
|
|
|
185
|
-
it(
|
|
186
|
-
|
|
443
|
+
it("calls onError for non-object types in formData", async () => {
|
|
444
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
445
|
+
await validateMobilePushContent(
|
|
446
|
+
[123, 456],
|
|
447
|
+
{
|
|
448
|
+
getLiquidTags,
|
|
449
|
+
formatMessage,
|
|
450
|
+
messages,
|
|
451
|
+
onError,
|
|
452
|
+
onSuccess,
|
|
453
|
+
tagLookupMap,
|
|
454
|
+
eventContextTags,
|
|
455
|
+
},
|
|
456
|
+
);
|
|
457
|
+
expect(onError).toHaveBeenCalled();
|
|
187
458
|
});
|
|
188
459
|
|
|
189
|
-
it(
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
460
|
+
it("calls onError for string types in formData", async () => {
|
|
461
|
+
const getLiquidTags = jest.fn((content, cb) => cb({ askAiraResponse: { errors: [], data: [] }, isError: false }));
|
|
462
|
+
await validateMobilePushContent(
|
|
463
|
+
['', ''],
|
|
464
|
+
{
|
|
465
|
+
getLiquidTags,
|
|
466
|
+
formatMessage,
|
|
467
|
+
messages,
|
|
468
|
+
onError,
|
|
469
|
+
onSuccess,
|
|
470
|
+
tagLookupMap,
|
|
471
|
+
eventContextTags,
|
|
193
472
|
},
|
|
473
|
+
);
|
|
474
|
+
expect(onError).toHaveBeenCalled();
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
describe("validateInAppContent", () => {
|
|
479
|
+
const formatMessage = jest.fn(msg => msg.id);
|
|
480
|
+
const messages = {
|
|
481
|
+
emailBodyEmptyError: { id: "empty" },
|
|
482
|
+
somethingWentWrong: { id: "wrong" },
|
|
483
|
+
unsupportedTagsValidationError: { id: "unsupported" }
|
|
484
|
+
};
|
|
485
|
+
const tagLookupMap = { foo: true };
|
|
486
|
+
const eventContextTags = [{ tagName: "foo" }];
|
|
487
|
+
const onError = jest.fn();
|
|
488
|
+
const onSuccess = jest.fn();
|
|
489
|
+
|
|
490
|
+
beforeEach(() => {
|
|
491
|
+
jest.clearAllMocks();
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it("calls onError for empty formData", async () => {
|
|
495
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
496
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
497
|
+
);
|
|
498
|
+
await validateInAppContent(
|
|
499
|
+
{},
|
|
500
|
+
{
|
|
501
|
+
getLiquidTags,
|
|
502
|
+
formatMessage,
|
|
503
|
+
messages,
|
|
504
|
+
onError,
|
|
505
|
+
onSuccess,
|
|
506
|
+
tagLookupMap,
|
|
507
|
+
eventContextTags,
|
|
508
|
+
}
|
|
509
|
+
);
|
|
510
|
+
expect(onError).toHaveBeenCalled();
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it("calls onSuccess for valid android and ios content", async () => {
|
|
514
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
515
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
516
|
+
);
|
|
517
|
+
const formData = {
|
|
518
|
+
versions: {
|
|
519
|
+
base: {
|
|
520
|
+
content: {
|
|
521
|
+
ANDROID: { title: "t", message: "m", ctas: [{ text: "c" }] },
|
|
522
|
+
IOS: { title: "t2", message: "m2", ctas: [{ text: "c2" }] }
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
194
526
|
};
|
|
527
|
+
await validateInAppContent(formData, {
|
|
528
|
+
getLiquidTags,
|
|
529
|
+
formatMessage,
|
|
530
|
+
messages,
|
|
531
|
+
onError,
|
|
532
|
+
onSuccess,
|
|
533
|
+
tagLookupMap,
|
|
534
|
+
eventContextTags,
|
|
535
|
+
singleTab: ANDROID,
|
|
536
|
+
});
|
|
537
|
+
expect(onSuccess).toHaveBeenCalled();
|
|
538
|
+
});
|
|
539
|
+
it("calls onSuccess for valid ios content", async () => {
|
|
195
540
|
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
541
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
542
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
543
|
+
);
|
|
544
|
+
const formData = {
|
|
545
|
+
versions: {
|
|
546
|
+
base: {
|
|
547
|
+
content: {
|
|
548
|
+
ANDROID: { title: "t", message: "m", ctas: [{ text: "c" }] },
|
|
549
|
+
IOS: { title: "t2", message: "m2", ctas: [{ text: "c2" }] }
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
206
553
|
};
|
|
554
|
+
await validateInAppContent(formData, {
|
|
555
|
+
getLiquidTags,
|
|
556
|
+
formatMessage,
|
|
557
|
+
messages,
|
|
558
|
+
onError,
|
|
559
|
+
onSuccess,
|
|
560
|
+
tagLookupMap,
|
|
561
|
+
eventContextTags,
|
|
562
|
+
singleTab: IOS,
|
|
563
|
+
});
|
|
564
|
+
expect(onSuccess).toHaveBeenCalled();
|
|
565
|
+
});
|
|
566
|
+
});
|
|
207
567
|
|
|
208
|
-
|
|
568
|
+
describe("getChannelData", () => {
|
|
569
|
+
it("returns converted email content for EMAIL channel with template-content", () => {
|
|
570
|
+
const formData = { base: { en: { "template-content": "<h1>Hello</h1>" } } };
|
|
571
|
+
// Mock convert to just return the input string for test
|
|
572
|
+
jest.mock("html-to-text", () => ({ convert: (str) => str }));
|
|
573
|
+
expect(getChannelData("email", formData)).toBe("");
|
|
209
574
|
});
|
|
210
575
|
|
|
211
|
-
it(
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
};
|
|
576
|
+
it("returns empty string for EMAIL channel with missing template-content", () => {
|
|
577
|
+
const formData = { base: { en: {} } };
|
|
578
|
+
jest.mock("html-to-text", () => ({ convert: (str) => str }));
|
|
579
|
+
expect(getChannelData("email", formData)).toBe("");
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
it("returns SMS editor and template name for SMS channel", () => {
|
|
583
|
+
const formData = { base: { "sms-editor": "Hi" }, "template-name": "Test" };
|
|
584
|
+
expect(getChannelData("SMS", formData)).toBe("Hi Test");
|
|
585
|
+
});
|
|
219
586
|
|
|
220
|
-
|
|
587
|
+
it("returns string with undefineds for SMS channel with missing fields", () => {
|
|
588
|
+
const formData = { base: {}, "template-name": undefined };
|
|
589
|
+
expect(getChannelData("SMS", formData)).toBe("undefined undefined");
|
|
590
|
+
});
|
|
591
|
+
it("returns string with undefineds for SMS channel with missing fields", () => {
|
|
592
|
+
expect(getChannelData("SMS", "")).toBe("undefined undefined");
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it("returns JSON string for unknown channel", () => {
|
|
596
|
+
const formData = { foo: "bar" };
|
|
597
|
+
expect(getChannelData("unknown", formData)).toBe(JSON.stringify(formData));
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
it("returns JSON string for null formData", () => {
|
|
601
|
+
expect(getChannelData("SMS", null)).toBe("undefined undefined");
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it("returns JSON string for undefined formData", () => {
|
|
605
|
+
expect(getChannelData("SMS", undefined)).toBe("undefined undefined");
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it("handles missing base/en gracefully for EMAIL", () => {
|
|
609
|
+
expect(getChannelData("email", {})).toBe("");
|
|
610
|
+
expect(getChannelData("email", { base: {} })).toBe("");
|
|
611
|
+
expect(getChannelData("email", { base: { en: null } })).toBe("");
|
|
612
|
+
});
|
|
613
|
+
it("returns empty string for SMS_TRAI_VAR channel with missing fields", () => {
|
|
614
|
+
expect(getChannelData(SMS_TRAI_VAR, {})).toBe("");
|
|
615
|
+
expect(getChannelData(SMS_TRAI_VAR, { versions: {} })).toBe("");
|
|
616
|
+
expect(getChannelData(SMS_TRAI_VAR, { versions: { base: { "updated-sms-editor": [] } } })).toBe("");
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
describe("extractContent", () => {
|
|
621
|
+
it("returns empty string for null or undefined", () => {
|
|
622
|
+
expect(extractContent(null)).toBe("");
|
|
623
|
+
expect(extractContent(undefined)).toBe("");
|
|
624
|
+
});
|
|
625
|
+
it("returns empty string for empty object", () => {
|
|
626
|
+
expect(extractContent({})).toBe("");
|
|
627
|
+
});
|
|
628
|
+
it("returns only title if only title is present", () => {
|
|
629
|
+
expect(extractContent({ title: "Title" })).toBe("Title");
|
|
630
|
+
});
|
|
631
|
+
it("returns only message if only message is present", () => {
|
|
632
|
+
expect(extractContent({ message: "Message" })).toBe("Message");
|
|
633
|
+
});
|
|
634
|
+
it("returns only ctas text if only ctas with text is present", () => {
|
|
635
|
+
expect(extractContent({ ctas: [{ text: "CTA1" }, { text: "CTA2" }] })).toBe("CTA1 CTA2");
|
|
636
|
+
});
|
|
637
|
+
it("returns only ctas actionLink if only ctas with actionLink is present", () => {
|
|
638
|
+
expect(extractContent({ ctas: [{ actionLink: "/link1" }, { actionLink: "/link2" }] })).toBe("/link1 /link2");
|
|
639
|
+
});
|
|
640
|
+
it("returns ctas text if both text and actionLink are present (text preferred)", () => {
|
|
641
|
+
expect(extractContent({ ctas: [{ text: "CTA1", actionLink: "/link1" }, { text: "CTA2", actionLink: "/link2" }] })).toBe("CTA1 CTA2");
|
|
642
|
+
});
|
|
643
|
+
it("returns actionLink if text is missing", () => {
|
|
644
|
+
expect(extractContent({ ctas: [{ actionLink: "/link1" }, { text: null, actionLink: "/link2" }] })).toBe("/link1 /link2");
|
|
645
|
+
});
|
|
646
|
+
it("returns empty string for ctas with neither text nor actionLink", () => {
|
|
647
|
+
expect(extractContent({ ctas: [{}, { text: null }] })).toBe("");
|
|
648
|
+
});
|
|
649
|
+
it("returns all fields joined if all present", () => {
|
|
650
|
+
expect(extractContent({ title: "T", message: "M", ctas: [{ text: "C1" }, { actionLink: "C2" }] })).toBe("T M C1 C2");
|
|
651
|
+
});
|
|
652
|
+
it("handles ctas as empty array", () => {
|
|
653
|
+
expect(extractContent({ title: "T", message: "M", ctas: [] })).toBe("T M");
|
|
654
|
+
});
|
|
655
|
+
it("handles ctas as undefined", () => {
|
|
656
|
+
expect(extractContent({ title: "T", message: "M" })).toBe("T M");
|
|
221
657
|
});
|
|
222
658
|
});
|