cap-creatives-ui 8.0.280 → 8.0.321
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/.github/workflows/pr-title-check.yml +88 -0
- package/app/constants/unified.js +21 -1
- package/app/containers/App/constants.js +0 -1
- package/app/containers/Login/test/index.test.js +123 -0
- package/app/containers/Login/test/selectors.test.js +165 -0
- package/app/initialState.js +0 -2
- package/app/services/api.js +6 -0
- package/app/services/tests/api.test.js +7 -0
- package/app/services/tests/getSchema.test.js +95 -0
- package/app/utils/common.js +23 -9
- package/app/utils/commonUtils.js +64 -93
- package/app/utils/tagValidations.js +83 -219
- package/app/utils/templateVarUtils.js +172 -0
- package/app/utils/tests/common.test.js +265 -323
- package/app/utils/tests/commonUtil.test.js +461 -118
- package/app/utils/tests/commonUtils.test.js +581 -0
- package/app/utils/tests/messageUtils.test.js +95 -0
- package/app/utils/tests/smsCharCount.test.js +304 -0
- package/app/utils/tests/smsCharCountV2.test.js +213 -10
- package/app/utils/tests/tagValidations.test.js +474 -357
- package/app/utils/tests/templateVarUtils.test.js +160 -0
- package/app/v2Components/CapDeviceContent/index.js +10 -7
- package/app/v2Components/CapTagList/index.js +32 -24
- package/app/v2Components/CapTagList/style.scss +48 -0
- package/app/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
- package/app/v2Components/CapTagListWithInput/index.js +8 -0
- package/app/v2Components/CapWhatsappCTA/index.js +2 -0
- package/app/v2Components/CapWhatsappCarouselButton/index.js +32 -14
- package/app/v2Components/CapWhatsappCarouselButton/tests/index.test.js +120 -2
- package/app/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +39 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +606 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.scss +36 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +79 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/index.js +314 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +141 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +156 -0
- package/app/v2Components/CommonTestAndPreview/SendTestMessage.js +57 -1
- package/app/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
- package/app/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
- package/app/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +210 -4
- package/app/v2Components/CommonTestAndPreview/actions.js +20 -0
- package/app/v2Components/CommonTestAndPreview/constants.js +57 -1
- package/app/v2Components/CommonTestAndPreview/index.js +878 -156
- package/app/v2Components/CommonTestAndPreview/messages.js +41 -3
- package/app/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/app/v2Components/CommonTestAndPreview/reducer.js +47 -0
- package/app/v2Components/CommonTestAndPreview/sagas.js +75 -5
- package/app/v2Components/CommonTestAndPreview/selectors.js +51 -0
- package/app/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
- package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +1156 -0
- package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +334 -0
- package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +576 -0
- package/app/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +156 -0
- package/app/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
- package/app/v2Components/CommonTestAndPreview/tests/actions.test.js +50 -0
- package/app/v2Components/CommonTestAndPreview/tests/constants.test.js +18 -7
- package/app/v2Components/CommonTestAndPreview/tests/index.test.js +914 -5
- package/app/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/app/v2Components/CommonTestAndPreview/tests/reducer.test.js +118 -0
- package/app/v2Components/CommonTestAndPreview/tests/sagas.test.js +146 -378
- package/app/v2Components/CommonTestAndPreview/tests/selectors.test.js +146 -0
- package/app/v2Components/ErrorInfoNote/index.js +24 -26
- package/app/v2Components/FormBuilder/index.js +182 -204
- package/app/v2Components/FormBuilder/messages.js +4 -8
- package/app/v2Components/HtmlEditor/HTMLEditor.js +7 -6
- package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -1
- package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +928 -17
- package/app/v2Components/HtmlEditor/components/CodeEditorPane/index.js +4 -2
- package/app/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +452 -3
- package/app/v2Components/HtmlEditor/hooks/useValidation.js +12 -9
- package/app/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +132 -0
- package/app/v2Components/HtmlEditor/utils/htmlValidator.js +4 -2
- package/app/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
- package/app/v2Components/SmsFallback/constants.js +73 -0
- package/app/v2Components/SmsFallback/index.js +956 -0
- package/app/v2Components/SmsFallback/index.scss +265 -0
- package/app/v2Components/SmsFallback/messages.js +78 -0
- package/app/v2Components/SmsFallback/smsFallbackUtils.js +107 -0
- package/app/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/app/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/app/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/app/v2Components/SmsFallback/tests/smsFallbackUi.test.js +197 -0
- package/app/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
- package/app/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/app/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/app/v2Components/TestAndPreviewSlidebox/index.js +22 -1
- package/app/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/app/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/app/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/app/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/app/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/app/v2Containers/BeeEditor/index.js +3 -0
- package/app/v2Containers/BeePopupEditor/index.js +9 -2
- package/app/v2Containers/Cap/mockData.js +0 -14
- package/app/v2Containers/Cap/reducer.js +3 -55
- package/app/v2Containers/Cap/tests/reducer.test.js +0 -102
- package/app/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
- package/app/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
- package/app/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
- package/app/v2Containers/CommunicationFlow/constants.js +200 -0
- package/app/v2Containers/CommunicationFlow/index.js +102 -0
- package/app/v2Containers/CommunicationFlow/messages.js +346 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
- package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
- package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
- package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
- package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
- package/app/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/app/v2Containers/CreativesContainer/SlideBoxContent.js +127 -11
- package/app/v2Containers/CreativesContainer/SlideBoxFooter.js +62 -9
- package/app/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/app/v2Containers/CreativesContainer/constants.js +24 -0
- package/app/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
- package/app/v2Containers/CreativesContainer/index.js +346 -71
- package/app/v2Containers/CreativesContainer/index.scss +51 -1
- package/app/v2Containers/CreativesContainer/messages.js +12 -0
- package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +69 -1
- package/app/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +443 -0
- package/app/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
- package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +147 -4
- package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
- package/app/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +57 -10
- package/app/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/app/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/app/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/app/v2Containers/Email/index.js +2 -5
- package/app/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +58 -77
- package/app/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
- package/app/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +158 -89
- package/app/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
- package/app/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +17 -12
- package/app/v2Containers/EmailWrapper/index.js +4 -0
- package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +133 -0
- package/app/v2Containers/FTP/index.js +2 -51
- package/app/v2Containers/FTP/messages.js +0 -4
- package/app/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +110 -155
- package/app/v2Containers/InApp/index.js +297 -118
- package/app/v2Containers/InApp/tests/index.test.js +17 -6
- package/app/v2Containers/InApp/tests/mockData.js +1 -1
- package/app/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
- package/app/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
- package/app/v2Containers/InAppWrapper/index.js +3 -0
- package/app/v2Containers/InappAdvance/index.js +5 -104
- package/app/v2Containers/InappAdvance/tests/index.test.js +2 -0
- package/app/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +24 -3
- package/app/v2Containers/Line/Container/Text/index.js +0 -1
- package/app/v2Containers/MobilePush/Create/index.js +105 -28
- package/app/v2Containers/MobilePush/Create/messages.js +4 -0
- package/app/v2Containers/MobilePush/Edit/index.js +250 -68
- package/app/v2Containers/MobilePush/Edit/messages.js +4 -0
- package/app/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
- package/app/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
- package/app/v2Containers/MobilePushNew/index.js +78 -35
- package/app/v2Containers/MobilePushNew/messages.js +8 -0
- package/app/v2Containers/MobilepushWrapper/index.js +11 -1
- package/app/v2Containers/Rcs/constants.js +32 -1
- package/app/v2Containers/Rcs/index.js +963 -916
- package/app/v2Containers/Rcs/index.scss +85 -6
- package/app/v2Containers/Rcs/messages.js +10 -1
- package/app/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
- package/app/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +41136 -1566
- package/app/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/app/v2Containers/Rcs/tests/index.test.js +41 -38
- package/app/v2Containers/Rcs/tests/mockData.js +38 -0
- package/app/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
- package/app/v2Containers/Rcs/tests/utils.test.js +379 -1
- package/app/v2Containers/Rcs/utils.js +358 -10
- package/app/v2Containers/Sms/Create/index.js +122 -39
- package/app/v2Containers/Sms/Create/messages.js +4 -0
- package/app/v2Containers/Sms/Edit/index.js +37 -3
- package/app/v2Containers/Sms/commonMethods.js +3 -6
- package/app/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/app/v2Containers/Sms/tests/commonMethods.test.js +122 -0
- package/app/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/app/v2Containers/SmsTrai/Create/index.js +9 -4
- package/app/v2Containers/SmsTrai/Create/index.scss +1 -1
- package/app/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/app/v2Containers/SmsTrai/Edit/index.js +667 -160
- package/app/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/app/v2Containers/SmsTrai/Edit/messages.js +9 -4
- package/app/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4590 -2436
- package/app/v2Containers/SmsWrapper/index.js +41 -8
- package/app/v2Containers/TagList/index.js +63 -2
- package/app/v2Containers/TagList/messages.js +8 -0
- package/app/v2Containers/TagList/tests/TagList.test.js +122 -20
- package/app/v2Containers/TagList/tests/mockdata.js +17 -0
- package/app/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/app/v2Containers/Templates/_templates.scss +61 -2
- package/app/v2Containers/Templates/actions.js +11 -0
- package/app/v2Containers/Templates/constants.js +2 -0
- package/app/v2Containers/Templates/index.js +90 -40
- package/app/v2Containers/Templates/reducer.js +3 -1
- package/app/v2Containers/Templates/sagas.js +57 -12
- package/app/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/app/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
- package/app/v2Containers/Templates/tests/reducer.test.js +12 -0
- package/app/v2Containers/Templates/tests/sagas.test.js +193 -12
- package/app/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/app/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/app/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/app/v2Containers/TemplatesV2/index.js +147 -49
- package/app/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/app/v2Containers/Viber/index.js +9 -10
- package/app/v2Containers/Viber/index.scss +1 -1
- package/app/v2Containers/WebPush/Create/components/BrandIconSection.test.js +264 -0
- package/app/v2Containers/WebPush/Create/components/MessageSection.js +78 -19
- package/app/v2Containers/WebPush/Create/components/MessageSection.test.js +82 -0
- package/app/v2Containers/WebPush/Create/components/__snapshots__/BrandIconSection.test.js.snap +187 -0
- package/app/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +25 -17
- package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.js +80 -0
- package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.test.js +210 -0
- package/app/v2Containers/WebPush/Create/hooks/useTagManagement.js +1 -5
- package/app/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -7
- package/app/v2Containers/WebPush/Create/index.js +36 -6
- package/app/v2Containers/WebPush/Create/index.scss +5 -0
- package/app/v2Containers/WebPush/Create/messages.js +8 -1
- package/app/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +269 -0
- package/app/v2Containers/WebPush/Create/utils/validation.js +31 -15
- package/app/v2Containers/WebPush/Create/utils/validation.test.js +72 -24
- package/app/v2Containers/Whatsapp/index.js +28 -53
- package/app/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +26939 -3982
- package/app/v2Containers/Whatsapp/tests/index.test.js +172 -0
- package/app/v2Containers/Zalo/index.js +5 -11
- package/package.json +2 -2
- package/version +9 -0
|
@@ -13,7 +13,7 @@ import { IntlProvider } from 'react-intl';
|
|
|
13
13
|
import EmailHTMLEditor from '../EmailHTMLEditor';
|
|
14
14
|
import { validateLiquidTemplateContent } from '../../../../utils/commonUtils';
|
|
15
15
|
import { validateTags } from '../../../../utils/tagValidations';
|
|
16
|
-
import {
|
|
16
|
+
import { isEmailUnsubscribeTagOptional } from '../../../../utils/common';
|
|
17
17
|
|
|
18
18
|
// Mock dependencies
|
|
19
19
|
jest.mock('../../../../utils/commonUtils', () => ({
|
|
@@ -24,11 +24,8 @@ jest.mock('../../../../utils/tagValidations', () => ({
|
|
|
24
24
|
validateTags: jest.fn(),
|
|
25
25
|
}));
|
|
26
26
|
|
|
27
|
-
// Create mutable mock for hasLiquidSupportFeature
|
|
28
|
-
const mockHasLiquidSupportFeature = jest.fn(() => true);
|
|
29
27
|
jest.mock('../../../../utils/common', () => ({
|
|
30
|
-
|
|
31
|
-
isEmailUnsubscribeTagMandatory: jest.fn(() => false),
|
|
28
|
+
isEmailUnsubscribeTagOptional: jest.fn(() => false),
|
|
32
29
|
}));
|
|
33
30
|
|
|
34
31
|
jest.mock('../../../../utils/history', () => ({
|
|
@@ -49,10 +46,16 @@ const mockGetValidationState = jest.fn(() => ({
|
|
|
49
46
|
issueCounts: { errors: 0, warnings: 0, total: 0 },
|
|
50
47
|
}));
|
|
51
48
|
|
|
49
|
+
// Ref to capture apiValidationErrors passed to HTMLEditor (for mergedApiValidationErrors tests)
|
|
50
|
+
const capturedApiValidationErrorsRef = { current: null };
|
|
51
|
+
|
|
52
52
|
// Mock HtmlEditor - it exports a lazy-loaded component by default
|
|
53
53
|
jest.mock('../../../../v2Components/HtmlEditor/index.lazy', () => {
|
|
54
54
|
const React = require('react');
|
|
55
55
|
const MockHTMLEditor = React.forwardRef((props, ref) => {
|
|
56
|
+
if (global.__captureApiValidationErrorsRef && props.apiValidationErrors) {
|
|
57
|
+
global.__captureApiValidationErrorsRef.current = props.apiValidationErrors;
|
|
58
|
+
}
|
|
56
59
|
React.useImperativeHandle(ref, () => ({
|
|
57
60
|
getAllIssues: () => mockGetAllIssues(),
|
|
58
61
|
getValidationState: () => mockGetValidationState(),
|
|
@@ -68,7 +71,10 @@ jest.mock('../../../../v2Components/HtmlEditor/index.lazy', () => {
|
|
|
68
71
|
}));
|
|
69
72
|
|
|
70
73
|
return (
|
|
71
|
-
<div
|
|
74
|
+
<div
|
|
75
|
+
data-testid="html-editor"
|
|
76
|
+
data-wait-event-context-tags={JSON.stringify(props.waitEventContextTags ?? null)}
|
|
77
|
+
>
|
|
72
78
|
<button
|
|
73
79
|
onClick={() => props.onContentChange && props.onContentChange('<p>New content</p>')}
|
|
74
80
|
data-testid="trigger-content-change"
|
|
@@ -109,6 +115,9 @@ jest.mock('../../../../v2Components/HtmlEditor/index.lazy', () => {
|
|
|
109
115
|
jest.mock('../../../../v2Components/HtmlEditor', () => {
|
|
110
116
|
const React = require('react');
|
|
111
117
|
const MockHTMLEditor = React.forwardRef((props, ref) => {
|
|
118
|
+
if (global.__captureApiValidationErrorsRef && props.apiValidationErrors) {
|
|
119
|
+
global.__captureApiValidationErrorsRef.current = props.apiValidationErrors;
|
|
120
|
+
}
|
|
112
121
|
React.useImperativeHandle(ref, () => ({
|
|
113
122
|
getAllIssues: () => mockGetAllIssues(),
|
|
114
123
|
getValidationState: () => mockGetValidationState(),
|
|
@@ -124,7 +133,10 @@ jest.mock('../../../../v2Components/HtmlEditor', () => {
|
|
|
124
133
|
}));
|
|
125
134
|
|
|
126
135
|
return (
|
|
127
|
-
<div
|
|
136
|
+
<div
|
|
137
|
+
data-testid="html-editor"
|
|
138
|
+
data-wait-event-context-tags={JSON.stringify(props.waitEventContextTags ?? null)}
|
|
139
|
+
>
|
|
128
140
|
<button
|
|
129
141
|
onClick={() => props.onContentChange && props.onContentChange('<p>New content</p>')}
|
|
130
142
|
data-testid="trigger-content-change"
|
|
@@ -358,6 +370,7 @@ const defaultProps = {
|
|
|
358
370
|
},
|
|
359
371
|
loadingTags: false,
|
|
360
372
|
eventContextTags: [],
|
|
373
|
+
waitEventContextTags: {},
|
|
361
374
|
forwardedTags: {},
|
|
362
375
|
selectedOfferDetails: [],
|
|
363
376
|
currentOrgDetails: {
|
|
@@ -411,7 +424,7 @@ describe('EmailHTMLEditor', () => {
|
|
|
411
424
|
jest.clearAllMocks();
|
|
412
425
|
validateLiquidTemplateContent.mockResolvedValue(true);
|
|
413
426
|
validateTags.mockReturnValue({ valid: true });
|
|
414
|
-
|
|
427
|
+
isEmailUnsubscribeTagOptional.mockReturnValue(false);
|
|
415
428
|
// Reset mock functions
|
|
416
429
|
mockGetAllIssues.mockReturnValue([]);
|
|
417
430
|
mockGetValidationState.mockReturnValue({
|
|
@@ -419,8 +432,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
419
432
|
hasErrors: false,
|
|
420
433
|
issueCounts: { errors: 0, warnings: 0, total: 0 },
|
|
421
434
|
});
|
|
422
|
-
// Reset hasLiquidSupportFeature mock to return true by default
|
|
423
|
-
mockHasLiquidSupportFeature.mockReturnValue(true);
|
|
424
435
|
});
|
|
425
436
|
|
|
426
437
|
describe('Default Parameter Values (lines 60-63)', () => {
|
|
@@ -518,6 +529,17 @@ describe('EmailHTMLEditor', () => {
|
|
|
518
529
|
});
|
|
519
530
|
});
|
|
520
531
|
|
|
532
|
+
describe('waitEventContextTags', () => {
|
|
533
|
+
it('forwards waitEventContextTags to HTMLEditor', () => {
|
|
534
|
+
const waitMap = { b1: { eventName: 'E', blockName: 'B', tags: ['t'] } };
|
|
535
|
+
renderWithIntl({ waitEventContextTags: waitMap });
|
|
536
|
+
expect(screen.getByTestId('html-editor')).toHaveAttribute(
|
|
537
|
+
'data-wait-event-context-tags',
|
|
538
|
+
JSON.stringify(waitMap),
|
|
539
|
+
);
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
|
|
521
543
|
describe('Content Initialization', () => {
|
|
522
544
|
it('initializes with empty content in create mode', () => {
|
|
523
545
|
renderWithIntl({ isGetFormData: false });
|
|
@@ -1016,38 +1038,8 @@ describe('EmailHTMLEditor', () => {
|
|
|
1016
1038
|
}, { timeout: 3000 });
|
|
1017
1039
|
});
|
|
1018
1040
|
|
|
1019
|
-
it('blocks save when unsubscribe validation is on (flag false) and tag is missing', async () => {
|
|
1020
|
-
// When EMAIL_UNSUBSCRIBE_TAG_MANDATORY is false we validate and require unsubscribe
|
|
1021
|
-
isEmailUnsubscribeTagMandatory.mockReturnValue(false);
|
|
1022
|
-
const onValidationFail = jest.fn();
|
|
1023
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
1024
|
-
|
|
1025
|
-
// Set subject via input and content via HTMLEditor mock
|
|
1026
|
-
const { rerender } = renderWithIntl({
|
|
1027
|
-
onValidationFail,
|
|
1028
|
-
isGetFormData: false,
|
|
1029
|
-
moduleType: 'OUTBOUND',
|
|
1030
|
-
});
|
|
1031
|
-
const input = screen.getByTestId('subject-input');
|
|
1032
|
-
fireEvent.change(input, { target: { value: 'Valid Subject' } });
|
|
1033
|
-
// Trigger content change to set htmlContent
|
|
1034
|
-
const changeButton = screen.getByTestId('trigger-content-change');
|
|
1035
|
-
fireEvent.click(changeButton);
|
|
1036
|
-
// Now trigger save
|
|
1037
|
-
rerender(
|
|
1038
|
-
<IntlProvider locale="en" messages={{}}>
|
|
1039
|
-
<EmailHTMLEditor {...defaultProps} onValidationFail={onValidationFail} isGetFormData moduleType="OUTBOUND" />
|
|
1040
|
-
</IntlProvider>
|
|
1041
|
-
);
|
|
1042
|
-
|
|
1043
|
-
await waitFor(() => {
|
|
1044
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
1045
|
-
expect(onValidationFail).toHaveBeenCalled();
|
|
1046
|
-
}, { timeout: 3000 });
|
|
1047
|
-
});
|
|
1048
|
-
|
|
1049
1041
|
it('allows save when unsubscribe validation is on and tag is present', () => {
|
|
1050
|
-
|
|
1042
|
+
isEmailUnsubscribeTagOptional.mockReturnValue(false);
|
|
1051
1043
|
renderWithIntl({
|
|
1052
1044
|
isGetFormData: true,
|
|
1053
1045
|
subject: 'Valid Subject',
|
|
@@ -1057,49 +1049,44 @@ describe('EmailHTMLEditor', () => {
|
|
|
1057
1049
|
// Should proceed with save (validation passes)
|
|
1058
1050
|
});
|
|
1059
1051
|
|
|
1060
|
-
it('blocks save
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
missingTags: ['tag2'],
|
|
1052
|
+
it('blocks save when liquid API validation fails for Email', async () => {
|
|
1053
|
+
// Liquid validation runs in library mode (!isFullMode). Simulate API validation failure via mock onError.
|
|
1054
|
+
validateLiquidTemplateContent.mockImplementation((content, options) => {
|
|
1055
|
+
options.onError({ standardErrors: [], liquidErrors: ['Validation failed'] });
|
|
1056
|
+
return Promise.resolve(false);
|
|
1066
1057
|
});
|
|
1067
1058
|
const onValidationFail = jest.fn();
|
|
1068
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
1069
|
-
|
|
1070
|
-
// Set subject and content via component interactions
|
|
1071
1059
|
const { rerender } = renderWithIntl({
|
|
1072
1060
|
onValidationFail,
|
|
1073
1061
|
isGetFormData: false,
|
|
1062
|
+
isFullMode: false,
|
|
1074
1063
|
metaEntities: {
|
|
1075
1064
|
tags: {
|
|
1076
1065
|
standard: [{ name: 'customer.name' }],
|
|
1077
1066
|
},
|
|
1078
1067
|
},
|
|
1079
|
-
getLiquidTags:
|
|
1068
|
+
getLiquidTags: jest.fn((content, cb) => cb({ askAiraResponse: { data: [] }, isError: false })),
|
|
1080
1069
|
});
|
|
1081
1070
|
const input = screen.getByTestId('subject-input');
|
|
1082
1071
|
fireEvent.change(input, { target: { value: 'Valid Subject' } });
|
|
1083
1072
|
const changeButton = screen.getByTestId('trigger-content-change');
|
|
1084
1073
|
fireEvent.click(changeButton);
|
|
1085
|
-
// Now trigger save
|
|
1086
1074
|
rerender(
|
|
1087
1075
|
<IntlProvider locale="en" messages={{}}>
|
|
1088
1076
|
<EmailHTMLEditor
|
|
1089
1077
|
{...defaultProps}
|
|
1090
1078
|
onValidationFail={onValidationFail}
|
|
1091
1079
|
isGetFormData
|
|
1080
|
+
isFullMode={false}
|
|
1092
1081
|
metaEntities={{
|
|
1093
1082
|
tags: {
|
|
1094
1083
|
standard: [{ name: 'customer.name' }],
|
|
1095
1084
|
},
|
|
1096
1085
|
}}
|
|
1097
|
-
getLiquidTags={
|
|
1086
|
+
getLiquidTags={jest.fn((content, cb) => cb({ askAiraResponse: { data: [] }, isError: false }))} />
|
|
1098
1087
|
</IntlProvider>
|
|
1099
1088
|
);
|
|
1100
|
-
|
|
1101
1089
|
await waitFor(() => {
|
|
1102
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
1103
1090
|
expect(onValidationFail).toHaveBeenCalled();
|
|
1104
1091
|
}, { timeout: 3000 });
|
|
1105
1092
|
});
|
|
@@ -1116,16 +1103,16 @@ describe('EmailHTMLEditor', () => {
|
|
|
1116
1103
|
// Ensure no HTML/Label/Liquid errors from HtmlEditor
|
|
1117
1104
|
mockGetAllIssues.mockReturnValue([]);
|
|
1118
1105
|
|
|
1119
|
-
//
|
|
1106
|
+
// Liquid validation runs only in library mode
|
|
1107
|
+
// Use isFullMode: false (library mode) to test liquid validation path
|
|
1120
1108
|
const { rerender } = renderWithIntl({
|
|
1121
1109
|
isGetFormData: false,
|
|
1122
|
-
isFullMode:
|
|
1110
|
+
isFullMode: false,
|
|
1123
1111
|
metaEntities: {
|
|
1124
1112
|
tags: {
|
|
1125
1113
|
standard: [{ name: 'customer.name' }],
|
|
1126
1114
|
},
|
|
1127
1115
|
},
|
|
1128
|
-
isLiquidEnabled: true,
|
|
1129
1116
|
getLiquidTags,
|
|
1130
1117
|
});
|
|
1131
1118
|
const input = screen.getByTestId('subject-input');
|
|
@@ -1147,7 +1134,7 @@ describe('EmailHTMLEditor', () => {
|
|
|
1147
1134
|
<EmailHTMLEditor
|
|
1148
1135
|
{...defaultProps}
|
|
1149
1136
|
isGetFormData
|
|
1150
|
-
isFullMode
|
|
1137
|
+
isFullMode={false}
|
|
1151
1138
|
metaEntities={{
|
|
1152
1139
|
tags: {
|
|
1153
1140
|
standard: [{ name: 'customer.name' }],
|
|
@@ -1171,11 +1158,11 @@ describe('EmailHTMLEditor', () => {
|
|
|
1171
1158
|
// Ensure no HTML/Label/Liquid errors from HtmlEditor
|
|
1172
1159
|
mockGetAllIssues.mockReturnValue([]);
|
|
1173
1160
|
|
|
1174
|
-
//
|
|
1161
|
+
// Liquid validation runs only in library mode
|
|
1162
|
+
// Use isFullMode: false (library mode) to test liquid validation path
|
|
1175
1163
|
const { rerender } = renderWithIntl({
|
|
1176
1164
|
isGetFormData: false,
|
|
1177
|
-
isFullMode:
|
|
1178
|
-
isLiquidEnabled: true,
|
|
1165
|
+
isFullMode: false,
|
|
1179
1166
|
getLiquidTags,
|
|
1180
1167
|
});
|
|
1181
1168
|
const input = screen.getByTestId('subject-input');
|
|
@@ -1194,7 +1181,7 @@ describe('EmailHTMLEditor', () => {
|
|
|
1194
1181
|
await act(async () => {
|
|
1195
1182
|
rerender(
|
|
1196
1183
|
<IntlProvider locale="en" messages={{}}>
|
|
1197
|
-
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode getLiquidTags={getLiquidTags} />
|
|
1184
|
+
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode={false} getLiquidTags={getLiquidTags} />
|
|
1198
1185
|
</IntlProvider>
|
|
1199
1186
|
);
|
|
1200
1187
|
});
|
|
@@ -1221,11 +1208,11 @@ describe('EmailHTMLEditor', () => {
|
|
|
1221
1208
|
// Ensure no HTML/Label/Liquid errors from HtmlEditor
|
|
1222
1209
|
mockGetAllIssues.mockReturnValue([]);
|
|
1223
1210
|
|
|
1224
|
-
//
|
|
1211
|
+
// Liquid validation runs only in library mode
|
|
1212
|
+
// Use isFullMode: false (library mode) to test liquid validation path
|
|
1225
1213
|
const { rerender } = renderWithIntl({
|
|
1226
1214
|
isGetFormData: false,
|
|
1227
|
-
isFullMode:
|
|
1228
|
-
isLiquidEnabled: true,
|
|
1215
|
+
isFullMode: false,
|
|
1229
1216
|
getLiquidTags,
|
|
1230
1217
|
showLiquidErrorInFooter,
|
|
1231
1218
|
onValidationFail,
|
|
@@ -1246,7 +1233,7 @@ describe('EmailHTMLEditor', () => {
|
|
|
1246
1233
|
await act(async () => {
|
|
1247
1234
|
rerender(
|
|
1248
1235
|
<IntlProvider locale="en" messages={{}}>
|
|
1249
|
-
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode getLiquidTags={getLiquidTags} showLiquidErrorInFooter={showLiquidErrorInFooter} onValidationFail={onValidationFail} />
|
|
1236
|
+
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode={false} getLiquidTags={getLiquidTags} showLiquidErrorInFooter={showLiquidErrorInFooter} onValidationFail={onValidationFail} />
|
|
1250
1237
|
</IntlProvider>
|
|
1251
1238
|
);
|
|
1252
1239
|
});
|
|
@@ -1266,27 +1253,22 @@ describe('EmailHTMLEditor', () => {
|
|
|
1266
1253
|
return Promise.resolve(true);
|
|
1267
1254
|
});
|
|
1268
1255
|
|
|
1269
|
-
const
|
|
1270
|
-
...defaultProps.emailActions,
|
|
1271
|
-
transformEmailTemplate: jest.fn((obj, callback) => callback(obj)),
|
|
1272
|
-
createTemplate: jest.fn((obj, callback) => {
|
|
1273
|
-
callback({ templateId: { _id: '123', versions: {} } });
|
|
1274
|
-
}),
|
|
1275
|
-
};
|
|
1256
|
+
const getFormdata = jest.fn();
|
|
1276
1257
|
const getLiquidTags = jest.fn((content, callback) => {
|
|
1277
1258
|
callback({ askAiraResponse: { data: [] }, isError: false });
|
|
1278
1259
|
});
|
|
1279
1260
|
// Ensure no HTML/Label/Liquid errors from HtmlEditor
|
|
1280
1261
|
mockGetAllIssues.mockReturnValue([]);
|
|
1281
1262
|
|
|
1282
|
-
//
|
|
1263
|
+
// Liquid validation runs only in library mode; then performSave calls getFormdata
|
|
1264
|
+
// Use isFullMode: false (library mode) to test liquid validation path
|
|
1283
1265
|
const { rerender } = renderWithIntl({
|
|
1284
1266
|
isGetFormData: false,
|
|
1285
|
-
isFullMode:
|
|
1286
|
-
|
|
1267
|
+
isFullMode: false,
|
|
1268
|
+
isFullMode: false,
|
|
1287
1269
|
getLiquidTags,
|
|
1288
|
-
|
|
1289
|
-
|
|
1270
|
+
getFormdata,
|
|
1271
|
+
location: { query: { module: 'library' } },
|
|
1290
1272
|
});
|
|
1291
1273
|
const input = screen.getByTestId('subject-input');
|
|
1292
1274
|
await act(async () => {
|
|
@@ -1304,7 +1286,7 @@ describe('EmailHTMLEditor', () => {
|
|
|
1304
1286
|
await act(async () => {
|
|
1305
1287
|
rerender(
|
|
1306
1288
|
<IntlProvider locale="en" messages={{}}>
|
|
1307
|
-
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode getLiquidTags={getLiquidTags}
|
|
1289
|
+
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode={false} getLiquidTags={getLiquidTags} getFormdata={getFormdata} location={{ query: { module: 'library' } }} />
|
|
1308
1290
|
</IntlProvider>
|
|
1309
1291
|
);
|
|
1310
1292
|
});
|
|
@@ -1313,13 +1295,13 @@ describe('EmailHTMLEditor', () => {
|
|
|
1313
1295
|
expect(validateLiquidTemplateContent).toHaveBeenCalled();
|
|
1314
1296
|
}, { timeout: 5000 });
|
|
1315
1297
|
|
|
1298
|
+
// In library mode (isFullMode=false), save proceeds via getFormdata
|
|
1316
1299
|
await waitFor(() => {
|
|
1317
|
-
expect(
|
|
1300
|
+
expect(getFormdata).toHaveBeenCalled();
|
|
1318
1301
|
}, { timeout: 5000 });
|
|
1319
1302
|
});
|
|
1320
1303
|
|
|
1321
1304
|
it('saves in full mode with create template', async () => {
|
|
1322
|
-
mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
|
|
1323
1305
|
const emailActions = {
|
|
1324
1306
|
...defaultProps.emailActions,
|
|
1325
1307
|
transformEmailTemplate: jest.fn((obj, callback) => callback(obj)),
|
|
@@ -1353,7 +1335,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
1353
1335
|
});
|
|
1354
1336
|
|
|
1355
1337
|
it('saves in full mode with edit template', async () => {
|
|
1356
|
-
mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
|
|
1357
1338
|
const emailActions = {
|
|
1358
1339
|
...defaultProps.emailActions,
|
|
1359
1340
|
transformEmailTemplate: jest.fn((obj, callback) => callback(obj)),
|
|
@@ -1423,7 +1404,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
1423
1404
|
});
|
|
1424
1405
|
|
|
1425
1406
|
it('handles create template error response', async () => {
|
|
1426
|
-
mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
|
|
1427
1407
|
const emailActions = {
|
|
1428
1408
|
...defaultProps.emailActions,
|
|
1429
1409
|
transformEmailTemplate: jest.fn((obj, callback) => callback(obj)),
|
|
@@ -1458,7 +1438,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
1458
1438
|
});
|
|
1459
1439
|
|
|
1460
1440
|
it('handles create template success with getFormdata', async () => {
|
|
1461
|
-
mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
|
|
1462
1441
|
const emailActions = {
|
|
1463
1442
|
...defaultProps.emailActions,
|
|
1464
1443
|
transformEmailTemplate: jest.fn((obj, callback) => callback(obj)),
|
|
@@ -1495,7 +1474,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
1495
1474
|
});
|
|
1496
1475
|
|
|
1497
1476
|
it('handles create template success without getFormdata', async () => {
|
|
1498
|
-
mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
|
|
1499
1477
|
const emailActions = {
|
|
1500
1478
|
...defaultProps.emailActions,
|
|
1501
1479
|
transformEmailTemplate: jest.fn((obj, callback) => callback(obj)),
|
|
@@ -1531,7 +1509,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
1531
1509
|
});
|
|
1532
1510
|
|
|
1533
1511
|
it('saves in library mode with getFormdata', async () => {
|
|
1534
|
-
mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
|
|
1535
1512
|
const getFormdata = jest.fn();
|
|
1536
1513
|
|
|
1537
1514
|
// Set subject and content via component interactions
|
|
@@ -1559,7 +1536,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
1559
1536
|
});
|
|
1560
1537
|
|
|
1561
1538
|
it('saves in library mode without library module', async () => {
|
|
1562
|
-
mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
|
|
1563
1539
|
const getFormdata = jest.fn();
|
|
1564
1540
|
|
|
1565
1541
|
// Set subject and content via component interactions
|
|
@@ -1699,7 +1675,6 @@ describe('EmailHTMLEditor', () => {
|
|
|
1699
1675
|
renderWithIntl({
|
|
1700
1676
|
getLiquidTags: null,
|
|
1701
1677
|
globalActions,
|
|
1702
|
-
isLiquidEnabled: true,
|
|
1703
1678
|
isGetFormData: true,
|
|
1704
1679
|
subject: 'Valid Subject',
|
|
1705
1680
|
htmlContent: '<p>Content</p>',
|
|
@@ -2652,4 +2627,98 @@ describe('EmailHTMLEditor', () => {
|
|
|
2652
2627
|
expect(screen.getByTestId('html-editor')).toBeInTheDocument();
|
|
2653
2628
|
});
|
|
2654
2629
|
});
|
|
2630
|
+
|
|
2631
|
+
describe('isFullMode - skip liquid validation on save', () => {
|
|
2632
|
+
it('skips liquid validation when isFullMode is true', async () => {
|
|
2633
|
+
validateLiquidTemplateContent.mockClear();
|
|
2634
|
+
const getLiquidTags = jest.fn((content, callback) => {
|
|
2635
|
+
callback({ askAiraResponse: { data: [] }, isError: false });
|
|
2636
|
+
});
|
|
2637
|
+
const getFormdata = jest.fn();
|
|
2638
|
+
// Ensure no HTML/Label/Liquid errors from HtmlEditor
|
|
2639
|
+
mockGetAllIssues.mockReturnValue([]);
|
|
2640
|
+
|
|
2641
|
+
const { rerender } = renderWithIntl({
|
|
2642
|
+
isGetFormData: false,
|
|
2643
|
+
isFullMode: true,
|
|
2644
|
+
isLiquidEnabled: true,
|
|
2645
|
+
getLiquidTags,
|
|
2646
|
+
getFormdata,
|
|
2647
|
+
});
|
|
2648
|
+
const input = screen.getByTestId('subject-input');
|
|
2649
|
+
await act(async () => {
|
|
2650
|
+
fireEvent.change(input, { target: { value: 'Valid Subject' } });
|
|
2651
|
+
});
|
|
2652
|
+
const changeButton = screen.getByTestId('trigger-content-change');
|
|
2653
|
+
await act(async () => {
|
|
2654
|
+
fireEvent.click(changeButton);
|
|
2655
|
+
});
|
|
2656
|
+
await act(async () => {
|
|
2657
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2658
|
+
});
|
|
2659
|
+
// Trigger save
|
|
2660
|
+
await act(async () => {
|
|
2661
|
+
rerender(
|
|
2662
|
+
<IntlProvider locale="en" messages={{}}>
|
|
2663
|
+
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode getLiquidTags={getLiquidTags} getFormdata={getFormdata} />
|
|
2664
|
+
</IntlProvider>
|
|
2665
|
+
);
|
|
2666
|
+
});
|
|
2667
|
+
|
|
2668
|
+
// In full mode, liquid validation should be skipped entirely
|
|
2669
|
+
await act(async () => {
|
|
2670
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
2671
|
+
});
|
|
2672
|
+
expect(validateLiquidTemplateContent).not.toHaveBeenCalled();
|
|
2673
|
+
});
|
|
2674
|
+
|
|
2675
|
+
it('proceeds directly to save without liquid validation in full mode', async () => {
|
|
2676
|
+
validateLiquidTemplateContent.mockClear();
|
|
2677
|
+
const getLiquidTags = jest.fn((content, callback) => {
|
|
2678
|
+
callback({ askAiraResponse: { data: [] }, isError: false });
|
|
2679
|
+
});
|
|
2680
|
+
const emailActions = {
|
|
2681
|
+
...defaultProps.emailActions,
|
|
2682
|
+
transformEmailTemplate: jest.fn((obj, callback) => callback(obj)),
|
|
2683
|
+
createTemplate: jest.fn((obj, callback) => {
|
|
2684
|
+
callback({ templateId: { _id: '123', versions: {} } });
|
|
2685
|
+
}),
|
|
2686
|
+
};
|
|
2687
|
+
// Ensure no HTML/Label/Liquid errors from HtmlEditor
|
|
2688
|
+
mockGetAllIssues.mockReturnValue([]);
|
|
2689
|
+
|
|
2690
|
+
const { rerender } = renderWithIntl({
|
|
2691
|
+
isGetFormData: false,
|
|
2692
|
+
isFullMode: true,
|
|
2693
|
+
getLiquidTags,
|
|
2694
|
+
emailActions,
|
|
2695
|
+
templateName: 'New Template',
|
|
2696
|
+
});
|
|
2697
|
+
const input = screen.getByTestId('subject-input');
|
|
2698
|
+
await act(async () => {
|
|
2699
|
+
fireEvent.change(input, { target: { value: 'Valid Subject' } });
|
|
2700
|
+
});
|
|
2701
|
+
const changeButton = screen.getByTestId('trigger-content-change');
|
|
2702
|
+
await act(async () => {
|
|
2703
|
+
fireEvent.click(changeButton);
|
|
2704
|
+
});
|
|
2705
|
+
await act(async () => {
|
|
2706
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2707
|
+
});
|
|
2708
|
+
// Trigger save
|
|
2709
|
+
await act(async () => {
|
|
2710
|
+
rerender(
|
|
2711
|
+
<IntlProvider locale="en" messages={{}}>
|
|
2712
|
+
<EmailHTMLEditor {...defaultProps} isGetFormData isFullMode getLiquidTags={getLiquidTags} emailActions={emailActions} templateName="New Template" />
|
|
2713
|
+
</IntlProvider>
|
|
2714
|
+
);
|
|
2715
|
+
});
|
|
2716
|
+
|
|
2717
|
+
// Should skip liquid validation and proceed to save directly
|
|
2718
|
+
await waitFor(() => {
|
|
2719
|
+
expect(emailActions.createTemplate).toHaveBeenCalled();
|
|
2720
|
+
}, { timeout: 5000 });
|
|
2721
|
+
expect(validateLiquidTemplateContent).not.toHaveBeenCalled();
|
|
2722
|
+
});
|
|
2723
|
+
});
|
|
2655
2724
|
});
|
|
@@ -37,7 +37,14 @@ jest.mock('../EmailHTMLEditor', () => {
|
|
|
37
37
|
getContentForPreview: jest.fn(() => '<p>Test</p>'),
|
|
38
38
|
}));
|
|
39
39
|
|
|
40
|
-
return
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
data-testid="email-html-editor"
|
|
43
|
+
data-wait-event-context-tags={JSON.stringify(props.waitEventContextTags ?? null)}
|
|
44
|
+
>
|
|
45
|
+
HTML Editor
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
41
48
|
});
|
|
42
49
|
});
|
|
43
50
|
|
|
@@ -137,6 +144,7 @@ const defaultProps = {
|
|
|
137
144
|
forwardedTags: {},
|
|
138
145
|
selectedOfferDetails: [],
|
|
139
146
|
eventContextTags: [],
|
|
147
|
+
waitEventContextTags: {},
|
|
140
148
|
getFormdata: jest.fn(),
|
|
141
149
|
isGetFormData: false,
|
|
142
150
|
getLiquidTags: jest.fn(),
|
|
@@ -171,6 +179,13 @@ describe('EmailWrapperView', () => {
|
|
|
171
179
|
jest.clearAllMocks();
|
|
172
180
|
});
|
|
173
181
|
|
|
182
|
+
it('passes waitEventContextTags to EmailHTMLEditor when HTML editor is shown', () => {
|
|
183
|
+
const waitMap = { b1: { eventName: 'E', blockName: 'B', tags: [] } };
|
|
184
|
+
renderWithIntl({ waitEventContextTags: waitMap });
|
|
185
|
+
const el = screen.getByTestId('email-html-editor');
|
|
186
|
+
expect(el).toHaveAttribute('data-wait-event-context-tags', JSON.stringify(waitMap));
|
|
187
|
+
});
|
|
188
|
+
|
|
174
189
|
describe('Mode Selection UI', () => {
|
|
175
190
|
it('renders mode selection when step is MODE_SELECTION', () => {
|
|
176
191
|
renderWithIntl({ step: STEPS.MODE_SELECTION });
|
|
@@ -51,6 +51,7 @@ const useEmailWrapper = ({
|
|
|
51
51
|
editor,
|
|
52
52
|
moduleType,
|
|
53
53
|
eventContextTags,
|
|
54
|
+
waitEventContextTags,
|
|
54
55
|
isLoyaltyModule,
|
|
55
56
|
// Props for CmsTemplates component
|
|
56
57
|
cmsTemplatesLoader,
|
|
@@ -206,7 +207,11 @@ const useEmailWrapper = ({
|
|
|
206
207
|
|
|
207
208
|
// Only fetch if we have an ID, don't have template data yet, and not already loading
|
|
208
209
|
if (hasParamsId && !hasTemplateDetails && !hasTemplateDataProp && !isTemplateLoading && emailActions?.getTemplateDetails) {
|
|
209
|
-
|
|
210
|
+
let templateId = params?.id || location?.query?.id || location?.params?.id;
|
|
211
|
+
if (!templateId && location?.pathname?.includes('/edit/')) {
|
|
212
|
+
const [, extractedId] = location.pathname.match(/\/edit\/([^/]+)/) || [];
|
|
213
|
+
if (extractedId) templateId = extractedId;
|
|
214
|
+
}
|
|
210
215
|
if (templateId) {
|
|
211
216
|
emailActions.getTemplateDetails(templateId, 'email');
|
|
212
217
|
}
|
|
@@ -581,8 +586,6 @@ const useEmailWrapper = ({
|
|
|
581
586
|
// CRITICAL: Only treat as edit mode if we have params.id (actual edit URL) or templateData prop
|
|
582
587
|
// Don't use templateDetails existence alone, as it might persist from previous template
|
|
583
588
|
const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
|
|
584
|
-
const hasTemplateDetails = Email?.templateDetails && !isEmpty(Email.templateDetails);
|
|
585
|
-
const hasBEETemplate = Email?.BEETemplate && !isEmpty(Email.BEETemplate);
|
|
586
589
|
const hasTemplateDataProp = templateData && !isEmpty(templateData);
|
|
587
590
|
// CRITICAL: Consider it edit mode if we have params.id OR templateData prop (library mode)
|
|
588
591
|
// This allows editor type determination even when template data is still loading
|
|
@@ -590,13 +593,14 @@ const useEmailWrapper = ({
|
|
|
590
593
|
|
|
591
594
|
if (isEditMode) {
|
|
592
595
|
// Edit mode: Determine editor based on template data
|
|
593
|
-
// Check if template was created in BEE editor
|
|
594
596
|
// Priority: Email.templateDetails > Email.BEETemplate > templateData prop
|
|
595
|
-
|
|
596
|
-
|
|
597
|
+
// Use first non-empty source (empty array/object can appear while template is loading)
|
|
598
|
+
const editTemplateData = [Email?.templateDetails, Email?.BEETemplate, templateData].find(
|
|
599
|
+
(d) => d && !isEmpty(d)
|
|
600
|
+
) || null;
|
|
597
601
|
// Helper function to safely get is_drag_drop from various possible paths
|
|
598
602
|
const getIsDragDrop = (data) => {
|
|
599
|
-
if (!data) return false;
|
|
603
|
+
if (!data || isEmpty(data)) return false;
|
|
600
604
|
|
|
601
605
|
// Check common paths for is_drag_drop
|
|
602
606
|
// Path 1: versions.base.is_drag_drop (most common)
|
|
@@ -630,8 +634,10 @@ const useEmailWrapper = ({
|
|
|
630
634
|
return false;
|
|
631
635
|
};
|
|
632
636
|
|
|
633
|
-
|
|
634
|
-
|
|
637
|
+
// When template data is still loading (editTemplateData empty), trust editor prop so BEE templates open in BEE
|
|
638
|
+
const hasMeaningfulTemplateData = editTemplateData && !isEmpty(editTemplateData);
|
|
639
|
+
const isDragDrop = getIsDragDrop(editTemplateData)
|
|
640
|
+
|| (!hasMeaningfulTemplateData && editor === 'BEE');
|
|
635
641
|
// Check if BEE is enabled for org (equivalent to checkBeeEditorAllowedForLibrary)
|
|
636
642
|
// For editor selection:
|
|
637
643
|
// - In full mode: BEE is always enabled
|
|
@@ -643,7 +649,6 @@ const useEmailWrapper = ({
|
|
|
643
649
|
|| (editor === "BEE" && !isFullMode)
|
|
644
650
|
|| beeEnabledFromAPI
|
|
645
651
|
|| (isAPIResponsePending && isDragDrop && !isFullMode); // Optimistic: if template is BEE and API pending, allow BEE
|
|
646
|
-
|
|
647
652
|
// If template was created in BEE AND BEE is enabled → open in BEE editor
|
|
648
653
|
// Otherwise → open in HTML editor (fallback)
|
|
649
654
|
// IMPORTANT: When supportCKEditor is false, default to HTML editor unless explicitly BEE
|
|
@@ -733,6 +738,7 @@ const useEmailWrapper = ({
|
|
|
733
738
|
selectedEditorMode, // Pass selected mode to Email component (only for HTML_EDITOR)
|
|
734
739
|
moduleType,
|
|
735
740
|
eventContextTags,
|
|
741
|
+
waitEventContextTags,
|
|
736
742
|
isLoyaltyModule,
|
|
737
743
|
showTestAndPreviewSlidebox,
|
|
738
744
|
handleTestAndPreview,
|
|
@@ -762,6 +768,7 @@ const useEmailWrapper = ({
|
|
|
762
768
|
editor,
|
|
763
769
|
moduleType,
|
|
764
770
|
eventContextTags,
|
|
771
|
+
waitEventContextTags,
|
|
765
772
|
isLoyaltyModule,
|
|
766
773
|
showTestAndPreviewSlidebox,
|
|
767
774
|
handleTestAndPreview,
|
|
@@ -790,8 +797,6 @@ const useEmailWrapper = ({
|
|
|
790
797
|
// In edit mode (when supportCKEditor is false), always show editor
|
|
791
798
|
if (!supportCKEditorFlag && isEditMode) {
|
|
792
799
|
// Check if it's explicitly BEE editor
|
|
793
|
-
const isExplicitlyBEE = emailCreateMode === EMAIL_CREATE_MODES.DRAG_DROP
|
|
794
|
-
|| (emailProps?.editor === 'BEE' && emailProps?.selectedEditorMode === null);
|
|
795
800
|
// Show editor for both BEE and HTML in edit mode
|
|
796
801
|
return true;
|
|
797
802
|
}
|
|
@@ -63,6 +63,7 @@ const EmailWrapper = (props) => {
|
|
|
63
63
|
onEnterTemplateName,
|
|
64
64
|
onRemoveTemplateName,
|
|
65
65
|
eventContextTags,
|
|
66
|
+
waitEventContextTags,
|
|
66
67
|
isLoyaltyModule,
|
|
67
68
|
cmsTemplatesLoader,
|
|
68
69
|
onPreviewContentClicked,
|
|
@@ -130,6 +131,7 @@ const EmailWrapper = (props) => {
|
|
|
130
131
|
onEnterTemplateName,
|
|
131
132
|
onRemoveTemplateName,
|
|
132
133
|
eventContextTags,
|
|
134
|
+
waitEventContextTags,
|
|
133
135
|
isLoyaltyModule,
|
|
134
136
|
cmsTemplatesLoader,
|
|
135
137
|
onPreviewContentClicked,
|
|
@@ -184,6 +186,7 @@ const EmailWrapper = (props) => {
|
|
|
184
186
|
forwardedTags={forwardedTags}
|
|
185
187
|
selectedOfferDetails={selectedOfferDetails}
|
|
186
188
|
eventContextTags={eventContextTags}
|
|
189
|
+
waitEventContextTags={waitEventContextTags}
|
|
187
190
|
getFormdata={getFormdata}
|
|
188
191
|
isGetFormData={isGetFormData}
|
|
189
192
|
getLiquidTags={globalActionsProp?.getLiquidTags}
|
|
@@ -241,6 +244,7 @@ EmailWrapper.propTypes = {
|
|
|
241
244
|
onEnterTemplateName: PropTypes.func,
|
|
242
245
|
onRemoveTemplateName: PropTypes.func,
|
|
243
246
|
eventContextTags: PropTypes.array,
|
|
247
|
+
waitEventContextTags: PropTypes.object,
|
|
244
248
|
isLoyaltyModule: PropTypes.bool,
|
|
245
249
|
onPreviewContentClicked: PropTypes.func,
|
|
246
250
|
onTestContentClicked: PropTypes.func,
|