@capillarytech/creatives-library 8.0.307 → 8.0.308
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 +1 -5
- package/initialState.js +2 -0
- package/package.json +1 -1
- package/utils/common.js +8 -5
- package/utils/commonUtils.js +93 -36
- package/utils/tagValidations.js +223 -83
- package/utils/tests/commonUtil.test.js +124 -147
- package/utils/tests/tagValidations.test.js +358 -441
- package/v2Components/ErrorInfoNote/index.js +5 -2
- package/v2Components/FormBuilder/index.js +203 -137
- package/v2Components/FormBuilder/messages.js +8 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
- package/v2Containers/Cap/mockData.js +14 -0
- package/v2Containers/Cap/reducer.js +55 -3
- package/v2Containers/Cap/tests/reducer.test.js +102 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -5
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -13
- package/v2Containers/CreativesContainer/constants.js +0 -6
- package/v2Containers/CreativesContainer/index.js +7 -47
- package/v2Containers/Email/index.js +5 -1
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +70 -23
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +120 -20
- package/v2Containers/FTP/index.js +51 -2
- package/v2Containers/FTP/messages.js +4 -0
- package/v2Containers/InApp/index.js +122 -35
- package/v2Containers/InApp/tests/index.test.js +6 -17
- package/v2Containers/InappAdvance/index.js +112 -4
- package/v2Containers/InappAdvance/tests/index.test.js +0 -2
- package/v2Containers/Line/Container/Text/index.js +1 -0
- package/v2Containers/MobilePush/Create/index.js +19 -59
- package/v2Containers/MobilePush/Edit/index.js +20 -48
- package/v2Containers/MobilePushNew/index.js +32 -12
- package/v2Containers/MobilepushWrapper/index.js +1 -3
- package/v2Containers/Rcs/index.js +37 -12
- package/v2Containers/Sms/Create/index.js +3 -39
- package/v2Containers/Sms/Create/messages.js +0 -4
- package/v2Containers/Sms/Edit/index.js +3 -35
- package/v2Containers/Sms/commonMethods.js +6 -3
- package/v2Containers/SmsTrai/Edit/index.js +47 -11
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/SmsWrapper/index.js +0 -2
- package/v2Containers/TemplatesV2/index.js +13 -28
- package/v2Containers/Viber/index.js +1 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
- package/v2Containers/WebPush/Create/index.js +2 -2
- package/v2Containers/WebPush/Create/utils/validation.js +8 -17
- package/v2Containers/WebPush/Create/utils/validation.test.js +24 -44
- package/v2Containers/Whatsapp/index.js +17 -9
- package/v2Containers/Zalo/index.js +11 -3
- package/v2Containers/Sms/tests/commonMethods.test.js +0 -122
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
checkSupport,
|
|
4
|
+
extractNames,
|
|
5
5
|
getTagMapValue,
|
|
6
6
|
getLoyaltyTagsMapValue,
|
|
7
7
|
getForwardedMapValues,
|
|
@@ -9,160 +9,10 @@ import {
|
|
|
9
9
|
validateIfTagClosed,
|
|
10
10
|
validateTags,
|
|
11
11
|
skipTags,
|
|
12
|
-
|
|
13
|
-
transformInjectedTags,
|
|
12
|
+
isInsideLiquidBlock,
|
|
14
13
|
} from '../tagValidations';
|
|
15
14
|
import { containsBase64Images } from '../content';
|
|
16
|
-
|
|
17
|
-
describe('hasUnsubscribeTag', () => {
|
|
18
|
-
it('should return false when content is not a string', () => {
|
|
19
|
-
expect(hasUnsubscribeTag(null)).toBe(false);
|
|
20
|
-
expect(hasUnsubscribeTag(undefined)).toBe(false);
|
|
21
|
-
expect(hasUnsubscribeTag(123)).toBe(false);
|
|
22
|
-
expect(hasUnsubscribeTag({})).toBe(false);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should return false when content has no unsubscribe tag', () => {
|
|
26
|
-
expect(hasUnsubscribeTag('Hello world')).toBe(false);
|
|
27
|
-
expect(hasUnsubscribeTag('{{ name }}')).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should return true when content has {{ unsubscribe }}', () => {
|
|
31
|
-
expect(hasUnsubscribeTag('Click {{ unsubscribe }} here')).toBe(true);
|
|
32
|
-
expect(hasUnsubscribeTag('{{ unsubscribe }}')).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('validateTagsCore', () => {
|
|
37
|
-
it('should include isContentEmpty: false when includeIsContentEmpty is true', () => {
|
|
38
|
-
const result = validateTagsCore({
|
|
39
|
-
contentForBraceCheck: '{{a}}',
|
|
40
|
-
contentForUnsubscribeScan: '{{a}}',
|
|
41
|
-
tags: null,
|
|
42
|
-
currentModule: 'default',
|
|
43
|
-
isFullMode: true,
|
|
44
|
-
includeIsContentEmpty: true,
|
|
45
|
-
});
|
|
46
|
-
expect(result.isContentEmpty).toBe(false);
|
|
47
|
-
expect(result.valid).toBe(true);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should use initialMissingTags when provided', () => {
|
|
51
|
-
const result = validateTagsCore({
|
|
52
|
-
contentForBraceCheck: '{{a}}',
|
|
53
|
-
contentForUnsubscribeScan: '{{a}}',
|
|
54
|
-
tags: [{ definition: { supportedModules: [], value: 'x' } }],
|
|
55
|
-
currentModule: 'default',
|
|
56
|
-
isFullMode: false,
|
|
57
|
-
initialMissingTags: ['requiredTag'],
|
|
58
|
-
});
|
|
59
|
-
expect(result.missingTags).toEqual(['requiredTag']);
|
|
60
|
-
expect(result.valid).toBe(false);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should use custom skipTagsFn when provided', () => {
|
|
64
|
-
const customSkip = jest.fn(() => true);
|
|
65
|
-
const result = validateTagsCore({
|
|
66
|
-
contentForBraceCheck: '{{ unsubscribe }}',
|
|
67
|
-
contentForUnsubscribeScan: '{{ unsubscribe }}',
|
|
68
|
-
tags: [
|
|
69
|
-
{
|
|
70
|
-
definition: {
|
|
71
|
-
supportedModules: [{ context: 'DEFAULT', mandatory: true }],
|
|
72
|
-
value: 'unsubscribe',
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
currentModule: 'DEFAULT',
|
|
77
|
-
isFullMode: false,
|
|
78
|
-
skipTagsFn: customSkip,
|
|
79
|
-
});
|
|
80
|
-
expect(customSkip).toHaveBeenCalled();
|
|
81
|
-
expect(result.valid).toBe(true);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('checkIfSupportedTag', () => {
|
|
86
|
-
it('should return false for empty or no injected tags', () => {
|
|
87
|
-
expect(checkIfSupportedTag('someTag', {})).toBe(false);
|
|
88
|
-
expect(checkIfSupportedTag('someTag', undefined)).toBe(false);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should return true when tag matches a top-level key', () => {
|
|
92
|
-
const injectedTags = { name: { name: 'Name' }, unsubscribe: { name: 'Unsubscribe' } };
|
|
93
|
-
expect(checkIfSupportedTag('name', injectedTags)).toBe(true);
|
|
94
|
-
expect(checkIfSupportedTag('unsubscribe', injectedTags)).toBe(true);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('should return false when tag does not match any key', () => {
|
|
98
|
-
const injectedTags = { name: { name: 'Name' } };
|
|
99
|
-
expect(checkIfSupportedTag('other', injectedTags)).toBe(false);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should return true when tag matches a nested subtag', () => {
|
|
103
|
-
const injectedTags = {
|
|
104
|
-
customer: {
|
|
105
|
-
name: 'Customer',
|
|
106
|
-
subtags: {
|
|
107
|
-
first_name: { name: 'First Name' },
|
|
108
|
-
last_name: { name: 'Last Name' },
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
expect(checkIfSupportedTag('first_name', injectedTags)).toBe(true);
|
|
113
|
-
expect(checkIfSupportedTag('last_name', injectedTags)).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should return false when tag is in neither top-level nor subtags', () => {
|
|
117
|
-
const injectedTags = {
|
|
118
|
-
customer: {
|
|
119
|
-
name: 'Customer',
|
|
120
|
-
subtags: { first_name: { name: 'First Name' } },
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
expect(checkIfSupportedTag('unknown', injectedTags)).toBe(false);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe('transformInjectedTags', () => {
|
|
128
|
-
it('should add tag-header and normalize subtags when key contains "subtags"', () => {
|
|
129
|
-
const tags = [
|
|
130
|
-
{
|
|
131
|
-
name: 'Customer',
|
|
132
|
-
subtags: {
|
|
133
|
-
first_name: { name: 'First Name' },
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
];
|
|
137
|
-
const result = transformInjectedTags(tags);
|
|
138
|
-
expect(result).toBe(tags);
|
|
139
|
-
expect(tags[0]['tag-header']).toBe(true);
|
|
140
|
-
expect(tags[0].subtags).toEqual({ first_name: { name: 'First Name' } });
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should recursively transform nested subtags', () => {
|
|
144
|
-
const tags = [
|
|
145
|
-
{
|
|
146
|
-
name: 'Parent',
|
|
147
|
-
subtags: {
|
|
148
|
-
child: {
|
|
149
|
-
name: 'Child',
|
|
150
|
-
subtags: { grandchild: { name: 'Grandchild' } },
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
];
|
|
155
|
-
transformInjectedTags(tags);
|
|
156
|
-
expect(tags[0].subtags.child.subtags).toEqual({ grandchild: { name: 'Grandchild' } });
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('should return tags unchanged when no subtag keys exist', () => {
|
|
160
|
-
const tags = [{ name: 'Simple', desc: 'No subtags' }];
|
|
161
|
-
const result = transformInjectedTags(tags);
|
|
162
|
-
expect(result).toBe(tags);
|
|
163
|
-
expect(tags[0]).toEqual({ name: 'Simple', desc: 'No subtags' });
|
|
164
|
-
});
|
|
165
|
-
});
|
|
15
|
+
import { eventContextTags } from '../../v2Containers/TagList/tests/mockdata';
|
|
166
16
|
|
|
167
17
|
describe("check if curly brackets are balanced", () => {
|
|
168
18
|
it("test for balanced curly brackets", () => {
|
|
@@ -172,9 +22,6 @@ describe("check if curly brackets are balanced", () => {
|
|
|
172
22
|
value += "}}"
|
|
173
23
|
let result = validateIfTagClosed(value);
|
|
174
24
|
expect(result).toEqual(true);
|
|
175
|
-
// no braces or empty string: match returns null, l1/l2/l3 undefined -> true
|
|
176
|
-
expect(validateIfTagClosed("")).toEqual(true);
|
|
177
|
-
expect(validateIfTagClosed("plain text no braces")).toEqual(true);
|
|
178
25
|
//valid cases
|
|
179
26
|
expect(validateIfTagClosed("{{{Hello}}}")).toEqual(true);
|
|
180
27
|
expect(validateIfTagClosed("{{{Hello}}")).toEqual(true);
|
|
@@ -217,41 +64,53 @@ describe("validateTags", () => {
|
|
|
217
64
|
it("should return valid response when all tags are present", () => {
|
|
218
65
|
const content = "Hello {{tag1}}, {{tag2}}, {{tag3}} {{entryTrigger.lifetimePurchases}}";
|
|
219
66
|
|
|
67
|
+
const injectedTagsParams = [];
|
|
220
68
|
const location = { query: { module: "DEFAULT" } };
|
|
221
69
|
const tagModule = null;
|
|
222
70
|
|
|
223
71
|
const result = validateTags({
|
|
224
72
|
content,
|
|
225
73
|
tagsParam,
|
|
74
|
+
injectedTagsParams,
|
|
226
75
|
location,
|
|
227
76
|
tagModule,
|
|
77
|
+
eventContextTags,
|
|
228
78
|
});
|
|
229
79
|
|
|
230
80
|
expect(result.valid).toEqual(true);
|
|
231
81
|
expect(result.missingTags).toEqual([]);
|
|
82
|
+
expect(result.unsupportedTags).toEqual([]);
|
|
232
83
|
expect(result.isBraceError).toEqual(false);
|
|
233
84
|
});
|
|
234
85
|
|
|
235
|
-
it("should return
|
|
86
|
+
it("should return invalid response when a mandatory tag is missing", () => {
|
|
236
87
|
const content = "Hello {{tag1}}, {{tag2}}, {{tag3}}";
|
|
88
|
+
const updatedTagsParam = [...tagsParam, {
|
|
89
|
+
definition: {
|
|
90
|
+
supportedModules: [{ context: "DEFAULT", mandatory: true }],
|
|
91
|
+
value: "tag4",
|
|
92
|
+
},
|
|
93
|
+
},];
|
|
94
|
+
const injectedTagsParams = [];
|
|
237
95
|
const location = { query: { module: "DEFAULT" } };
|
|
238
96
|
const tagModule = null;
|
|
239
97
|
|
|
240
98
|
const result = validateTags({
|
|
241
99
|
content,
|
|
242
|
-
|
|
100
|
+
updatedTagsParam,
|
|
101
|
+
injectedTagsParams,
|
|
243
102
|
location,
|
|
244
103
|
tagModule,
|
|
245
104
|
});
|
|
246
105
|
|
|
247
106
|
expect(result.valid).toEqual(true);
|
|
248
|
-
expect(result.
|
|
107
|
+
expect(result.unsupportedTags).toEqual(["tag1", "tag2", "tag3"]);
|
|
249
108
|
expect(result.isBraceError).toEqual(false);
|
|
250
109
|
});
|
|
251
110
|
|
|
252
|
-
it("should return
|
|
111
|
+
it("should return invalid response when an unsupported tag is present", () => {
|
|
253
112
|
const content = "Hello {{tag1}}, {{tag2}}, {{tag3}} {{missingEventContextTags}}";
|
|
254
|
-
const
|
|
113
|
+
const tagsParam = [
|
|
255
114
|
{
|
|
256
115
|
definition: {
|
|
257
116
|
supportedModules: [{ context: "DEFAULT", mandatory: true }],
|
|
@@ -265,24 +124,27 @@ describe("validateTags", () => {
|
|
|
265
124
|
},
|
|
266
125
|
},
|
|
267
126
|
];
|
|
127
|
+
const injectedTagsParams = [];
|
|
268
128
|
const location = { query: { module: "DEFAULT" } };
|
|
269
129
|
const tagModule = null;
|
|
270
130
|
|
|
271
131
|
const result = validateTags({
|
|
272
132
|
content,
|
|
273
|
-
tagsParam
|
|
133
|
+
tagsParam,
|
|
134
|
+
injectedTagsParams,
|
|
274
135
|
location,
|
|
275
136
|
tagModule,
|
|
276
137
|
});
|
|
277
138
|
|
|
278
139
|
expect(result.valid).toEqual(true);
|
|
279
140
|
expect(result.missingTags).toEqual([]);
|
|
141
|
+
expect(result.unsupportedTags).toEqual(["tag3", "missingEventContextTags"]);
|
|
280
142
|
expect(result.isBraceError).toEqual(false);
|
|
281
143
|
});
|
|
282
144
|
|
|
283
145
|
it("should return invalid response when there is an unbalanced bracket error", () => {
|
|
284
146
|
const content = "Hello {{tag1}, {{tag2}}, {{tag3}}";
|
|
285
|
-
const
|
|
147
|
+
const tagsParam = [
|
|
286
148
|
{
|
|
287
149
|
definition: {
|
|
288
150
|
supportedModules: [{ context: "DEFAULT", mandatory: true }],
|
|
@@ -302,23 +164,26 @@ describe("validateTags", () => {
|
|
|
302
164
|
},
|
|
303
165
|
},
|
|
304
166
|
];
|
|
167
|
+
const injectedTagsParams = [];
|
|
305
168
|
const location = { query: { module: "DEFAULT" } };
|
|
306
169
|
const tagModule = null;
|
|
307
170
|
|
|
308
171
|
const result = validateTags({
|
|
309
172
|
content,
|
|
310
|
-
tagsParam
|
|
173
|
+
tagsParam,
|
|
174
|
+
injectedTagsParams,
|
|
311
175
|
location,
|
|
312
176
|
tagModule,
|
|
313
177
|
});
|
|
314
178
|
|
|
315
179
|
expect(result.valid).toEqual(false);
|
|
316
|
-
expect(result.missingTags).toEqual([]);
|
|
180
|
+
expect(result.missingTags).toEqual(["tag1"]);
|
|
181
|
+
expect(result.unsupportedTags).toEqual([]);
|
|
317
182
|
expect(result.isBraceError).toEqual(true);
|
|
318
183
|
});
|
|
319
184
|
|
|
320
|
-
it("should
|
|
321
|
-
const
|
|
185
|
+
it("should remove 'unsubscribe' from missingTags if skipTags logic is triggered", () => {
|
|
186
|
+
const tagsParam = [
|
|
322
187
|
{
|
|
323
188
|
definition: {
|
|
324
189
|
supportedModules: [{ context: "DEFAULT", mandatory: true }],
|
|
@@ -326,310 +191,288 @@ describe("validateTags", () => {
|
|
|
326
191
|
},
|
|
327
192
|
},
|
|
328
193
|
];
|
|
194
|
+
// Content does not include {{unsubscribe}}, so it would be missing
|
|
195
|
+
const contentMissing = "Hello {{tag1}}";
|
|
196
|
+
const injectedTagsParams = [];
|
|
329
197
|
const location = { query: { module: "DEFAULT" } };
|
|
330
198
|
const tagModule = null;
|
|
331
199
|
|
|
332
|
-
|
|
200
|
+
// First, verify unsubscribe is missing if not present
|
|
333
201
|
const resultMissing = validateTags({
|
|
334
202
|
content: contentMissing,
|
|
335
|
-
tagsParam
|
|
203
|
+
tagsParam,
|
|
204
|
+
injectedTagsParams,
|
|
336
205
|
location,
|
|
337
206
|
tagModule,
|
|
338
207
|
});
|
|
339
208
|
expect(resultMissing.missingTags).toContain("unsubscribe");
|
|
340
|
-
expect(resultMissing.valid).toBe(false);
|
|
341
209
|
|
|
210
|
+
// Now, content includes a tag that triggers skipTags logic for unsubscribe
|
|
211
|
+
// e.g., {{unsubscribe(#123456)}} matches the skipTags regex
|
|
342
212
|
const contentWithSkippedUnsubscribe = "Hello {{unsubscribe(#123456)}}";
|
|
343
213
|
const resultSkipped = validateTags({
|
|
344
214
|
content: contentWithSkippedUnsubscribe,
|
|
345
|
-
tagsParam
|
|
215
|
+
tagsParam,
|
|
216
|
+
injectedTagsParams,
|
|
346
217
|
location,
|
|
347
218
|
tagModule,
|
|
348
219
|
});
|
|
349
220
|
expect(resultSkipped.missingTags).not.toContain("unsubscribe");
|
|
350
221
|
expect(resultSkipped.valid).toBe(true);
|
|
351
|
-
|
|
352
|
-
const contentWithWhitespaceUnsubscribe = "Hello {{ unsubscribe }}";
|
|
353
|
-
const resultWhitespace = validateTags({
|
|
354
|
-
content: contentWithWhitespaceUnsubscribe,
|
|
355
|
-
tagsParam: tagsParamUnsubscribe,
|
|
356
|
-
location,
|
|
357
|
-
tagModule,
|
|
358
|
-
});
|
|
359
|
-
expect(resultWhitespace.missingTags).not.toContain("unsubscribe");
|
|
360
|
-
expect(resultWhitespace.valid).toBe(true);
|
|
361
|
-
expect(resultWhitespace.unsupportedTags ?? []).toEqual([]);
|
|
362
222
|
});
|
|
363
223
|
});
|
|
364
224
|
|
|
365
|
-
describe(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
225
|
+
describe("extractNames", () => {
|
|
226
|
+
it("should return an empty array when data is empty", () => {
|
|
227
|
+
const data = [];
|
|
228
|
+
const result = extractNames(data);
|
|
229
|
+
expect(result).toEqual([]);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("should return an array of names when data contains nodes with names", () => {
|
|
233
|
+
const data = [
|
|
234
|
+
{
|
|
235
|
+
name: "Node 1",
|
|
236
|
+
children: [
|
|
237
|
+
{
|
|
238
|
+
name: "Node 1.1",
|
|
239
|
+
children: [],
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: "Node 1.2",
|
|
243
|
+
children: [],
|
|
244
|
+
},
|
|
245
|
+
],
|
|
371
246
|
},
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
247
|
+
{
|
|
248
|
+
name: "Node 2",
|
|
249
|
+
children: [
|
|
250
|
+
{
|
|
251
|
+
name: "Node 2.1",
|
|
252
|
+
children: [],
|
|
253
|
+
},
|
|
254
|
+
],
|
|
379
255
|
},
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
256
|
+
];
|
|
257
|
+
const result = extractNames(data);
|
|
258
|
+
expect(result).toEqual([
|
|
259
|
+
"Node 1",
|
|
260
|
+
"Node 1.1",
|
|
261
|
+
"Node 1.2",
|
|
262
|
+
"Node 2",
|
|
263
|
+
"Node 2.1",
|
|
264
|
+
]);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it("should ignore nodes without names", () => {
|
|
268
|
+
const data = [
|
|
269
|
+
{
|
|
270
|
+
name: "Node 1",
|
|
271
|
+
children: [
|
|
272
|
+
{
|
|
273
|
+
name: "Node 1.1",
|
|
274
|
+
children: [],
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
children: [],
|
|
278
|
+
},
|
|
279
|
+
],
|
|
387
280
|
},
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
location: { query: { module: 'DEFAULT' } },
|
|
410
|
-
tagModule: 'outbound',
|
|
411
|
-
});
|
|
412
|
-
expect(resultWithOutbound.missingTags).toContain('unsubscribe');
|
|
413
|
-
expect(resultWithOutbound.valid).toBe(false);
|
|
414
|
-
|
|
415
|
-
const resultWithDefault = validateTags({
|
|
416
|
-
content,
|
|
417
|
-
tagsParam: tagsWithUnsubscribe,
|
|
418
|
-
location: { query: { module: 'outbound' } },
|
|
419
|
-
tagModule: 'DEFAULT',
|
|
420
|
-
});
|
|
421
|
-
expect(resultWithDefault.missingTags).toContain('unsubscribe');
|
|
422
|
-
expect(resultWithDefault.valid).toBe(false);
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
it('uses DEFAULT (lowercase) when location is undefined', () => {
|
|
426
|
-
const content = 'Hello world';
|
|
427
|
-
const result = validateTags({
|
|
428
|
-
content,
|
|
429
|
-
tagsParam: tagsDefaultLowercase,
|
|
430
|
-
location: undefined,
|
|
431
|
-
tagModule: null,
|
|
432
|
-
});
|
|
433
|
-
expect(result.missingTags).toContain('unsubscribe');
|
|
434
|
-
expect(result.valid).toBe(false);
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
it('uses DEFAULT when location.query is undefined', () => {
|
|
438
|
-
const content = 'Hello world';
|
|
439
|
-
const result = validateTags({
|
|
440
|
-
content,
|
|
441
|
-
tagsParam: tagsDefaultLowercase,
|
|
442
|
-
location: {},
|
|
443
|
-
tagModule: null,
|
|
444
|
-
});
|
|
445
|
-
expect(result.missingTags).toContain('unsubscribe');
|
|
446
|
-
expect(result.valid).toBe(false);
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
it('uses DEFAULT when location.query.module is falsy', () => {
|
|
450
|
-
const content = 'Hello world';
|
|
451
|
-
const result = validateTags({
|
|
452
|
-
content,
|
|
453
|
-
tagsParam: tagsDefaultLowercase,
|
|
454
|
-
location: { query: { module: '' } },
|
|
455
|
-
tagModule: null,
|
|
456
|
-
});
|
|
457
|
-
expect(result.missingTags).toContain('unsubscribe');
|
|
458
|
-
expect(result.valid).toBe(false);
|
|
459
|
-
});
|
|
281
|
+
{
|
|
282
|
+
name: "Node 2",
|
|
283
|
+
children: [
|
|
284
|
+
{
|
|
285
|
+
name: "Node 2.1",
|
|
286
|
+
children: [],
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
name: "Node 2.2",
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
];
|
|
294
|
+
const result = extractNames(data);
|
|
295
|
+
expect(result).toEqual([
|
|
296
|
+
"Node 1",
|
|
297
|
+
"Node 1.1",
|
|
298
|
+
"Node 2",
|
|
299
|
+
"Node 2.1",
|
|
300
|
+
"Node 2.2",
|
|
301
|
+
]);
|
|
460
302
|
});
|
|
303
|
+
});
|
|
461
304
|
|
|
462
|
-
describe('content passed to contentForBraceCheck and contentForUnsubscribeScan', () => {
|
|
463
|
-
it('uses same content for brace check (isBraceError when unbalanced)', () => {
|
|
464
|
-
const content = 'Hello {{tag1}, {{tag2}}';
|
|
465
|
-
const result = validateTags({
|
|
466
|
-
content,
|
|
467
|
-
tagsParam: [],
|
|
468
|
-
location: { query: { module: 'DEFAULT' } },
|
|
469
|
-
});
|
|
470
|
-
expect(result.isBraceError).toBe(true);
|
|
471
|
-
expect(result.valid).toBe(false);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it('uses same content for unsubscribe scan (missing unsubscribe when required)', () => {
|
|
475
|
-
const content = 'Hello {{other}}';
|
|
476
|
-
const result = validateTags({
|
|
477
|
-
content,
|
|
478
|
-
tagsParam: tagsWithUnsubscribe,
|
|
479
|
-
location: { query: { module: 'DEFAULT' } },
|
|
480
|
-
});
|
|
481
|
-
expect(result.missingTags).toContain('unsubscribe');
|
|
482
|
-
expect(result.valid).toBe(false);
|
|
483
|
-
});
|
|
484
305
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
tagsParam: tagsWithUnsubscribe,
|
|
490
|
-
location: { query: { module: 'DEFAULT' } },
|
|
491
|
-
});
|
|
492
|
-
expect(result.missingTags).not.toContain('unsubscribe');
|
|
493
|
-
expect(result.valid).toBe(true);
|
|
494
|
-
});
|
|
306
|
+
describe("checkSupport", () => {
|
|
307
|
+
it("should return an empty array when args are empty", () => {
|
|
308
|
+
const result = checkSupport();
|
|
309
|
+
expect(result).toEqual([]);
|
|
495
310
|
});
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
content,
|
|
502
|
-
tagsParam: tagsWithUnsubscribe,
|
|
503
|
-
location: { query: { module: 'DEFAULT' } },
|
|
504
|
-
isFullMode: true,
|
|
505
|
-
});
|
|
506
|
-
expect(result.missingTags).toEqual([]);
|
|
507
|
-
expect(result.valid).toBe(true);
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
it('when true still runs brace check', () => {
|
|
511
|
-
const content = 'Hello {{tag1}';
|
|
512
|
-
const result = validateTags({
|
|
513
|
-
content,
|
|
514
|
-
tagsParam: tagsWithUnsubscribe,
|
|
515
|
-
location: { query: { module: 'DEFAULT' } },
|
|
516
|
-
isFullMode: true,
|
|
517
|
-
});
|
|
518
|
-
expect(result.isBraceError).toBe(true);
|
|
519
|
-
expect(result.valid).toBe(false);
|
|
520
|
-
});
|
|
311
|
+
it("should return an empty array when response data is empty", () => {
|
|
312
|
+
const response = { data: [] };
|
|
313
|
+
const tagObject = {};
|
|
314
|
+
const result = checkSupport(response, tagObject);
|
|
315
|
+
expect(result).toEqual([]);
|
|
521
316
|
});
|
|
522
317
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
});
|
|
531
|
-
expect(result.missingTags).toEqual([]);
|
|
532
|
-
expect(result.isBraceError).toBe(false);
|
|
533
|
-
expect(result.valid).toBe(true);
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
it('when empty array: only brace check runs', () => {
|
|
537
|
-
const content = 'Hello {{a}}';
|
|
538
|
-
const result = validateTags({
|
|
539
|
-
content,
|
|
540
|
-
tagsParam: [],
|
|
541
|
-
location: { query: { module: 'DEFAULT' } },
|
|
542
|
-
});
|
|
543
|
-
expect(result.missingTags).toEqual([]);
|
|
544
|
-
expect(result.valid).toBe(true);
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
it('when null with unbalanced braces: returns isBraceError', () => {
|
|
548
|
-
const content = 'Hello {{a}';
|
|
549
|
-
const result = validateTags({
|
|
550
|
-
content,
|
|
551
|
-
tagsParam: null,
|
|
552
|
-
location: { query: { module: 'DEFAULT' } },
|
|
553
|
-
});
|
|
554
|
-
expect(result.isBraceError).toBe(true);
|
|
555
|
-
expect(result.valid).toBe(false);
|
|
556
|
-
expect(result.missingTags).toEqual([]);
|
|
557
|
-
});
|
|
318
|
+
it("should return an empty array when tagObject is empty", () => {
|
|
319
|
+
const response = {
|
|
320
|
+
data: [{ name: "tag1" }, { name: "tag2" }, { name: "tag3" }],
|
|
321
|
+
};
|
|
322
|
+
const tagObject = {};
|
|
323
|
+
const result = checkSupport(response, tagObject);
|
|
324
|
+
expect(result).toEqual([]);
|
|
558
325
|
});
|
|
559
326
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
isFullMode: false,
|
|
569
|
-
});
|
|
570
|
-
expect(result.valid).toBe(true);
|
|
571
|
-
expect(result.isBraceError).toBe(false);
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
it('Zalo / Rcs / MobilePushNew / EmailWrapper: same pattern as Whatsapp', () => {
|
|
575
|
-
const result = validateTags({
|
|
576
|
-
content: 'Hi {{ unsubscribe }}',
|
|
577
|
-
tagsParam: tagsWithUnsubscribe,
|
|
578
|
-
location: { query: { module: 'DEFAULT' } },
|
|
579
|
-
tagModule: 'DEFAULT',
|
|
580
|
-
isFullMode: false,
|
|
581
|
-
});
|
|
582
|
-
expect(result.valid).toBe(true);
|
|
583
|
-
});
|
|
327
|
+
it("should return event context tags even if tagObject is empty", () => {
|
|
328
|
+
const response = {
|
|
329
|
+
data: [{ name: "tag1" }, { name: "entryTrigger.lifetimePurchases" }],
|
|
330
|
+
};
|
|
331
|
+
const tagObject = {};
|
|
332
|
+
const result = checkSupport(response, tagObject, eventContextTags);
|
|
333
|
+
expect(result).toEqual(['entryTrigger.lifetimePurchases']);
|
|
334
|
+
});
|
|
584
335
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const resultOk = validateTags({
|
|
598
|
-
content: 'Hello {{ unsubscribe }}',
|
|
599
|
-
tagsParam: tagsOutboundUnsubscribe,
|
|
600
|
-
location: {},
|
|
601
|
-
tagModule: 'outbound',
|
|
602
|
-
isFullMode: false,
|
|
603
|
-
});
|
|
604
|
-
expect(resultOk.valid).toBe(true);
|
|
605
|
-
});
|
|
336
|
+
it("should return an array of supported tags", () => {
|
|
337
|
+
const response = {
|
|
338
|
+
data: [{ name: "tag1" }, { name: "tag2" }, { name: "tag3" }],
|
|
339
|
+
};
|
|
340
|
+
const tagObject = {
|
|
341
|
+
tag1: { definition: { subtags: ["tag1.1", "tag1.2"] } },
|
|
342
|
+
tag2: { definition: { subtags: ["tag2.1", "tag2.2"] } },
|
|
343
|
+
tag3: { definition: { subtags: ["tag3.1", "tag3.2"] } },
|
|
344
|
+
};
|
|
345
|
+
const result = checkSupport(response, tagObject);
|
|
346
|
+
expect(result).toEqual(["tag1", "tag2", "tag3"]);
|
|
347
|
+
});
|
|
606
348
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
349
|
+
it("should return an array of supported tags with subtags", () => {
|
|
350
|
+
const response = {
|
|
351
|
+
data: [{ name: "tag1" }, { name: "tag2" }, { name: "tag3" }],
|
|
352
|
+
};
|
|
353
|
+
const tagObject = {
|
|
354
|
+
tag1: { definition: { subtags: ["tag1.1", "tag1.2"] } },
|
|
355
|
+
tag2: { definition: { subtags: ["tag2.1", "tag2.2"] } },
|
|
356
|
+
tag3: { definition: { subtags: ["tag3.1", "tag3.2"] } },
|
|
357
|
+
"tag1.1": {},
|
|
358
|
+
"tag2.1": {},
|
|
359
|
+
"tag3.1": {},
|
|
360
|
+
};
|
|
361
|
+
const result = checkSupport(response, tagObject);
|
|
362
|
+
expect(result).toEqual(["tag1", "tag2", "tag3"]);
|
|
363
|
+
});
|
|
621
364
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
365
|
+
it("should return an empty array when no tags are supported", () => {
|
|
366
|
+
const response = {
|
|
367
|
+
data: [{ name: "tag1" }, { name: "tag2" }, { name: "tag3" }],
|
|
368
|
+
};
|
|
369
|
+
const tagObject = {
|
|
370
|
+
tag4: {},
|
|
371
|
+
tag5: {},
|
|
372
|
+
tag6: {},
|
|
373
|
+
};
|
|
374
|
+
const result = checkSupport(response, tagObject);
|
|
375
|
+
expect(result).toEqual([]);
|
|
376
|
+
});
|
|
377
|
+
it("should return an array of supported tags with subtags", () => {
|
|
378
|
+
const response = {
|
|
379
|
+
data: [
|
|
380
|
+
{
|
|
381
|
+
name: "tag1",
|
|
382
|
+
children: [{ name: "tag1.1", children: [{ name: "tag1.2" }] }],
|
|
383
|
+
},
|
|
384
|
+
{ name: "tag2", children: [] },
|
|
385
|
+
{ name: "tag3" },
|
|
386
|
+
],
|
|
387
|
+
};
|
|
388
|
+
const tagObject = {
|
|
389
|
+
tag1: { definition: { subtags: [".1", "tag1.2"] } },
|
|
390
|
+
tag2: { definition: { subtags: ["tag2.1", "tag2.2"] } },
|
|
391
|
+
tag3: { definition: { subtags: ["tag3.1", "tag3.2"] } },
|
|
392
|
+
"tag1.1": {},
|
|
393
|
+
"tag2.1": {},
|
|
394
|
+
"tag3.1": {},
|
|
395
|
+
};
|
|
396
|
+
const result = checkSupport(response, tagObject);
|
|
397
|
+
expect(result).toEqual(["tag1", "tag1.1", "tag2", "tag3"]);
|
|
398
|
+
});
|
|
399
|
+
it("should return an array of supported tags children as an object", () => {
|
|
400
|
+
const response = {
|
|
401
|
+
data: [
|
|
402
|
+
{ name: "tag1", children: [{ name: "tag" }] },
|
|
403
|
+
{ name: "tag2", children: [] },
|
|
404
|
+
{ name: "tag3" },
|
|
405
|
+
],
|
|
406
|
+
};
|
|
407
|
+
const tagObject = {
|
|
408
|
+
tag1: { definition: { subtags: [".1", "tag1.2"] } },
|
|
409
|
+
tag2: { definition: { subtags: ["tag2.1", "tag2.2"] } },
|
|
410
|
+
tag3: { definition: { subtags: ["tag3.1", "tag3.2"] } },
|
|
411
|
+
"tag1.1": {},
|
|
412
|
+
"tag2.1": {},
|
|
413
|
+
"tag3.1": {},
|
|
414
|
+
};
|
|
415
|
+
const result = checkSupport(response, tagObject);
|
|
416
|
+
expect(result).toEqual(["tag1", "tag2", "tag3"]);
|
|
417
|
+
});
|
|
418
|
+
it("should return an empty array if tagObject is empty", () => {
|
|
419
|
+
const response = {
|
|
420
|
+
data: [
|
|
421
|
+
{ name: "tag1", children: [{ name: "tag" }] },
|
|
422
|
+
{ name: "tag2", children: [] },
|
|
423
|
+
{ name: "tag3" },
|
|
424
|
+
],
|
|
425
|
+
};
|
|
426
|
+
const result = checkSupport(response, {});
|
|
427
|
+
expect(result).toEqual([]);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("should add childName to supportedList if it is a subtag of parentTag in eventContextTags", () => {
|
|
431
|
+
const response = { data: [{ name: "leaderboard", children: [{name: "person.userId"}]}]};
|
|
432
|
+
const tagObject = {};
|
|
433
|
+
const eventContextTags = [{ tagName: "leaderboard", subTags: ["userId"]}];
|
|
434
|
+
const isLiquidFlow = true;
|
|
435
|
+
const result = checkSupport(response, tagObject, eventContextTags, isLiquidFlow);
|
|
436
|
+
expect(result).toEqual( [ 'leaderboard', 'person.userId' ]);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it("should not add childName to supportedList which does not have dot in eventContextTags", () => {
|
|
440
|
+
// This case is unlikely to happen as we are not supporting tags without dot in eventContextTags
|
|
441
|
+
const response = { data: [{ name: "entryTrigger.lifetimePoints", children: [{name: "userId"}] }]};
|
|
442
|
+
const tagObject = {};
|
|
443
|
+
const eventContextTags = [{ tagName: "entryTrigger.lifetimePoints", children: [{name: "userId"}] }];
|
|
444
|
+
const isLiquidFlow = true;
|
|
445
|
+
const result = checkSupport(response, tagObject, eventContextTags, isLiquidFlow);
|
|
446
|
+
expect(result).toEqual( [ "entryTrigger.lifetimePoints" ]);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it("should add only parent tag to supportedList if isLiquidFlow false", () => {
|
|
450
|
+
const response = { data: [{ name: "leaderboard", children: [{name: "person.userId"}]}]};
|
|
451
|
+
const tagObject = {};
|
|
452
|
+
const eventContextTags = [{ tagName: "leaderboard", subTags: ["userId"]}];
|
|
453
|
+
const isLiquidFlow = false;
|
|
454
|
+
const result = checkSupport(response, tagObject, eventContextTags, isLiquidFlow);
|
|
455
|
+
expect(result).toEqual( [ 'leaderboard' ]);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it("test for checking loyalty tags in that are coming in forwardedTags", () => {
|
|
459
|
+
const response = { data: [{ name: "leaderboard", children: [{name: "person.userId"}]}]};
|
|
460
|
+
const tagObject = {};
|
|
461
|
+
const isLiquidFlow = true;
|
|
462
|
+
// forwardedTags contains tag hierarchy with parent tags and their subtags
|
|
463
|
+
// needed for loyalty email liquid tag resolution
|
|
464
|
+
const forwardedTags = {
|
|
465
|
+
leaderboard: {
|
|
466
|
+
name: "Leaderboard",
|
|
467
|
+
subtags: {
|
|
468
|
+
"person.userId": {
|
|
469
|
+
name: "User ID",
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
},
|
|
473
|
+
};
|
|
474
|
+
const result = checkSupport(response, tagObject, [], isLiquidFlow, forwardedTags);
|
|
475
|
+
expect(result).toEqual( [ 'leaderboard', 'person.userId' ]);
|
|
633
476
|
});
|
|
634
477
|
});
|
|
635
478
|
|
|
@@ -1205,10 +1048,6 @@ describe('getForwardedMapValues', () => {
|
|
|
1205
1048
|
expect(getForwardedMapValues(input)).toEqual(expected);
|
|
1206
1049
|
});
|
|
1207
1050
|
|
|
1208
|
-
test('should return empty object when called with no argument (default param)', () => {
|
|
1209
|
-
expect(getForwardedMapValues()).toEqual({});
|
|
1210
|
-
});
|
|
1211
|
-
|
|
1212
1051
|
test('should correctly process objects with subtags', () => {
|
|
1213
1052
|
const input = {
|
|
1214
1053
|
customer: {
|
|
@@ -1470,6 +1309,84 @@ describe('getForwardedMapValues', () => {
|
|
|
1470
1309
|
});
|
|
1471
1310
|
});
|
|
1472
1311
|
|
|
1312
|
+
describe('isInsideLiquidBlock', () => {
|
|
1313
|
+
it('returns true for index inside a single block', () => {
|
|
1314
|
+
const content = 'Hello {% assign foo = 1 %} World';
|
|
1315
|
+
// Index of 'a' in 'assign' inside the block
|
|
1316
|
+
const tagIndex = content.indexOf('assign');
|
|
1317
|
+
expect(isInsideLiquidBlock(content, tagIndex)).toBe(true);
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
it('returns false for index outside any block', () => {
|
|
1321
|
+
const content = 'Hello {% assign foo = 1 %} World';
|
|
1322
|
+
// Index of 'H' in 'Hello'
|
|
1323
|
+
expect(isInsideLiquidBlock(content, 0)).toBe(false);
|
|
1324
|
+
// Index of 'W' in 'World'
|
|
1325
|
+
expect(isInsideLiquidBlock(content, content.indexOf('World'))).toBe(false);
|
|
1326
|
+
});
|
|
1327
|
+
|
|
1328
|
+
it('returns true for index at the start of a block', () => {
|
|
1329
|
+
const content = 'Hello {% assign foo = 1 %} World';
|
|
1330
|
+
// Index of '{' in '{%'
|
|
1331
|
+
const tagIndex = content.indexOf('{%');
|
|
1332
|
+
expect(isInsideLiquidBlock(content, tagIndex)).toBe(true);
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
it('returns false for index at the end of a block (exclusive)', () => {
|
|
1336
|
+
const content = 'Hello {% assign foo = 1 %} World';
|
|
1337
|
+
// Index just after the closing '%}'
|
|
1338
|
+
const blockEnd = content.indexOf('%}') + 2;
|
|
1339
|
+
expect(isInsideLiquidBlock(content, blockEnd)).toBe(false);
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
it('returns true for index inside the second of multiple blocks', () => {
|
|
1343
|
+
const content = 'A {% first %} B {% second %} C';
|
|
1344
|
+
const tagIndex = content.indexOf('second');
|
|
1345
|
+
expect(isInsideLiquidBlock(content, tagIndex)).toBe(true);
|
|
1346
|
+
});
|
|
1347
|
+
|
|
1348
|
+
it('returns false for index between blocks', () => {
|
|
1349
|
+
const content = 'A {% first %} B {% second %} C';
|
|
1350
|
+
// Index of 'B' (between blocks)
|
|
1351
|
+
const tagIndex = content.indexOf('B');
|
|
1352
|
+
expect(isInsideLiquidBlock(content, tagIndex)).toBe(false);
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1355
|
+
it('returns false for empty string', () => {
|
|
1356
|
+
expect(isInsideLiquidBlock('', 0)).toBe(false);
|
|
1357
|
+
});
|
|
1358
|
+
|
|
1359
|
+
it('returns false if there are no blocks', () => {
|
|
1360
|
+
const content = 'Just some text with no blocks';
|
|
1361
|
+
expect(isInsideLiquidBlock(content, 5)).toBe(false);
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1364
|
+
it('returns false for negative index', () => {
|
|
1365
|
+
const content = 'Hello {% assign foo = 1 %} World';
|
|
1366
|
+
expect(isInsideLiquidBlock(content, -1)).toBe(false);
|
|
1367
|
+
});
|
|
1368
|
+
|
|
1369
|
+
it('returns false for index beyond string length', () => {
|
|
1370
|
+
const content = 'Hello {% assign foo = 1 %} World';
|
|
1371
|
+
expect(isInsideLiquidBlock(content, 100)).toBe(false);
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
it('works for nested-like blocks (not truly nested)', () => {
|
|
1375
|
+
const content = 'A {% outer {% inner %} outer %} B';
|
|
1376
|
+
// Index of 'inner' (should be inside the first block)
|
|
1377
|
+
const tagIndex = content.indexOf('inner');
|
|
1378
|
+
expect(isInsideLiquidBlock(content, tagIndex)).toBe(true);
|
|
1379
|
+
});
|
|
1380
|
+
|
|
1381
|
+
it('returns true for index at last char inside block', () => {
|
|
1382
|
+
const content = 'A {% foo %} B';
|
|
1383
|
+
// Index of last char inside block (just before %})
|
|
1384
|
+
const blockStart = content.indexOf('{%');
|
|
1385
|
+
const blockEnd = content.indexOf('%}');
|
|
1386
|
+
expect(isInsideLiquidBlock(content, blockEnd - 1)).toBe(true);
|
|
1387
|
+
});
|
|
1388
|
+
});
|
|
1389
|
+
|
|
1473
1390
|
describe('containsBase64Images', () => {
|
|
1474
1391
|
let mockCapNotification;
|
|
1475
1392
|
let mockCallback;
|