@capillarytech/creatives-library 8.0.288 → 8.0.290-alpha.0
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/constants/unified.js +0 -1
- package/initialState.js +0 -2
- package/package.json +1 -1
- package/utils/common.js +5 -8
- package/utils/commonUtils.js +4 -85
- package/utils/tagValidations.js +84 -222
- package/utils/tests/commonUtil.test.js +461 -118
- package/utils/tests/tagValidations.test.js +280 -358
- package/v2Components/ErrorInfoNote/index.js +2 -5
- package/v2Components/FormBuilder/index.js +78 -161
- package/v2Components/FormBuilder/messages.js +0 -8
- package/v2Components/HtmlEditor/HTMLEditor.js +0 -5
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +0 -15
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +1 -2
- package/v2Containers/Cap/mockData.js +0 -14
- package/v2Containers/Cap/reducer.js +3 -55
- package/v2Containers/Cap/tests/reducer.test.js +0 -102
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
- package/v2Containers/CreativesContainer/index.js +19 -6
- package/v2Containers/Email/index.js +1 -5
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +10 -62
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +12 -115
- package/v2Containers/FTP/index.js +2 -51
- package/v2Containers/FTP/messages.js +0 -4
- package/v2Containers/InApp/index.js +1 -96
- package/v2Containers/InApp/tests/index.test.js +17 -6
- package/v2Containers/InappAdvance/index.js +2 -103
- package/v2Containers/Line/Container/Text/index.js +0 -1
- package/v2Containers/MobilePush/Create/index.js +6 -16
- package/v2Containers/MobilePush/Edit/index.js +6 -16
- package/v2Containers/MobilePushNew/index.js +2 -33
- package/v2Containers/Rcs/index.js +12 -37
- package/v2Containers/Sms/Create/index.js +31 -3
- package/v2Containers/Sms/Create/messages.js +4 -0
- package/v2Containers/Sms/Edit/index.js +29 -3
- package/v2Containers/Sms/commonMethods.js +6 -6
- package/v2Containers/SmsTrai/Edit/index.js +6 -47
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/Templates/reducer.js +3 -1
- package/v2Containers/Templates/tests/reducer.test.js +12 -0
- package/v2Containers/Viber/index.js +0 -1
- package/v2Containers/WebPush/Create/components/BrandIconSection.test.js +264 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/BrandIconSection.test.js.snap +187 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +1 -3
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -7
- package/v2Containers/WebPush/Create/index.js +2 -2
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +269 -0
- package/v2Containers/WebPush/Create/utils/validation.js +17 -2
- package/v2Containers/WebPush/Create/utils/validation.test.js +0 -24
- package/v2Containers/Whatsapp/index.js +9 -17
- package/v2Containers/Zalo/index.js +3 -11
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
extractContent,
|
|
7
7
|
addBaseToTemplate,
|
|
8
8
|
validateCarouselCards,
|
|
9
|
+
hasPersonalizationTags,
|
|
10
|
+
checkForPersonalizationTokens,
|
|
9
11
|
} from "../commonUtils";
|
|
10
12
|
import { skipTags } from "../tagValidations";
|
|
11
13
|
import { SMS_TRAI_VAR } from '../../v2Containers/SmsTrai/Edit/constants';
|
|
@@ -20,13 +22,17 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
20
22
|
somethingWentWrong: { id: "wrong" },
|
|
21
23
|
unsupportedTagsValidationError: { id: "unsupported" }
|
|
22
24
|
};
|
|
23
|
-
const tagLookupMap = { foo: true };
|
|
24
25
|
const eventContextTags = [{ tagName: "bar" }];
|
|
25
26
|
const onError = jest.fn();
|
|
26
27
|
const onSuccess = jest.fn();
|
|
27
28
|
|
|
28
29
|
beforeEach(() => {
|
|
29
30
|
jest.clearAllMocks();
|
|
31
|
+
formatMessage.mockImplementation((msg, vars) =>
|
|
32
|
+
vars && vars.unsupportedTags != null
|
|
33
|
+
? `${msg?.id}:${vars.unsupportedTags}`
|
|
34
|
+
: (msg?.id ?? "unsupported")
|
|
35
|
+
);
|
|
30
36
|
});
|
|
31
37
|
|
|
32
38
|
it("calls onError for empty content", async () => {
|
|
@@ -39,11 +45,10 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
39
45
|
messages,
|
|
40
46
|
onError,
|
|
41
47
|
onSuccess,
|
|
42
|
-
tagLookupMap,
|
|
43
48
|
eventContextTags
|
|
44
49
|
});
|
|
45
50
|
expect(onError).toHaveBeenCalledWith({
|
|
46
|
-
standardErrors: [
|
|
51
|
+
standardErrors: ["empty"],
|
|
47
52
|
liquidErrors: [],
|
|
48
53
|
tabType: undefined
|
|
49
54
|
});
|
|
@@ -58,7 +63,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
58
63
|
getLiquidTags,
|
|
59
64
|
formatMessage,
|
|
60
65
|
messages,
|
|
61
|
-
tagLookupMap,
|
|
62
66
|
eventContextTags
|
|
63
67
|
});
|
|
64
68
|
expect(onError).not.toHaveBeenCalled();
|
|
@@ -75,7 +79,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
75
79
|
messages,
|
|
76
80
|
onError,
|
|
77
81
|
onSuccess,
|
|
78
|
-
tagLookupMap,
|
|
79
82
|
eventContextTags
|
|
80
83
|
});
|
|
81
84
|
expect(onError).toHaveBeenCalledWith({
|
|
@@ -86,9 +89,149 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
86
89
|
expect(onSuccess).not.toHaveBeenCalled();
|
|
87
90
|
});
|
|
88
91
|
|
|
89
|
-
it("
|
|
92
|
+
it("categorizes errors as liquidErrors when isError=true with no result.errors (line 194-197)", async () => {
|
|
93
|
+
// isError=true + empty errors array → else-if (isError) branch → liquidErrors = [somethingWrongMsg]
|
|
94
|
+
// Use a plain function (not jest.fn) to avoid resetMocks:true wiping the implementation
|
|
95
|
+
const localFormatMessage = (msg) => msg?.id;
|
|
90
96
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
91
|
-
cb({ askAiraResponse: { errors: [], data: [
|
|
97
|
+
cb({ askAiraResponse: { errors: [], data: [] }, isError: true })
|
|
98
|
+
);
|
|
99
|
+
await validateLiquidTemplateContent("foo", {
|
|
100
|
+
getLiquidTags,
|
|
101
|
+
formatMessage: localFormatMessage,
|
|
102
|
+
messages,
|
|
103
|
+
onError,
|
|
104
|
+
onSuccess,
|
|
105
|
+
eventContextTags
|
|
106
|
+
});
|
|
107
|
+
expect(onError).toHaveBeenCalledWith({
|
|
108
|
+
standardErrors: [],
|
|
109
|
+
liquidErrors: ["wrong"],
|
|
110
|
+
tabType: undefined
|
|
111
|
+
});
|
|
112
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("falls back to somethingWentWrong when error.message is not a string (line 189-191)", async () => {
|
|
116
|
+
// error.message is an object, not a string → typeof check fails → returns somethingWrongMsg
|
|
117
|
+
const localFormatMessage = (msg) => msg?.id;
|
|
118
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
119
|
+
cb({ askAiraResponse: { errors: [{ message: { code: 123 } }], data: [] }, isError: false })
|
|
120
|
+
);
|
|
121
|
+
await validateLiquidTemplateContent("foo", {
|
|
122
|
+
getLiquidTags,
|
|
123
|
+
formatMessage: localFormatMessage,
|
|
124
|
+
messages,
|
|
125
|
+
onError,
|
|
126
|
+
onSuccess,
|
|
127
|
+
eventContextTags
|
|
128
|
+
});
|
|
129
|
+
expect(onError).toHaveBeenCalledWith({
|
|
130
|
+
standardErrors: [],
|
|
131
|
+
liquidErrors: ["wrong"],
|
|
132
|
+
tabType: undefined
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("falls back to somethingWentWrong when error.message is null (line 189-191)", async () => {
|
|
137
|
+
const localFormatMessage = (msg) => msg?.id;
|
|
138
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
139
|
+
cb({ askAiraResponse: { errors: [{ message: null }], data: [] }, isError: false })
|
|
140
|
+
);
|
|
141
|
+
await validateLiquidTemplateContent("foo", {
|
|
142
|
+
getLiquidTags,
|
|
143
|
+
formatMessage: localFormatMessage,
|
|
144
|
+
messages,
|
|
145
|
+
onError,
|
|
146
|
+
onSuccess,
|
|
147
|
+
eventContextTags
|
|
148
|
+
});
|
|
149
|
+
expect(onError).toHaveBeenCalledWith({
|
|
150
|
+
standardErrors: [],
|
|
151
|
+
liquidErrors: ["wrong"],
|
|
152
|
+
tabType: undefined
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("falls back to somethingWentWrong when error.message is undefined (line 189-191)", async () => {
|
|
157
|
+
const localFormatMessage = (msg) => msg?.id;
|
|
158
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
159
|
+
cb({ askAiraResponse: { errors: [{}], data: [] }, isError: false })
|
|
160
|
+
);
|
|
161
|
+
await validateLiquidTemplateContent("foo", {
|
|
162
|
+
getLiquidTags,
|
|
163
|
+
formatMessage: localFormatMessage,
|
|
164
|
+
messages,
|
|
165
|
+
onError,
|
|
166
|
+
onSuccess,
|
|
167
|
+
eventContextTags
|
|
168
|
+
});
|
|
169
|
+
expect(onError).toHaveBeenCalledWith({
|
|
170
|
+
standardErrors: [],
|
|
171
|
+
liquidErrors: ["wrong"],
|
|
172
|
+
tabType: undefined
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("maps multiple errors with mixed string/non-string messages (line 188-193)", async () => {
|
|
177
|
+
const localFormatMessage = (msg) => msg?.id;
|
|
178
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
179
|
+
cb({
|
|
180
|
+
askAiraResponse: {
|
|
181
|
+
errors: [
|
|
182
|
+
{ message: "First error" },
|
|
183
|
+
{ message: null },
|
|
184
|
+
{ message: "Third error" },
|
|
185
|
+
],
|
|
186
|
+
data: [],
|
|
187
|
+
},
|
|
188
|
+
isError: false,
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
await validateLiquidTemplateContent("foo", {
|
|
192
|
+
getLiquidTags,
|
|
193
|
+
formatMessage: localFormatMessage,
|
|
194
|
+
messages,
|
|
195
|
+
onError,
|
|
196
|
+
onSuccess,
|
|
197
|
+
eventContextTags
|
|
198
|
+
});
|
|
199
|
+
expect(onError).toHaveBeenCalledWith({
|
|
200
|
+
standardErrors: [],
|
|
201
|
+
liquidErrors: ["First error", "wrong", "Third error"],
|
|
202
|
+
tabType: undefined
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("prefers result.errors over isError when both are present (result.errors takes the if-branch)", async () => {
|
|
207
|
+
// Both errors array AND isError=true → the if-branch (line 186) wins over else-if (line 194)
|
|
208
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
209
|
+
cb({ askAiraResponse: { errors: [{ message: "from errors array" }], data: [] }, isError: true })
|
|
210
|
+
);
|
|
211
|
+
await validateLiquidTemplateContent("foo", {
|
|
212
|
+
getLiquidTags,
|
|
213
|
+
formatMessage,
|
|
214
|
+
messages,
|
|
215
|
+
onError,
|
|
216
|
+
onSuccess,
|
|
217
|
+
eventContextTags
|
|
218
|
+
});
|
|
219
|
+
expect(onError).toHaveBeenCalledWith({
|
|
220
|
+
standardErrors: [],
|
|
221
|
+
liquidErrors: ["from errors array"],
|
|
222
|
+
tabType: undefined
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("calls onError when API returns success but response.errors has validation errors (e.g. unsupported tag)", async () => {
|
|
227
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
228
|
+
cb({
|
|
229
|
+
askAiraResponse: {
|
|
230
|
+
errors: [{ message: "Unsupported tag: custom_tag" }],
|
|
231
|
+
data: []
|
|
232
|
+
},
|
|
233
|
+
isError: false
|
|
234
|
+
})
|
|
92
235
|
);
|
|
93
236
|
await validateLiquidTemplateContent("foo", {
|
|
94
237
|
getLiquidTags,
|
|
@@ -96,18 +239,33 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
96
239
|
messages,
|
|
97
240
|
onError,
|
|
98
241
|
onSuccess,
|
|
99
|
-
tagLookupMap,
|
|
100
242
|
eventContextTags
|
|
101
243
|
});
|
|
102
244
|
expect(onError).toHaveBeenCalledWith({
|
|
103
245
|
standardErrors: [],
|
|
104
|
-
liquidErrors: [
|
|
246
|
+
liquidErrors: ["Unsupported tag: custom_tag"],
|
|
105
247
|
tabType: undefined
|
|
106
248
|
});
|
|
107
249
|
expect(onSuccess).not.toHaveBeenCalled();
|
|
108
250
|
});
|
|
109
251
|
|
|
110
|
-
it("calls onSuccess
|
|
252
|
+
it("calls onSuccess when API returns no errors and a single extracted tag (extracted tags are not validated)", async () => {
|
|
253
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
254
|
+
cb({ askAiraResponse: { errors: [], data: [{ name: "foo" }] }, isError: false })
|
|
255
|
+
);
|
|
256
|
+
await validateLiquidTemplateContent("foo", {
|
|
257
|
+
getLiquidTags,
|
|
258
|
+
formatMessage,
|
|
259
|
+
messages,
|
|
260
|
+
onError,
|
|
261
|
+
onSuccess,
|
|
262
|
+
eventContextTags
|
|
263
|
+
});
|
|
264
|
+
expect(onSuccess).toHaveBeenCalledWith("foo", undefined);
|
|
265
|
+
expect(onError).not.toHaveBeenCalled();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("calls onSuccess for valid content when API returns multiple extracted tags but no errors", async () => {
|
|
111
269
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
112
270
|
cb({ askAiraResponse: { errors: [], data: [{ name: "foo" }, { name: "bar" }] }, isError: false })
|
|
113
271
|
);
|
|
@@ -117,7 +275,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
117
275
|
messages,
|
|
118
276
|
onError,
|
|
119
277
|
onSuccess,
|
|
120
|
-
tagLookupMap,
|
|
121
278
|
eventContextTags
|
|
122
279
|
});
|
|
123
280
|
expect(onSuccess).toHaveBeenCalledWith("foo", undefined);
|
|
@@ -133,7 +290,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
133
290
|
messages,
|
|
134
291
|
onError,
|
|
135
292
|
onSuccess,
|
|
136
|
-
tagLookupMap,
|
|
137
293
|
eventContextTags,
|
|
138
294
|
skipTags
|
|
139
295
|
});
|
|
@@ -151,7 +307,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
151
307
|
messages,
|
|
152
308
|
onError,
|
|
153
309
|
onSuccess,
|
|
154
|
-
tagLookupMap,
|
|
155
310
|
eventContextTags,
|
|
156
311
|
skipTags
|
|
157
312
|
});
|
|
@@ -169,7 +324,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
169
324
|
messages,
|
|
170
325
|
onError,
|
|
171
326
|
onSuccess,
|
|
172
|
-
tagLookupMap,
|
|
173
327
|
eventContextTags,
|
|
174
328
|
skipTags
|
|
175
329
|
});
|
|
@@ -187,7 +341,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
187
341
|
messages,
|
|
188
342
|
onError,
|
|
189
343
|
onSuccess,
|
|
190
|
-
tagLookupMap,
|
|
191
344
|
eventContextTags,
|
|
192
345
|
skipTags
|
|
193
346
|
});
|
|
@@ -205,7 +358,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
205
358
|
messages,
|
|
206
359
|
onError,
|
|
207
360
|
onSuccess,
|
|
208
|
-
tagLookupMap,
|
|
209
361
|
eventContextTags,
|
|
210
362
|
skipTags
|
|
211
363
|
});
|
|
@@ -223,7 +375,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
223
375
|
messages,
|
|
224
376
|
onError,
|
|
225
377
|
onSuccess,
|
|
226
|
-
tagLookupMap,
|
|
227
378
|
eventContextTags,
|
|
228
379
|
skipTags
|
|
229
380
|
});
|
|
@@ -241,7 +392,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
241
392
|
messages,
|
|
242
393
|
onError,
|
|
243
394
|
onSuccess,
|
|
244
|
-
tagLookupMap,
|
|
245
395
|
eventContextTags,
|
|
246
396
|
skipTags
|
|
247
397
|
});
|
|
@@ -259,7 +409,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
259
409
|
messages,
|
|
260
410
|
onError,
|
|
261
411
|
onSuccess,
|
|
262
|
-
tagLookupMap,
|
|
263
412
|
eventContextTags,
|
|
264
413
|
skipTags
|
|
265
414
|
});
|
|
@@ -277,7 +426,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
277
426
|
};
|
|
278
427
|
const onError = jest.fn();
|
|
279
428
|
const onSuccess = jest.fn();
|
|
280
|
-
const tagLookupMap = {};
|
|
281
429
|
const eventContextTags = [];
|
|
282
430
|
await validateLiquidTemplateContent('', {
|
|
283
431
|
getLiquidTags,
|
|
@@ -285,7 +433,6 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
285
433
|
messages,
|
|
286
434
|
onError,
|
|
287
435
|
onSuccess,
|
|
288
|
-
tagLookupMap,
|
|
289
436
|
eventContextTags,
|
|
290
437
|
});
|
|
291
438
|
expect(formatMessage).toHaveBeenCalledWith(messages.emailBodyEmptyError);
|
|
@@ -297,7 +444,7 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
297
444
|
expect(onSuccess).not.toHaveBeenCalled();
|
|
298
445
|
});
|
|
299
446
|
|
|
300
|
-
it("
|
|
447
|
+
it("calls onSuccess when API returns extracted tags from {% for %} template but no errors (extracted tags are not validated)", async () => {
|
|
301
448
|
const content = '{% for item in order.items %} Hello {% endfor %}';
|
|
302
449
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
303
450
|
cb({ askAiraResponse: { errors: [], data: [{ name: "order.items" }] }, isError: false })
|
|
@@ -308,15 +455,13 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
308
455
|
messages,
|
|
309
456
|
onError,
|
|
310
457
|
onSuccess,
|
|
311
|
-
tagLookupMap,
|
|
312
458
|
eventContextTags
|
|
313
459
|
});
|
|
314
|
-
// order.items appears in {% %} syntax, so it should be skipped and validation should pass
|
|
315
460
|
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
316
461
|
expect(onError).not.toHaveBeenCalled();
|
|
317
462
|
});
|
|
318
463
|
|
|
319
|
-
it("
|
|
464
|
+
it("calls onSuccess when API returns extracted tags in {% %} blocks but no errors", async () => {
|
|
320
465
|
const content = '{% for item in order.items %} {{ item.name }} - {{ item.quantity }} {% endfor %}';
|
|
321
466
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
322
467
|
cb({ askAiraResponse: { errors: [], data: [{ name: "item.name" }, { name: "item.quantity" }] }, isError: false })
|
|
@@ -327,15 +472,13 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
327
472
|
messages,
|
|
328
473
|
onError,
|
|
329
474
|
onSuccess,
|
|
330
|
-
tagLookupMap,
|
|
331
475
|
eventContextTags
|
|
332
476
|
});
|
|
333
|
-
// item.name and item.quantity appear inside {% for %} block, so they should be skipped
|
|
334
477
|
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
335
478
|
expect(onError).not.toHaveBeenCalled();
|
|
336
479
|
});
|
|
337
480
|
|
|
338
|
-
it("
|
|
481
|
+
it("calls onSuccess when API returns extracted tags not in content but no errors", async () => {
|
|
339
482
|
const content = 'Some content without the tag';
|
|
340
483
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
341
484
|
cb({ askAiraResponse: { errors: [], data: [{ name: "extractedTag" }] }, isError: false })
|
|
@@ -346,19 +489,13 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
346
489
|
messages,
|
|
347
490
|
onError,
|
|
348
491
|
onSuccess,
|
|
349
|
-
tagLookupMap,
|
|
350
492
|
eventContextTags
|
|
351
493
|
});
|
|
352
|
-
|
|
353
|
-
expect(onError).
|
|
354
|
-
standardErrors: [],
|
|
355
|
-
liquidErrors: [undefined],
|
|
356
|
-
tabType: undefined
|
|
357
|
-
});
|
|
358
|
-
expect(onSuccess).not.toHaveBeenCalled();
|
|
494
|
+
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
495
|
+
expect(onError).not.toHaveBeenCalled();
|
|
359
496
|
});
|
|
360
497
|
|
|
361
|
-
it("
|
|
498
|
+
it("calls onSuccess when API returns tags outside {% %} but no errors", async () => {
|
|
362
499
|
const content = '{{ outsideTag }} {% for item in order.items %} {{ item.name }} {% endfor %}';
|
|
363
500
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
364
501
|
cb({ askAiraResponse: { errors: [], data: [{ name: "outsideTag" }, { name: "item.name" }] }, isError: false })
|
|
@@ -369,20 +506,70 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
369
506
|
messages,
|
|
370
507
|
onError,
|
|
371
508
|
onSuccess,
|
|
372
|
-
tagLookupMap,
|
|
373
509
|
eventContextTags
|
|
374
510
|
});
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
511
|
+
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
512
|
+
expect(onError).not.toHaveBeenCalled();
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
it("calls onSuccess when API returns tag in {{ }} and no errors", async () => {
|
|
516
|
+
const content = 'Hello {{ unsupportedTag }} world';
|
|
517
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
518
|
+
cb({ askAiraResponse: { errors: [], data: [{ name: "unsupportedTag" }] }, isError: false })
|
|
519
|
+
);
|
|
520
|
+
await validateLiquidTemplateContent(content, {
|
|
521
|
+
getLiquidTags,
|
|
522
|
+
formatMessage,
|
|
523
|
+
messages,
|
|
524
|
+
onError,
|
|
525
|
+
onSuccess,
|
|
526
|
+
eventContextTags
|
|
381
527
|
});
|
|
382
|
-
expect(onSuccess).
|
|
528
|
+
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
529
|
+
expect(onError).not.toHaveBeenCalled();
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
it("calls onSuccess when API returns tag with spacing variants and no errors", async () => {
|
|
533
|
+
const content = '{{ tag}} and {{tag }} and {{ tag }}';
|
|
534
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
535
|
+
cb({
|
|
536
|
+
askAiraResponse: {
|
|
537
|
+
errors: [],
|
|
538
|
+
data: [{ name: "tag" }]
|
|
539
|
+
},
|
|
540
|
+
isError: false
|
|
541
|
+
})
|
|
542
|
+
);
|
|
543
|
+
await validateLiquidTemplateContent(content, {
|
|
544
|
+
getLiquidTags,
|
|
545
|
+
formatMessage,
|
|
546
|
+
messages,
|
|
547
|
+
onError,
|
|
548
|
+
onSuccess,
|
|
549
|
+
eventContextTags
|
|
550
|
+
});
|
|
551
|
+
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
552
|
+
expect(onError).not.toHaveBeenCalled();
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it("calls onSuccess when API returns tag inside {% %} blocks but no errors", async () => {
|
|
556
|
+
const content = '{% for x in some.unsupported %} {{ x }} {% endfor %}';
|
|
557
|
+
const getLiquidTags = jest.fn((content, cb) =>
|
|
558
|
+
cb({ askAiraResponse: { errors: [], data: [{ name: "some.unsupported" }] }, isError: false })
|
|
559
|
+
);
|
|
560
|
+
await validateLiquidTemplateContent(content, {
|
|
561
|
+
getLiquidTags,
|
|
562
|
+
formatMessage,
|
|
563
|
+
messages,
|
|
564
|
+
onError,
|
|
565
|
+
onSuccess,
|
|
566
|
+
eventContextTags
|
|
567
|
+
});
|
|
568
|
+
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
569
|
+
expect(onError).not.toHaveBeenCalled();
|
|
383
570
|
});
|
|
384
571
|
|
|
385
|
-
it("
|
|
572
|
+
it("calls onSuccess when API returns tags with dots in {% %} syntax but no errors", async () => {
|
|
386
573
|
const content = '{% assign myVar = order.items %} Some text';
|
|
387
574
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
388
575
|
cb({ askAiraResponse: { errors: [], data: [{ name: "order.items" }] }, isError: false })
|
|
@@ -393,10 +580,8 @@ describe("validateLiquidTemplateContent", () => {
|
|
|
393
580
|
messages,
|
|
394
581
|
onError,
|
|
395
582
|
onSuccess,
|
|
396
|
-
tagLookupMap,
|
|
397
583
|
eventContextTags
|
|
398
584
|
});
|
|
399
|
-
// order.items appears in {% %} syntax, so it should be skipped
|
|
400
585
|
expect(onSuccess).toHaveBeenCalledWith(content, undefined);
|
|
401
586
|
expect(onError).not.toHaveBeenCalled();
|
|
402
587
|
});
|
|
@@ -451,7 +636,6 @@ describe("validateMobilePushContent", () => {
|
|
|
451
636
|
somethingWentWrong: { id: "wrong" },
|
|
452
637
|
unsupportedTagsValidationError: { id: "unsupported" }
|
|
453
638
|
};
|
|
454
|
-
const tagLookupMap = { foo: true };
|
|
455
639
|
const eventContextTags = [{ tagName: "foo" }];
|
|
456
640
|
const onError = jest.fn();
|
|
457
641
|
const onSuccess = jest.fn();
|
|
@@ -460,7 +644,7 @@ describe("validateMobilePushContent", () => {
|
|
|
460
644
|
jest.clearAllMocks();
|
|
461
645
|
});
|
|
462
646
|
|
|
463
|
-
it("calls onError for empty formData", async () => {
|
|
647
|
+
it("calls onError for empty formData (validateMobilePushContent)", async () => {
|
|
464
648
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
465
649
|
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
466
650
|
);
|
|
@@ -469,18 +653,17 @@ describe("validateMobilePushContent", () => {
|
|
|
469
653
|
{
|
|
470
654
|
getLiquidTags,
|
|
471
655
|
formatMessage,
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
eventContextTags,
|
|
656
|
+
messages,
|
|
657
|
+
onError,
|
|
658
|
+
onSuccess,
|
|
659
|
+
eventContextTags,
|
|
477
660
|
currentTab: 1
|
|
478
661
|
}
|
|
479
662
|
);
|
|
480
663
|
expect(onError).toHaveBeenCalled();
|
|
481
664
|
});
|
|
482
665
|
|
|
483
|
-
it("calls onSuccess for valid android and ios content", async () => {
|
|
666
|
+
it("calls onSuccess for valid android and ios content (validateMobilePushContent)", async () => {
|
|
484
667
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
485
668
|
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
486
669
|
);
|
|
@@ -491,7 +674,6 @@ describe("validateMobilePushContent", () => {
|
|
|
491
674
|
messages,
|
|
492
675
|
onError,
|
|
493
676
|
onSuccess,
|
|
494
|
-
tagLookupMap,
|
|
495
677
|
eventContextTags,
|
|
496
678
|
currentTab: 1
|
|
497
679
|
});
|
|
@@ -509,7 +691,6 @@ describe("validateMobilePushContent", () => {
|
|
|
509
691
|
messages,
|
|
510
692
|
onError,
|
|
511
693
|
onSuccess,
|
|
512
|
-
tagLookupMap,
|
|
513
694
|
eventContextTags,
|
|
514
695
|
currentTab: 1
|
|
515
696
|
});
|
|
@@ -527,7 +708,6 @@ describe("validateMobilePushContent", () => {
|
|
|
527
708
|
messages,
|
|
528
709
|
onError,
|
|
529
710
|
onSuccess,
|
|
530
|
-
tagLookupMap,
|
|
531
711
|
eventContextTags,
|
|
532
712
|
currentTab: 2
|
|
533
713
|
});
|
|
@@ -545,7 +725,6 @@ describe("validateMobilePushContent", () => {
|
|
|
545
725
|
messages,
|
|
546
726
|
onError,
|
|
547
727
|
onSuccess,
|
|
548
|
-
tagLookupMap,
|
|
549
728
|
eventContextTags
|
|
550
729
|
});
|
|
551
730
|
expect(onSuccess).toHaveBeenCalledWith(JSON.stringify(formData[0]), "android");
|
|
@@ -562,7 +741,6 @@ describe("validateMobilePushContent", () => {
|
|
|
562
741
|
messages,
|
|
563
742
|
onError,
|
|
564
743
|
onSuccess,
|
|
565
|
-
tagLookupMap,
|
|
566
744
|
eventContextTags
|
|
567
745
|
});
|
|
568
746
|
expect(onSuccess).toHaveBeenCalledWith("null", "android");
|
|
@@ -575,11 +753,10 @@ describe("validateMobilePushContent", () => {
|
|
|
575
753
|
{
|
|
576
754
|
getLiquidTags,
|
|
577
755
|
formatMessage,
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
eventContextTags,
|
|
756
|
+
messages,
|
|
757
|
+
onError,
|
|
758
|
+
onSuccess,
|
|
759
|
+
eventContextTags,
|
|
583
760
|
currentTab: 1,
|
|
584
761
|
},
|
|
585
762
|
);
|
|
@@ -593,11 +770,10 @@ describe("validateMobilePushContent", () => {
|
|
|
593
770
|
{
|
|
594
771
|
getLiquidTags,
|
|
595
772
|
formatMessage,
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
eventContextTags,
|
|
773
|
+
messages,
|
|
774
|
+
onError,
|
|
775
|
+
onSuccess,
|
|
776
|
+
eventContextTags,
|
|
601
777
|
currentTab: 1,
|
|
602
778
|
},
|
|
603
779
|
);
|
|
@@ -611,11 +787,10 @@ describe("validateMobilePushContent", () => {
|
|
|
611
787
|
{
|
|
612
788
|
getLiquidTags,
|
|
613
789
|
formatMessage,
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
eventContextTags,
|
|
790
|
+
messages,
|
|
791
|
+
onError,
|
|
792
|
+
onSuccess,
|
|
793
|
+
eventContextTags,
|
|
619
794
|
currentTab: 1,
|
|
620
795
|
},
|
|
621
796
|
);
|
|
@@ -629,11 +804,10 @@ describe("validateMobilePushContent", () => {
|
|
|
629
804
|
{
|
|
630
805
|
getLiquidTags,
|
|
631
806
|
formatMessage,
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
eventContextTags,
|
|
807
|
+
messages,
|
|
808
|
+
onError,
|
|
809
|
+
onSuccess,
|
|
810
|
+
eventContextTags,
|
|
637
811
|
currentTab: 1,
|
|
638
812
|
},
|
|
639
813
|
);
|
|
@@ -647,11 +821,10 @@ describe("validateMobilePushContent", () => {
|
|
|
647
821
|
{
|
|
648
822
|
getLiquidTags,
|
|
649
823
|
formatMessage,
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
eventContextTags,
|
|
824
|
+
messages,
|
|
825
|
+
onError,
|
|
826
|
+
onSuccess,
|
|
827
|
+
eventContextTags,
|
|
655
828
|
},
|
|
656
829
|
);
|
|
657
830
|
expect(onError).toHaveBeenCalled();
|
|
@@ -664,11 +837,10 @@ describe("validateMobilePushContent", () => {
|
|
|
664
837
|
{
|
|
665
838
|
getLiquidTags,
|
|
666
839
|
formatMessage,
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
eventContextTags,
|
|
840
|
+
messages,
|
|
841
|
+
onError,
|
|
842
|
+
onSuccess,
|
|
843
|
+
eventContextTags,
|
|
672
844
|
},
|
|
673
845
|
);
|
|
674
846
|
expect(onError).toHaveBeenCalled();
|
|
@@ -681,11 +853,10 @@ describe("validateMobilePushContent", () => {
|
|
|
681
853
|
{
|
|
682
854
|
getLiquidTags,
|
|
683
855
|
formatMessage,
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
eventContextTags,
|
|
856
|
+
messages,
|
|
857
|
+
onError,
|
|
858
|
+
onSuccess,
|
|
859
|
+
eventContextTags,
|
|
689
860
|
},
|
|
690
861
|
);
|
|
691
862
|
expect(onError).toHaveBeenCalled();
|
|
@@ -698,11 +869,10 @@ describe("validateMobilePushContent", () => {
|
|
|
698
869
|
{
|
|
699
870
|
getLiquidTags,
|
|
700
871
|
formatMessage,
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
eventContextTags,
|
|
872
|
+
messages,
|
|
873
|
+
onError,
|
|
874
|
+
onSuccess,
|
|
875
|
+
eventContextTags,
|
|
706
876
|
},
|
|
707
877
|
);
|
|
708
878
|
expect(onError).toHaveBeenCalled();
|
|
@@ -715,11 +885,10 @@ describe("validateMobilePushContent", () => {
|
|
|
715
885
|
{
|
|
716
886
|
getLiquidTags,
|
|
717
887
|
formatMessage,
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
eventContextTags,
|
|
888
|
+
messages,
|
|
889
|
+
onError,
|
|
890
|
+
onSuccess,
|
|
891
|
+
eventContextTags,
|
|
723
892
|
},
|
|
724
893
|
);
|
|
725
894
|
expect(onError).toHaveBeenCalled();
|
|
@@ -733,7 +902,6 @@ describe("validateInAppContent", () => {
|
|
|
733
902
|
somethingWentWrong: { id: "wrong" },
|
|
734
903
|
unsupportedTagsValidationError: { id: "unsupported" }
|
|
735
904
|
};
|
|
736
|
-
const tagLookupMap = { foo: true };
|
|
737
905
|
const eventContextTags = [{ tagName: "foo" }];
|
|
738
906
|
const onError = jest.fn();
|
|
739
907
|
const onSuccess = jest.fn();
|
|
@@ -742,7 +910,7 @@ describe("validateInAppContent", () => {
|
|
|
742
910
|
jest.clearAllMocks();
|
|
743
911
|
});
|
|
744
912
|
|
|
745
|
-
it("calls onError for empty formData", async () => {
|
|
913
|
+
it("calls onError for empty formData (validateInAppContent)", async () => {
|
|
746
914
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
747
915
|
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
748
916
|
);
|
|
@@ -751,17 +919,16 @@ describe("validateInAppContent", () => {
|
|
|
751
919
|
{
|
|
752
920
|
getLiquidTags,
|
|
753
921
|
formatMessage,
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
eventContextTags,
|
|
922
|
+
messages,
|
|
923
|
+
onError,
|
|
924
|
+
onSuccess,
|
|
925
|
+
eventContextTags,
|
|
759
926
|
}
|
|
760
927
|
);
|
|
761
928
|
expect(onError).toHaveBeenCalled();
|
|
762
929
|
});
|
|
763
930
|
|
|
764
|
-
it("calls onSuccess for valid android and ios content", async () => {
|
|
931
|
+
it("calls onSuccess for valid android and ios content (validateInAppContent)", async () => {
|
|
765
932
|
const getLiquidTags = jest.fn((content, cb) =>
|
|
766
933
|
cb({ askAiraResponse: { errors: [], data: [] }, isError: false })
|
|
767
934
|
);
|
|
@@ -781,7 +948,6 @@ describe("validateInAppContent", () => {
|
|
|
781
948
|
messages,
|
|
782
949
|
onError,
|
|
783
950
|
onSuccess,
|
|
784
|
-
tagLookupMap,
|
|
785
951
|
eventContextTags,
|
|
786
952
|
singleTab: ANDROID,
|
|
787
953
|
});
|
|
@@ -808,7 +974,6 @@ describe("validateInAppContent", () => {
|
|
|
808
974
|
messages,
|
|
809
975
|
onError,
|
|
810
976
|
onSuccess,
|
|
811
|
-
tagLookupMap,
|
|
812
977
|
eventContextTags,
|
|
813
978
|
singleTab: IOS,
|
|
814
979
|
});
|
|
@@ -835,11 +1000,11 @@ describe("getChannelData", () => {
|
|
|
835
1000
|
expect(getChannelData("SMS", formData)).toBe("Hi Test");
|
|
836
1001
|
});
|
|
837
1002
|
|
|
838
|
-
it("returns string with undefineds for SMS
|
|
1003
|
+
it("returns string with undefineds for SMS when base and template-name are empty or undefined", () => {
|
|
839
1004
|
const formData = { base: {}, "template-name": undefined };
|
|
840
1005
|
expect(getChannelData("SMS", formData)).toBe("undefined undefined");
|
|
841
1006
|
});
|
|
842
|
-
it("returns string with undefineds for SMS
|
|
1007
|
+
it("returns string with undefineds for SMS when formData is empty string", () => {
|
|
843
1008
|
expect(getChannelData("SMS", "")).toBe("undefined undefined");
|
|
844
1009
|
});
|
|
845
1010
|
|
|
@@ -1601,3 +1766,181 @@ describe("validateCarouselCards", () => {
|
|
|
1601
1766
|
});
|
|
1602
1767
|
});
|
|
1603
1768
|
|
|
1769
|
+
describe('hasPersonalizationTags', () => {
|
|
1770
|
+
describe('liquid tags {{ }}', () => {
|
|
1771
|
+
it('returns true when text contains a liquid tag', () => {
|
|
1772
|
+
expect(hasPersonalizationTags('Hello {{user.name}}')).toBe(true);
|
|
1773
|
+
});
|
|
1774
|
+
|
|
1775
|
+
it('returns true for text with only opening and closing braces', () => {
|
|
1776
|
+
expect(hasPersonalizationTags('{{}}')).toBe(true);
|
|
1777
|
+
});
|
|
1778
|
+
|
|
1779
|
+
it('returns false when only {{ is present without }}', () => {
|
|
1780
|
+
expect(hasPersonalizationTags('Hello {{user.name')).toBeFalsy();
|
|
1781
|
+
});
|
|
1782
|
+
|
|
1783
|
+
it('returns false when only }} is present without {{', () => {
|
|
1784
|
+
expect(hasPersonalizationTags('Hello user.name}}')).toBeFalsy();
|
|
1785
|
+
});
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1788
|
+
describe('event context tags [ ]', () => {
|
|
1789
|
+
it('returns true when text contains square bracket tags', () => {
|
|
1790
|
+
expect(hasPersonalizationTags('Hello [first_name]')).toBe(true);
|
|
1791
|
+
});
|
|
1792
|
+
|
|
1793
|
+
it('returns true for text with only [ ]', () => {
|
|
1794
|
+
expect(hasPersonalizationTags('[]')).toBe(true);
|
|
1795
|
+
});
|
|
1796
|
+
|
|
1797
|
+
it('returns false when only [ is present without ]', () => {
|
|
1798
|
+
expect(hasPersonalizationTags('Hello [first_name')).toBeFalsy();
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
it('returns false when only ] is present without [', () => {
|
|
1802
|
+
expect(hasPersonalizationTags('Hello first_name]')).toBeFalsy();
|
|
1803
|
+
});
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
describe('both tag types', () => {
|
|
1807
|
+
it('returns true when text contains both liquid and square bracket tags', () => {
|
|
1808
|
+
expect(hasPersonalizationTags('{{title}} and [body]')).toBe(true);
|
|
1809
|
+
});
|
|
1810
|
+
});
|
|
1811
|
+
|
|
1812
|
+
describe('edge cases', () => {
|
|
1813
|
+
it('returns falsy for empty string (default parameter)', () => {
|
|
1814
|
+
expect(hasPersonalizationTags()).toBeFalsy();
|
|
1815
|
+
});
|
|
1816
|
+
|
|
1817
|
+
it('returns falsy for empty string argument', () => {
|
|
1818
|
+
expect(hasPersonalizationTags('')).toBeFalsy();
|
|
1819
|
+
});
|
|
1820
|
+
|
|
1821
|
+
it('returns falsy for plain text with no tokens', () => {
|
|
1822
|
+
expect(hasPersonalizationTags('Hello World')).toBeFalsy();
|
|
1823
|
+
});
|
|
1824
|
+
|
|
1825
|
+
it('returns falsy for null', () => {
|
|
1826
|
+
expect(hasPersonalizationTags(null)).toBeFalsy();
|
|
1827
|
+
});
|
|
1828
|
+
|
|
1829
|
+
it('returns falsy for undefined', () => {
|
|
1830
|
+
expect(hasPersonalizationTags(undefined)).toBeFalsy();
|
|
1831
|
+
});
|
|
1832
|
+
});
|
|
1833
|
+
});
|
|
1834
|
+
|
|
1835
|
+
describe('checkForPersonalizationTokens', () => {
|
|
1836
|
+
describe('liquid tags {{ }}', () => {
|
|
1837
|
+
it('returns true when a field contains a liquid tag', () => {
|
|
1838
|
+
const formData = {
|
|
1839
|
+
tab1: { title: 'Hello {{user.name}}' },
|
|
1840
|
+
};
|
|
1841
|
+
expect(checkForPersonalizationTokens(formData)).toBe(true);
|
|
1842
|
+
});
|
|
1843
|
+
|
|
1844
|
+
it('returns true for multiline liquid tag spanning field value', () => {
|
|
1845
|
+
const formData = {
|
|
1846
|
+
tab1: { body: '{{user\n.name}}' },
|
|
1847
|
+
};
|
|
1848
|
+
expect(checkForPersonalizationTokens(formData)).toBe(true);
|
|
1849
|
+
});
|
|
1850
|
+
});
|
|
1851
|
+
|
|
1852
|
+
describe('event context tags [ ]', () => {
|
|
1853
|
+
it('returns true when a field contains a square bracket token', () => {
|
|
1854
|
+
const formData = {
|
|
1855
|
+
tab1: { message: 'Hi [first_name]' },
|
|
1856
|
+
};
|
|
1857
|
+
expect(checkForPersonalizationTokens(formData)).toBe(true);
|
|
1858
|
+
});
|
|
1859
|
+
|
|
1860
|
+
it('returns true for multiline square bracket token', () => {
|
|
1861
|
+
const formData = {
|
|
1862
|
+
tab1: { body: '[first\nname]' },
|
|
1863
|
+
};
|
|
1864
|
+
expect(checkForPersonalizationTokens(formData)).toBe(true);
|
|
1865
|
+
});
|
|
1866
|
+
});
|
|
1867
|
+
|
|
1868
|
+
describe('multiple tabs / fields', () => {
|
|
1869
|
+
it('returns true when token is in a nested tab other than the first', () => {
|
|
1870
|
+
const formData = {
|
|
1871
|
+
tab1: { title: 'plain text' },
|
|
1872
|
+
tab2: { body: 'Hello {{name}}' },
|
|
1873
|
+
};
|
|
1874
|
+
expect(checkForPersonalizationTokens(formData)).toBe(true);
|
|
1875
|
+
});
|
|
1876
|
+
|
|
1877
|
+
it('returns true when token is in a field other than the first in a tab', () => {
|
|
1878
|
+
const formData = {
|
|
1879
|
+
tab1: { title: 'plain text', body: '[event_tag]' },
|
|
1880
|
+
};
|
|
1881
|
+
expect(checkForPersonalizationTokens(formData)).toBe(true);
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
it('returns false when no field in any tab has a token', () => {
|
|
1885
|
+
const formData = {
|
|
1886
|
+
tab1: { title: 'Hello World', body: 'No tokens here' },
|
|
1887
|
+
tab2: { title: 'Also plain', body: 'Still plain' },
|
|
1888
|
+
};
|
|
1889
|
+
expect(checkForPersonalizationTokens(formData)).toBe(false);
|
|
1890
|
+
});
|
|
1891
|
+
});
|
|
1892
|
+
|
|
1893
|
+
describe('non-string field values', () => {
|
|
1894
|
+
it('ignores numeric field values', () => {
|
|
1895
|
+
const formData = {
|
|
1896
|
+
tab1: { count: 42 },
|
|
1897
|
+
};
|
|
1898
|
+
expect(checkForPersonalizationTokens(formData)).toBe(false);
|
|
1899
|
+
});
|
|
1900
|
+
|
|
1901
|
+
it('ignores boolean field values', () => {
|
|
1902
|
+
const formData = {
|
|
1903
|
+
tab1: { enabled: true },
|
|
1904
|
+
};
|
|
1905
|
+
expect(checkForPersonalizationTokens(formData)).toBe(false);
|
|
1906
|
+
});
|
|
1907
|
+
|
|
1908
|
+
it('ignores null field values', () => {
|
|
1909
|
+
const formData = {
|
|
1910
|
+
tab1: { title: null },
|
|
1911
|
+
};
|
|
1912
|
+
expect(checkForPersonalizationTokens(formData)).toBe(false);
|
|
1913
|
+
});
|
|
1914
|
+
|
|
1915
|
+
it('ignores nested object field values (only one level deep)', () => {
|
|
1916
|
+
const formData = {
|
|
1917
|
+
tab1: { nested: { title: '{{token}}' } },
|
|
1918
|
+
};
|
|
1919
|
+
expect(checkForPersonalizationTokens(formData)).toBe(false);
|
|
1920
|
+
});
|
|
1921
|
+
});
|
|
1922
|
+
|
|
1923
|
+
describe('edge cases', () => {
|
|
1924
|
+
it('returns false for null input', () => {
|
|
1925
|
+
expect(checkForPersonalizationTokens(null)).toBe(false);
|
|
1926
|
+
});
|
|
1927
|
+
|
|
1928
|
+
it('returns false for undefined input', () => {
|
|
1929
|
+
expect(checkForPersonalizationTokens(undefined)).toBe(false);
|
|
1930
|
+
});
|
|
1931
|
+
|
|
1932
|
+
it('returns false for empty object', () => {
|
|
1933
|
+
expect(checkForPersonalizationTokens({})).toBe(false);
|
|
1934
|
+
});
|
|
1935
|
+
|
|
1936
|
+
it('returns false for non-object input (string)', () => {
|
|
1937
|
+
expect(checkForPersonalizationTokens('{{token}}')).toBe(false);
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
it('returns false when tab value is not an object', () => {
|
|
1941
|
+
const formData = { tab1: '{{token}}' };
|
|
1942
|
+
expect(checkForPersonalizationTokens(formData)).toBe(false);
|
|
1943
|
+
});
|
|
1944
|
+
});
|
|
1945
|
+
});
|
|
1946
|
+
|