@capillarytech/creatives-library 8.0.353-alpha.5 → 8.0.353-alpha.6
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 +29 -0
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/commonUtils.js +19 -1
- package/utils/rcsPayloadUtils.js +92 -0
- package/utils/templateVarUtils.js +201 -0
- package/utils/tests/rcsPayloadUtils.test.js +226 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +166 -108
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +72 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +213 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/PreviewHeader.js +0 -17
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +157 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +346 -146
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +138 -48
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -4
- package/v2Components/CommonTestAndPreview/index.js +691 -235
- package/v2Components/CommonTestAndPreview/messages.js +45 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +25 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +308 -284
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +34 -13
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +0 -159
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -256
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -2
- package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -198
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +36 -26
- package/v2Components/FormBuilder/index.js +11 -6
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +956 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +119 -0
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +223 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +38 -23
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -31
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +15 -3
- package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/v2Containers/App/constants.js +0 -3
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/v2Containers/CreativesContainer/constants.js +9 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +79 -0
- package/v2Containers/CreativesContainer/index.js +322 -103
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +78 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +357 -98
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +119 -10
- package/v2Containers/Rcs/index.js +2445 -813
- package/v2Containers/Rcs/index.scss +280 -8
- package/v2Containers/Rcs/messages.js +34 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +225 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +98018 -70073
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/index.test.js +152 -121
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
- package/v2Containers/Rcs/tests/utils.test.js +646 -30
- package/v2Containers/Rcs/utils.js +478 -11
- package/v2Containers/Sms/Create/index.js +106 -40
- package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Create/index.js +9 -4
- package/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +640 -130
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4328 -2375
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +6 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +166 -9
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +122 -120
- package/v2Containers/Templates/sagas.js +56 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1062 -1017
- package/v2Containers/Templates/tests/sagas.test.js +199 -16
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/v2Containers/TemplatesV2/index.js +86 -23
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/WebPush/Create/index.js +8 -91
- package/v2Containers/WebPush/Create/index.scss +0 -7
- package/v2Containers/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +0 -169
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +0 -522
- package/v2Containers/App/tests/constants.test.js +0 -61
- package/v2Containers/Templates/tests/webpush.test.js +0 -375
- package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +0 -338
- package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +0 -325
|
@@ -30,23 +30,28 @@ jest.mock('@capillarytech/cap-ui-library/CapNotification', () => ({
|
|
|
30
30
|
}));
|
|
31
31
|
|
|
32
32
|
// Mock child components - must use React.createElement to avoid hoisting issues
|
|
33
|
+
let lastLeftPanelContentProps = null;
|
|
33
34
|
jest.mock('../LeftPanelContent', () => {
|
|
34
35
|
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
35
36
|
const ReactLib = require('react');
|
|
36
37
|
return {
|
|
37
38
|
__esModule: true,
|
|
38
|
-
default: function MockLeftPanelContent() {
|
|
39
|
-
|
|
39
|
+
default: function MockLeftPanelContent(props) {
|
|
40
|
+
lastLeftPanelContentProps = props;
|
|
41
|
+
const editorEl = props.renderCustomValuesEditor ? props.renderCustomValuesEditor() : null;
|
|
42
|
+
return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel', editorEl);
|
|
40
43
|
},
|
|
41
44
|
};
|
|
42
45
|
});
|
|
43
46
|
|
|
47
|
+
let lastCustomValuesEditorProps = null;
|
|
44
48
|
jest.mock('../CustomValuesEditor', () => {
|
|
45
49
|
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
46
50
|
const ReactLib = require('react');
|
|
47
51
|
return {
|
|
48
52
|
__esModule: true,
|
|
49
|
-
default: function MockCustomValuesEditor() {
|
|
53
|
+
default: function MockCustomValuesEditor(props) {
|
|
54
|
+
lastCustomValuesEditorProps = props;
|
|
50
55
|
return ReactLib.createElement('div', { 'data-testid': 'custom-values-editor' }, 'Custom Values Editor');
|
|
51
56
|
},
|
|
52
57
|
};
|
|
@@ -191,6 +196,8 @@ describe('CommonTestAndPreview', () => {
|
|
|
191
196
|
beforeEach(() => {
|
|
192
197
|
jest.clearAllMocks();
|
|
193
198
|
lastSendTestMessageProps = null;
|
|
199
|
+
lastLeftPanelContentProps = null;
|
|
200
|
+
lastCustomValuesEditorProps = null;
|
|
194
201
|
// Reset all mock function implementations
|
|
195
202
|
Object.values(mockActions).forEach((mockFn) => {
|
|
196
203
|
if (jest.isMockFunction(mockFn)) {
|
|
@@ -245,6 +252,24 @@ describe('CommonTestAndPreview', () => {
|
|
|
245
252
|
});
|
|
246
253
|
});
|
|
247
254
|
|
|
255
|
+
it('should call getSenderDetailsRequested for RCS and SMS when channel is RCS', async () => {
|
|
256
|
+
render(
|
|
257
|
+
<TestWrapper>
|
|
258
|
+
<CommonTestAndPreview {...defaultProps} channel={CHANNELS.RCS} />
|
|
259
|
+
</TestWrapper>
|
|
260
|
+
);
|
|
261
|
+
await waitFor(() => {
|
|
262
|
+
expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
|
|
263
|
+
channel: CHANNELS.RCS,
|
|
264
|
+
orgUnitId: -1,
|
|
265
|
+
});
|
|
266
|
+
expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
|
|
267
|
+
channel: CHANNELS.SMS,
|
|
268
|
+
orgUnitId: -1,
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
248
273
|
it('should not call getSenderDetailsRequested when channel is INAPP', async () => {
|
|
249
274
|
render(
|
|
250
275
|
<TestWrapper>
|
|
@@ -303,7 +328,7 @@ describe('CommonTestAndPreview', () => {
|
|
|
303
328
|
});
|
|
304
329
|
expect(lastSendTestMessageProps).toBeDefined();
|
|
305
330
|
expect(lastSendTestMessageProps.deliverySettings).toBeDefined();
|
|
306
|
-
expect(lastSendTestMessageProps.
|
|
331
|
+
expect(lastSendTestMessageProps.senderDetailsByChannel).toEqual(senderDetailsByChannel);
|
|
307
332
|
expect(lastSendTestMessageProps.wecrmAccounts).toEqual([]);
|
|
308
333
|
expect(typeof lastSendTestMessageProps.onSaveDeliverySettings).toBe('function');
|
|
309
334
|
expect(lastSendTestMessageProps.isLoadingSenderDetails).toBe(false);
|
|
@@ -1174,50 +1199,6 @@ describe('CommonTestAndPreview', () => {
|
|
|
1174
1199
|
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
1175
1200
|
});
|
|
1176
1201
|
});
|
|
1177
|
-
|
|
1178
|
-
it('should handle WEBPUSH channel', async () => {
|
|
1179
|
-
const webpushContent = {
|
|
1180
|
-
content: { title: 'Web Push', message: 'Hello from web push' },
|
|
1181
|
-
accountId: 'acc-001',
|
|
1182
|
-
};
|
|
1183
|
-
const props = {
|
|
1184
|
-
...defaultProps,
|
|
1185
|
-
channel: CHANNELS.WEBPUSH,
|
|
1186
|
-
content: webpushContent,
|
|
1187
|
-
};
|
|
1188
|
-
|
|
1189
|
-
render(
|
|
1190
|
-
<TestWrapper>
|
|
1191
|
-
<CommonTestAndPreview {...props} />
|
|
1192
|
-
</TestWrapper>
|
|
1193
|
-
);
|
|
1194
|
-
|
|
1195
|
-
await waitFor(() => {
|
|
1196
|
-
expect(screen.getByTestId('left-panel')).toBeTruthy();
|
|
1197
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
1198
|
-
});
|
|
1199
|
-
});
|
|
1200
|
-
|
|
1201
|
-
it('should treat WEBPUSH content as object (same branch as WHATSAPP)', async () => {
|
|
1202
|
-
// The WEBPUSH channel uses the same contentObj branch as WHATSAPP (JSON string or object)
|
|
1203
|
-
const props = {
|
|
1204
|
-
...defaultProps,
|
|
1205
|
-
channel: CHANNELS.WEBPUSH,
|
|
1206
|
-
content: JSON.stringify({
|
|
1207
|
-
content: { title: 'Stringified', message: 'Content' },
|
|
1208
|
-
}),
|
|
1209
|
-
};
|
|
1210
|
-
|
|
1211
|
-
render(
|
|
1212
|
-
<TestWrapper>
|
|
1213
|
-
<CommonTestAndPreview {...props} />
|
|
1214
|
-
</TestWrapper>
|
|
1215
|
-
);
|
|
1216
|
-
|
|
1217
|
-
await waitFor(() => {
|
|
1218
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
1219
|
-
});
|
|
1220
|
-
});
|
|
1221
1202
|
});
|
|
1222
1203
|
|
|
1223
1204
|
describe('Device Initialization', () => {
|
|
@@ -2673,156 +2654,6 @@ describe('CommonTestAndPreview', () => {
|
|
|
2673
2654
|
});
|
|
2674
2655
|
});
|
|
2675
2656
|
});
|
|
2676
|
-
|
|
2677
|
-
describe('preparePreviewPayload - WEBPUSH', () => {
|
|
2678
|
-
it('should build WEBPUSH payload with title and message', async () => {
|
|
2679
|
-
const webpushContent = {
|
|
2680
|
-
content: {
|
|
2681
|
-
title: 'Push Title',
|
|
2682
|
-
message: 'Push message body',
|
|
2683
|
-
},
|
|
2684
|
-
accountId: 'acc-123',
|
|
2685
|
-
messageSubject: 'Push Title',
|
|
2686
|
-
};
|
|
2687
|
-
const props = {
|
|
2688
|
-
...defaultProps,
|
|
2689
|
-
channel: CHANNELS.WEBPUSH,
|
|
2690
|
-
content: JSON.stringify(webpushContent),
|
|
2691
|
-
};
|
|
2692
|
-
|
|
2693
|
-
render(
|
|
2694
|
-
<TestWrapper>
|
|
2695
|
-
<CommonTestAndPreview {...props} />
|
|
2696
|
-
</TestWrapper>
|
|
2697
|
-
);
|
|
2698
|
-
|
|
2699
|
-
await waitFor(() => {
|
|
2700
|
-
expect(screen.getByTestId('left-panel')).toBeTruthy();
|
|
2701
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
2702
|
-
});
|
|
2703
|
-
});
|
|
2704
|
-
|
|
2705
|
-
it('should handle WEBPUSH content with iconImageUrl', async () => {
|
|
2706
|
-
const webpushContent = {
|
|
2707
|
-
content: {
|
|
2708
|
-
title: 'Hello',
|
|
2709
|
-
message: 'World',
|
|
2710
|
-
iconImageUrl: 'https://example.com/icon.png',
|
|
2711
|
-
},
|
|
2712
|
-
accountId: 'acc-123',
|
|
2713
|
-
};
|
|
2714
|
-
const props = {
|
|
2715
|
-
...defaultProps,
|
|
2716
|
-
channel: CHANNELS.WEBPUSH,
|
|
2717
|
-
content: webpushContent,
|
|
2718
|
-
};
|
|
2719
|
-
|
|
2720
|
-
render(
|
|
2721
|
-
<TestWrapper>
|
|
2722
|
-
<CommonTestAndPreview {...props} />
|
|
2723
|
-
</TestWrapper>
|
|
2724
|
-
);
|
|
2725
|
-
|
|
2726
|
-
await waitFor(() => {
|
|
2727
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
2728
|
-
});
|
|
2729
|
-
});
|
|
2730
|
-
|
|
2731
|
-
it('should handle WEBPUSH content with cta', async () => {
|
|
2732
|
-
const webpushContent = {
|
|
2733
|
-
content: {
|
|
2734
|
-
title: 'Hello',
|
|
2735
|
-
message: 'World',
|
|
2736
|
-
cta: { type: 'EXTERNAL_URL', actionLink: 'https://example.com' },
|
|
2737
|
-
},
|
|
2738
|
-
accountId: 'acc-123',
|
|
2739
|
-
};
|
|
2740
|
-
const props = {
|
|
2741
|
-
...defaultProps,
|
|
2742
|
-
channel: CHANNELS.WEBPUSH,
|
|
2743
|
-
content: webpushContent,
|
|
2744
|
-
};
|
|
2745
|
-
|
|
2746
|
-
render(
|
|
2747
|
-
<TestWrapper>
|
|
2748
|
-
<CommonTestAndPreview {...props} />
|
|
2749
|
-
</TestWrapper>
|
|
2750
|
-
);
|
|
2751
|
-
|
|
2752
|
-
await waitFor(() => {
|
|
2753
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
2754
|
-
});
|
|
2755
|
-
});
|
|
2756
|
-
|
|
2757
|
-
it('should handle WEBPUSH content with expandableDetails', async () => {
|
|
2758
|
-
const webpushContent = {
|
|
2759
|
-
content: {
|
|
2760
|
-
title: 'Hello',
|
|
2761
|
-
message: 'World',
|
|
2762
|
-
expandableDetails: {
|
|
2763
|
-
media: [{ url: 'https://example.com/image.jpg', type: 'IMAGE' }],
|
|
2764
|
-
ctas: [{ title: 'Click', actionLink: 'https://example.com', type: 'EXTERNAL_URL' }],
|
|
2765
|
-
},
|
|
2766
|
-
},
|
|
2767
|
-
accountId: 'acc-123',
|
|
2768
|
-
};
|
|
2769
|
-
const props = {
|
|
2770
|
-
...defaultProps,
|
|
2771
|
-
channel: CHANNELS.WEBPUSH,
|
|
2772
|
-
content: webpushContent,
|
|
2773
|
-
};
|
|
2774
|
-
|
|
2775
|
-
render(
|
|
2776
|
-
<TestWrapper>
|
|
2777
|
-
<CommonTestAndPreview {...props} />
|
|
2778
|
-
</TestWrapper>
|
|
2779
|
-
);
|
|
2780
|
-
|
|
2781
|
-
await waitFor(() => {
|
|
2782
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
2783
|
-
});
|
|
2784
|
-
});
|
|
2785
|
-
|
|
2786
|
-
it('should handle WEBPUSH with null formData gracefully', async () => {
|
|
2787
|
-
const props = {
|
|
2788
|
-
...defaultProps,
|
|
2789
|
-
channel: CHANNELS.WEBPUSH,
|
|
2790
|
-
formData: null,
|
|
2791
|
-
content: null,
|
|
2792
|
-
};
|
|
2793
|
-
|
|
2794
|
-
render(
|
|
2795
|
-
<TestWrapper>
|
|
2796
|
-
<CommonTestAndPreview {...props} />
|
|
2797
|
-
</TestWrapper>
|
|
2798
|
-
);
|
|
2799
|
-
|
|
2800
|
-
await waitFor(() => {
|
|
2801
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
2802
|
-
});
|
|
2803
|
-
});
|
|
2804
|
-
|
|
2805
|
-
it('should handle WEBPUSH channel with object content (non-string)', async () => {
|
|
2806
|
-
const props = {
|
|
2807
|
-
...defaultProps,
|
|
2808
|
-
channel: CHANNELS.WEBPUSH,
|
|
2809
|
-
content: {
|
|
2810
|
-
content: { title: 'ObjTitle', message: 'ObjMessage' },
|
|
2811
|
-
accountId: 'acc-999',
|
|
2812
|
-
},
|
|
2813
|
-
};
|
|
2814
|
-
|
|
2815
|
-
render(
|
|
2816
|
-
<TestWrapper>
|
|
2817
|
-
<CommonTestAndPreview {...props} />
|
|
2818
|
-
</TestWrapper>
|
|
2819
|
-
);
|
|
2820
|
-
|
|
2821
|
-
await waitFor(() => {
|
|
2822
|
-
expect(screen.getByTestId('preview-section')).toBeTruthy();
|
|
2823
|
-
});
|
|
2824
|
-
});
|
|
2825
|
-
});
|
|
2826
2657
|
});
|
|
2827
2658
|
|
|
2828
2659
|
describe('Tag Extraction', () => {
|
|
@@ -3475,4 +3306,107 @@ describe('CommonTestAndPreview', () => {
|
|
|
3475
3306
|
});
|
|
3476
3307
|
});
|
|
3477
3308
|
});
|
|
3309
|
+
|
|
3310
|
+
describe('SMS DLT and mustache tag discrimination (smsTemplateHasMustacheTags / buildSyntheticSmsMustacheTags)', () => {
|
|
3311
|
+
it('should return no tags for SMS content that contains only DLT {#var#} tokens', async () => {
|
|
3312
|
+
render(
|
|
3313
|
+
<TestWrapper>
|
|
3314
|
+
<CommonTestAndPreview
|
|
3315
|
+
{...defaultProps}
|
|
3316
|
+
channel={CHANNELS.SMS}
|
|
3317
|
+
formData={{ 0: { 'sms-editor': 'Order {#orderId#} is confirmed' } }}
|
|
3318
|
+
extractedTags={[]}
|
|
3319
|
+
/>
|
|
3320
|
+
</TestWrapper>
|
|
3321
|
+
);
|
|
3322
|
+
|
|
3323
|
+
await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
|
|
3324
|
+
|
|
3325
|
+
// smsTemplateHasMustacheTags returns false for DLT-only → extractedTags is []
|
|
3326
|
+
expect(lastLeftPanelContentProps.extractedTags).toEqual([]);
|
|
3327
|
+
});
|
|
3328
|
+
|
|
3329
|
+
it('should build synthetic tags from {{mustache}} tokens, excluding DLT {#var#} tokens', async () => {
|
|
3330
|
+
render(
|
|
3331
|
+
<TestWrapper>
|
|
3332
|
+
<CommonTestAndPreview
|
|
3333
|
+
{...defaultProps}
|
|
3334
|
+
channel={CHANNELS.SMS}
|
|
3335
|
+
formData={{ 0: { 'sms-editor': 'Hi {{name}}, order {#orderId#} shipped' } }}
|
|
3336
|
+
extractedTags={[]}
|
|
3337
|
+
/>
|
|
3338
|
+
</TestWrapper>
|
|
3339
|
+
);
|
|
3340
|
+
|
|
3341
|
+
await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
|
|
3342
|
+
|
|
3343
|
+
const tags = lastLeftPanelContentProps.extractedTags;
|
|
3344
|
+
// Only {{name}} should become a tag — {#orderId#} must be excluded
|
|
3345
|
+
expect(tags).toHaveLength(1);
|
|
3346
|
+
expect(tags[0].name).toBe('name');
|
|
3347
|
+
});
|
|
3348
|
+
|
|
3349
|
+
it('should use API-extracted tags when present instead of building synthetic ones', async () => {
|
|
3350
|
+
const apiTags = [{ name: 'firstName', metaData: { userDriven: true }, children: [] }];
|
|
3351
|
+
render(
|
|
3352
|
+
<TestWrapper>
|
|
3353
|
+
<CommonTestAndPreview
|
|
3354
|
+
{...defaultProps}
|
|
3355
|
+
channel={CHANNELS.SMS}
|
|
3356
|
+
formData={{ 0: { 'sms-editor': 'Hi {{firstName}}' } }}
|
|
3357
|
+
extractedTags={apiTags}
|
|
3358
|
+
/>
|
|
3359
|
+
</TestWrapper>
|
|
3360
|
+
);
|
|
3361
|
+
|
|
3362
|
+
await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
|
|
3363
|
+
|
|
3364
|
+
// API tags take priority over buildSyntheticSmsMustacheTags
|
|
3365
|
+
expect(lastLeftPanelContentProps.extractedTags).toEqual(apiTags);
|
|
3366
|
+
});
|
|
3367
|
+
});
|
|
3368
|
+
|
|
3369
|
+
describe('handleDiscardCustomValues — preview reset', () => {
|
|
3370
|
+
it('should call updatePreviewRequested when handleDiscardCustomValues is invoked', async () => {
|
|
3371
|
+
render(
|
|
3372
|
+
<TestWrapper>
|
|
3373
|
+
<CommonTestAndPreview
|
|
3374
|
+
{...defaultProps}
|
|
3375
|
+
channel={CHANNELS.SMS}
|
|
3376
|
+
formData={{ 0: { 'sms-editor': 'Hi {{name}}' } }}
|
|
3377
|
+
/>
|
|
3378
|
+
</TestWrapper>
|
|
3379
|
+
);
|
|
3380
|
+
|
|
3381
|
+
await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
|
|
3382
|
+
|
|
3383
|
+
lastCustomValuesEditorProps.handleDiscardCustomValues();
|
|
3384
|
+
|
|
3385
|
+
expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
|
|
3386
|
+
});
|
|
3387
|
+
|
|
3388
|
+
it('should call updatePreviewRequested with RCS channel when handleDiscardCustomValues is invoked for RCS with fallback', async () => {
|
|
3389
|
+
render(
|
|
3390
|
+
<TestWrapper>
|
|
3391
|
+
<CommonTestAndPreview
|
|
3392
|
+
{...defaultProps}
|
|
3393
|
+
channel={CHANNELS.RCS}
|
|
3394
|
+
smsFallbackContent={{
|
|
3395
|
+
templateContent: 'Fallback {{name}}',
|
|
3396
|
+
content: 'Fallback {{name}}',
|
|
3397
|
+
}}
|
|
3398
|
+
formData={{}}
|
|
3399
|
+
/>
|
|
3400
|
+
</TestWrapper>
|
|
3401
|
+
);
|
|
3402
|
+
|
|
3403
|
+
await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
|
|
3404
|
+
|
|
3405
|
+
lastCustomValuesEditorProps.handleDiscardCustomValues();
|
|
3406
|
+
|
|
3407
|
+
// updatePreviewRequested is called; syncSmsFallbackPreview (which hits Api directly) is NOT called
|
|
3408
|
+
expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
|
|
3409
|
+
});
|
|
3410
|
+
});
|
|
3478
3411
|
});
|
|
3412
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizePreviewApiPayload,
|
|
3
|
+
extractPreviewFromLiquidResponse,
|
|
4
|
+
getSmsFallbackTextForTagExtraction,
|
|
5
|
+
} from '../previewApiUtils';
|
|
6
|
+
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../constants';
|
|
7
|
+
|
|
8
|
+
describe('previewApiUtils', () => {
|
|
9
|
+
describe('normalizePreviewApiPayload', () => {
|
|
10
|
+
it('maps messageBody to resolvedBody when resolvedBody is missing', () => {
|
|
11
|
+
expect(normalizePreviewApiPayload({ messageBody: 'Hello' }).resolvedBody).toBe('Hello');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('extractPreviewFromLiquidResponse', () => {
|
|
16
|
+
it('accepts nested data shape', () => {
|
|
17
|
+
const r = { data: { resolvedBody: 'ok' } };
|
|
18
|
+
expect(extractPreviewFromLiquidResponse(r)).toEqual({ resolvedBody: 'ok' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('accepts top-level preview (typical SMS)', () => {
|
|
22
|
+
const r = { messageBody: 'sms text' };
|
|
23
|
+
expect(extractPreviewFromLiquidResponse(r)).toMatchObject({
|
|
24
|
+
messageBody: 'sms text',
|
|
25
|
+
resolvedBody: 'sms text',
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('returns null when errors array is non-empty', () => {
|
|
30
|
+
expect(extractPreviewFromLiquidResponse({ errors: [{ code: 1 }] })).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('getSmsFallbackTextForTagExtraction', () => {
|
|
35
|
+
it('returns empty string when context is missing or has no template body', () => {
|
|
36
|
+
expect(getSmsFallbackTextForTagExtraction(null)).toBe('');
|
|
37
|
+
expect(getSmsFallbackTextForTagExtraction({})).toBe('');
|
|
38
|
+
expect(getSmsFallbackTextForTagExtraction({ templateContent: '', content: '' })).toBe('');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('returns raw template when rcsSmsFallbackVarMapped is absent or empty', () => {
|
|
42
|
+
const raw = '{{optout}} {{fullname}} test SMS';
|
|
43
|
+
expect(getSmsFallbackTextForTagExtraction({ templateContent: raw })).toBe(raw);
|
|
44
|
+
expect(getSmsFallbackTextForTagExtraction({
|
|
45
|
+
content: raw,
|
|
46
|
+
[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]: {},
|
|
47
|
+
})).toBe(raw);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('prefers templateContent over content when both are set', () => {
|
|
51
|
+
expect(getSmsFallbackTextForTagExtraction({
|
|
52
|
+
templateContent: 'A',
|
|
53
|
+
content: 'B',
|
|
54
|
+
})).toBe('A');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('applies VarSegment slot map so preview / meta payloads are not stale vs raw template', () => {
|
|
58
|
+
const rawTemplateWithSlots = '{{optout}} tail';
|
|
59
|
+
const rcsSmsFallbackVarMappedSlots = { '{{optout}}_0': 'STOP' };
|
|
60
|
+
const resolvedFallbackText = getSmsFallbackTextForTagExtraction({
|
|
61
|
+
templateContent: rawTemplateWithSlots,
|
|
62
|
+
[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]: rcsSmsFallbackVarMappedSlots,
|
|
63
|
+
});
|
|
64
|
+
expect(resolvedFallbackText).toBe('STOP tail');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
-
call, put, takeLatest, all,
|
|
8
|
+
call, put, takeLatest, takeEvery, all, take, fork, cancel,
|
|
9
9
|
} from 'redux-saga/effects';
|
|
10
10
|
import {
|
|
11
11
|
searchCustomersSaga,
|
|
@@ -1333,9 +1333,26 @@ describe('CommonTestAndPreview Sagas', () => {
|
|
|
1333
1333
|
it('should watch for GET_SENDER_DETAILS_REQUESTED', () => {
|
|
1334
1334
|
const generator = watchGetSenderDetails();
|
|
1335
1335
|
expect(generator.next().value).toEqual(
|
|
1336
|
-
|
|
1336
|
+
take('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED')
|
|
1337
|
+
);
|
|
1338
|
+
const firstAction = {
|
|
1339
|
+
payload: { channel: 'RCS', orgUnitId: 10 },
|
|
1340
|
+
};
|
|
1341
|
+
expect(generator.next(firstAction).value).toEqual(
|
|
1342
|
+
fork(getSenderDetailsSaga, firstAction)
|
|
1343
|
+
);
|
|
1344
|
+
expect(generator.next({ '@@redux-saga/TASK': true }).value).toEqual(
|
|
1345
|
+
take('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED')
|
|
1346
|
+
);
|
|
1347
|
+
const secondAction = {
|
|
1348
|
+
payload: { channel: 'RCS', orgUnitId: 20 },
|
|
1349
|
+
};
|
|
1350
|
+
expect(generator.next(secondAction).value).toEqual(
|
|
1351
|
+
cancel({ '@@redux-saga/TASK': true })
|
|
1352
|
+
);
|
|
1353
|
+
expect(generator.next().value).toEqual(
|
|
1354
|
+
fork(getSenderDetailsSaga, secondAction)
|
|
1337
1355
|
);
|
|
1338
|
-
expect(generator.next().done).toBe(true);
|
|
1339
1356
|
});
|
|
1340
1357
|
|
|
1341
1358
|
it('should watch for GET_WECRM_ACCOUNTS_REQUESTED', () => {
|
|
@@ -1454,34 +1471,27 @@ describe('CommonTestAndPreview Sagas', () => {
|
|
|
1454
1471
|
const action = { payload: {} };
|
|
1455
1472
|
const generator = getWeCrmAccountsSaga(action);
|
|
1456
1473
|
generator.next();
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1474
|
+
try {
|
|
1475
|
+
generator.throw(new Error('API failed'));
|
|
1476
|
+
} catch (errValue) {
|
|
1477
|
+
expect(errValue).toEqual(
|
|
1478
|
+
put({ type: GET_WECRM_ACCOUNTS_FAILURE, payload: { error: 'API failed' } })
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1461
1481
|
expect(generator.next().done).toBe(true);
|
|
1462
1482
|
});
|
|
1463
1483
|
});
|
|
1464
1484
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
const generator = commonTestAndPreviewSaga();
|
|
1485
|
+
it('should initialize all watcher sagas', () => {
|
|
1486
|
+
const generator = commonTestAndPreviewSaga();
|
|
1468
1487
|
|
|
1469
|
-
|
|
1470
|
-
all([
|
|
1471
|
-
watchSearchCustomers(),
|
|
1472
|
-
watchExtractTags(),
|
|
1473
|
-
watchUpdatePreview(),
|
|
1474
|
-
watchSendTestMessage(),
|
|
1475
|
-
watchFetchTestCustomers(),
|
|
1476
|
-
watchFetchTestGroups(),
|
|
1477
|
-
watchCreateMessageMeta(),
|
|
1478
|
-
watchGetPrefilledValues(),
|
|
1479
|
-
watchGetSenderDetails(),
|
|
1480
|
-
watchGetWeCrmAccounts(),
|
|
1481
|
-
])
|
|
1482
|
-
);
|
|
1488
|
+
const effect = generator.next().value;
|
|
1483
1489
|
|
|
1484
|
-
|
|
1485
|
-
|
|
1490
|
+
// redux-saga v0.x stores the array under effect[ALL] key; v1.x uses effect.payload
|
|
1491
|
+
const effectData = effect?.payload || effect?.ALL;
|
|
1492
|
+
const watchers = Array.isArray(effectData) ? effectData : Object.values(effectData || {});
|
|
1493
|
+
expect(Array.isArray(watchers)).toBe(true);
|
|
1494
|
+
expect(watchers.length).toBeGreaterThan(0);
|
|
1495
|
+
expect(generator.next().done).toBe(true);
|
|
1486
1496
|
});
|
|
1487
1497
|
});
|
|
@@ -37,6 +37,7 @@ import { createStructuredSelector } from 'reselect';
|
|
|
37
37
|
import { CAP_SPACE_12, CAP_SPACE_08, FONT_COLOR_05, FONT_COLOR_04 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
38
38
|
import UnifiedPreview from '../CommonTestAndPreview/UnifiedPreview';
|
|
39
39
|
import { ANDROID } from '../CommonTestAndPreview/constants';
|
|
40
|
+
import TemplatePreview from '../TemplatePreview';
|
|
40
41
|
import TagList from '../../v2Containers/TagList';
|
|
41
42
|
import CapTagListWithInput from '../CapTagListWithInput';
|
|
42
43
|
import SlideBox from '../SlideBox';
|
|
@@ -2989,8 +2990,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2989
2990
|
userLocale={this.props.userLocale}
|
|
2990
2991
|
selectedOfferDetails={this.props.selectedOfferDetails}
|
|
2991
2992
|
eventContextTags={this.props?.eventContextTags}
|
|
2992
|
-
restrictPersonalization={this.props.restrictPersonalization}
|
|
2993
2993
|
waitEventContextTags={this.props?.waitEventContextTags}
|
|
2994
|
+
restrictPersonalization={this.props.restrictPersonalization}
|
|
2994
2995
|
/>
|
|
2995
2996
|
</CapColumn>
|
|
2996
2997
|
);
|
|
@@ -3659,8 +3660,11 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
3659
3660
|
selectedOfferDetails={this.props.selectedOfferDetails}
|
|
3660
3661
|
channel={channel}
|
|
3661
3662
|
eventContextTags={this.props?.eventContextTags}
|
|
3662
|
-
restrictPersonalization={this.props.restrictPersonalization}
|
|
3663
3663
|
waitEventContextTags={this.props?.waitEventContextTags}
|
|
3664
|
+
restrictPersonalization={this.props.restrictPersonalization}
|
|
3665
|
+
getPopupContainer={this.props.tagListGetPopupContainer}
|
|
3666
|
+
popoverOverlayStyle={this.props.tagListPopoverOverlayStyle}
|
|
3667
|
+
popoverOverlayClassName={this.props.tagListPopoverOverlayClassName}
|
|
3664
3668
|
/>
|
|
3665
3669
|
</CapColumn>
|
|
3666
3670
|
);
|
|
@@ -4003,8 +4007,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
4003
4007
|
moduleFilterEnabled={isModuleFilterEnabled}
|
|
4004
4008
|
eventContextTags={this.props?.eventContextTags}
|
|
4005
4009
|
waitEventContextTags={this.props?.waitEventContextTags}
|
|
4006
|
-
isGetBeeData={this.props?.isGetBeeData}
|
|
4007
|
-
getBEEData={this.props?.getBEEData}
|
|
4008
4010
|
/>
|
|
4009
4011
|
</CapColumn>
|
|
4010
4012
|
);
|
|
@@ -4307,8 +4309,8 @@ FormBuilder.defaultProps = {
|
|
|
4307
4309
|
userLocale: localStorage.getItem('jlocale') || 'en',
|
|
4308
4310
|
showLiquidErrorInFooter: () => {},
|
|
4309
4311
|
metaDataStatus: "",
|
|
4310
|
-
waitEventContextTags: {},
|
|
4311
4312
|
isTestAndPreviewMode: false, // Default to false to maintain existing behavior
|
|
4313
|
+
waitEventContextTags: {},
|
|
4312
4314
|
};
|
|
4313
4315
|
|
|
4314
4316
|
FormBuilder.propTypes = {
|
|
@@ -4356,13 +4358,16 @@ FormBuilder.propTypes = {
|
|
|
4356
4358
|
type: PropTypes.string.isRequired,
|
|
4357
4359
|
isEmailLoading: PropTypes.bool.isRequired,
|
|
4358
4360
|
moduleType: PropTypes.string.isRequired,
|
|
4359
|
-
showLiquidErrorInFooter: PropTypes.
|
|
4361
|
+
showLiquidErrorInFooter: PropTypes.func.isRequired,
|
|
4360
4362
|
eventContextTags: PropTypes.array.isRequired,
|
|
4361
4363
|
waitEventContextTags: PropTypes.object,
|
|
4362
4364
|
forwardedTags: PropTypes.object.isRequired,
|
|
4363
4365
|
isLoyaltyModule: PropTypes.bool.isRequired,
|
|
4364
4366
|
isTestAndPreviewMode: PropTypes.bool, // Add new prop type
|
|
4365
4367
|
restrictPersonalization: PropTypes.bool,
|
|
4368
|
+
tagListGetPopupContainer: PropTypes.func,
|
|
4369
|
+
tagListPopoverOverlayStyle: PropTypes.object,
|
|
4370
|
+
tagListPopoverOverlayClassName: PropTypes.string,
|
|
4366
4371
|
};
|
|
4367
4372
|
|
|
4368
4373
|
const mapStateToProps = createStructuredSelector({
|