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.
Files changed (247) hide show
  1. package/.github/workflows/pr-title-check.yml +88 -0
  2. package/app/constants/unified.js +21 -1
  3. package/app/containers/App/constants.js +0 -1
  4. package/app/containers/Login/test/index.test.js +123 -0
  5. package/app/containers/Login/test/selectors.test.js +165 -0
  6. package/app/initialState.js +0 -2
  7. package/app/services/api.js +6 -0
  8. package/app/services/tests/api.test.js +7 -0
  9. package/app/services/tests/getSchema.test.js +95 -0
  10. package/app/utils/common.js +23 -9
  11. package/app/utils/commonUtils.js +64 -93
  12. package/app/utils/tagValidations.js +83 -219
  13. package/app/utils/templateVarUtils.js +172 -0
  14. package/app/utils/tests/common.test.js +265 -323
  15. package/app/utils/tests/commonUtil.test.js +461 -118
  16. package/app/utils/tests/commonUtils.test.js +581 -0
  17. package/app/utils/tests/messageUtils.test.js +95 -0
  18. package/app/utils/tests/smsCharCount.test.js +304 -0
  19. package/app/utils/tests/smsCharCountV2.test.js +213 -10
  20. package/app/utils/tests/tagValidations.test.js +474 -357
  21. package/app/utils/tests/templateVarUtils.test.js +160 -0
  22. package/app/v2Components/CapDeviceContent/index.js +10 -7
  23. package/app/v2Components/CapTagList/index.js +32 -24
  24. package/app/v2Components/CapTagList/style.scss +48 -0
  25. package/app/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
  26. package/app/v2Components/CapTagListWithInput/index.js +8 -0
  27. package/app/v2Components/CapWhatsappCTA/index.js +2 -0
  28. package/app/v2Components/CapWhatsappCarouselButton/index.js +32 -14
  29. package/app/v2Components/CapWhatsappCarouselButton/tests/index.test.js +120 -2
  30. package/app/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
  31. package/app/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +39 -0
  32. package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +606 -0
  33. package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.scss +36 -0
  34. package/app/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +79 -0
  35. package/app/v2Components/CommonTestAndPreview/DeliverySettings/index.js +314 -0
  36. package/app/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +141 -0
  37. package/app/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +156 -0
  38. package/app/v2Components/CommonTestAndPreview/SendTestMessage.js +57 -1
  39. package/app/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
  40. package/app/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
  41. package/app/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +210 -4
  42. package/app/v2Components/CommonTestAndPreview/actions.js +20 -0
  43. package/app/v2Components/CommonTestAndPreview/constants.js +57 -1
  44. package/app/v2Components/CommonTestAndPreview/index.js +878 -156
  45. package/app/v2Components/CommonTestAndPreview/messages.js +41 -3
  46. package/app/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  47. package/app/v2Components/CommonTestAndPreview/reducer.js +47 -0
  48. package/app/v2Components/CommonTestAndPreview/sagas.js +75 -5
  49. package/app/v2Components/CommonTestAndPreview/selectors.js +51 -0
  50. package/app/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
  51. package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +1156 -0
  52. package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +334 -0
  53. package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +576 -0
  54. package/app/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +156 -0
  55. package/app/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  56. package/app/v2Components/CommonTestAndPreview/tests/actions.test.js +50 -0
  57. package/app/v2Components/CommonTestAndPreview/tests/constants.test.js +18 -7
  58. package/app/v2Components/CommonTestAndPreview/tests/index.test.js +914 -5
  59. package/app/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  60. package/app/v2Components/CommonTestAndPreview/tests/reducer.test.js +118 -0
  61. package/app/v2Components/CommonTestAndPreview/tests/sagas.test.js +146 -378
  62. package/app/v2Components/CommonTestAndPreview/tests/selectors.test.js +146 -0
  63. package/app/v2Components/ErrorInfoNote/index.js +24 -26
  64. package/app/v2Components/FormBuilder/index.js +182 -204
  65. package/app/v2Components/FormBuilder/messages.js +4 -8
  66. package/app/v2Components/HtmlEditor/HTMLEditor.js +7 -6
  67. package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -1
  68. package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +928 -17
  69. package/app/v2Components/HtmlEditor/components/CodeEditorPane/index.js +4 -2
  70. package/app/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +452 -3
  71. package/app/v2Components/HtmlEditor/hooks/useValidation.js +12 -9
  72. package/app/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +132 -0
  73. package/app/v2Components/HtmlEditor/utils/htmlValidator.js +4 -2
  74. package/app/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
  75. package/app/v2Components/SmsFallback/constants.js +73 -0
  76. package/app/v2Components/SmsFallback/index.js +956 -0
  77. package/app/v2Components/SmsFallback/index.scss +265 -0
  78. package/app/v2Components/SmsFallback/messages.js +78 -0
  79. package/app/v2Components/SmsFallback/smsFallbackUtils.js +107 -0
  80. package/app/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  81. package/app/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  82. package/app/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  83. package/app/v2Components/SmsFallback/tests/smsFallbackUi.test.js +197 -0
  84. package/app/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
  85. package/app/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
  86. package/app/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  87. package/app/v2Components/TestAndPreviewSlidebox/index.js +22 -1
  88. package/app/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  89. package/app/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  90. package/app/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  91. package/app/v2Components/VarSegmentMessageEditor/index.js +125 -0
  92. package/app/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  93. package/app/v2Containers/BeeEditor/index.js +3 -0
  94. package/app/v2Containers/BeePopupEditor/index.js +9 -2
  95. package/app/v2Containers/Cap/mockData.js +0 -14
  96. package/app/v2Containers/Cap/reducer.js +3 -55
  97. package/app/v2Containers/Cap/tests/reducer.test.js +0 -102
  98. package/app/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
  99. package/app/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
  100. package/app/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
  101. package/app/v2Containers/CommunicationFlow/constants.js +200 -0
  102. package/app/v2Containers/CommunicationFlow/index.js +102 -0
  103. package/app/v2Containers/CommunicationFlow/messages.js +346 -0
  104. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
  105. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
  106. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
  107. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
  108. package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
  109. package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
  110. package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
  111. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
  112. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
  113. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
  114. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
  115. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
  116. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
  117. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
  118. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
  119. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
  120. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
  121. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
  122. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
  123. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
  124. package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
  125. package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
  126. package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
  127. package/app/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
  128. package/app/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
  129. package/app/v2Containers/CreativesContainer/SlideBoxContent.js +127 -11
  130. package/app/v2Containers/CreativesContainer/SlideBoxFooter.js +62 -9
  131. package/app/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
  132. package/app/v2Containers/CreativesContainer/constants.js +24 -0
  133. package/app/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
  134. package/app/v2Containers/CreativesContainer/index.js +346 -71
  135. package/app/v2Containers/CreativesContainer/index.scss +51 -1
  136. package/app/v2Containers/CreativesContainer/messages.js +12 -0
  137. package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  138. package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +69 -1
  139. package/app/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +443 -0
  140. package/app/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
  141. package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +147 -4
  142. package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
  143. package/app/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +57 -10
  144. package/app/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  145. package/app/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  146. package/app/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  147. package/app/v2Containers/Email/index.js +2 -5
  148. package/app/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +58 -77
  149. package/app/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
  150. package/app/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +158 -89
  151. package/app/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
  152. package/app/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +17 -12
  153. package/app/v2Containers/EmailWrapper/index.js +4 -0
  154. package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
  155. package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +133 -0
  156. package/app/v2Containers/FTP/index.js +2 -51
  157. package/app/v2Containers/FTP/messages.js +0 -4
  158. package/app/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +110 -155
  159. package/app/v2Containers/InApp/index.js +297 -118
  160. package/app/v2Containers/InApp/tests/index.test.js +17 -6
  161. package/app/v2Containers/InApp/tests/mockData.js +1 -1
  162. package/app/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
  163. package/app/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
  164. package/app/v2Containers/InAppWrapper/index.js +3 -0
  165. package/app/v2Containers/InappAdvance/index.js +5 -104
  166. package/app/v2Containers/InappAdvance/tests/index.test.js +2 -0
  167. package/app/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +24 -3
  168. package/app/v2Containers/Line/Container/Text/index.js +0 -1
  169. package/app/v2Containers/MobilePush/Create/index.js +105 -28
  170. package/app/v2Containers/MobilePush/Create/messages.js +4 -0
  171. package/app/v2Containers/MobilePush/Edit/index.js +250 -68
  172. package/app/v2Containers/MobilePush/Edit/messages.js +4 -0
  173. package/app/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
  174. package/app/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
  175. package/app/v2Containers/MobilePushNew/index.js +78 -35
  176. package/app/v2Containers/MobilePushNew/messages.js +8 -0
  177. package/app/v2Containers/MobilepushWrapper/index.js +11 -1
  178. package/app/v2Containers/Rcs/constants.js +32 -1
  179. package/app/v2Containers/Rcs/index.js +963 -916
  180. package/app/v2Containers/Rcs/index.scss +85 -6
  181. package/app/v2Containers/Rcs/messages.js +10 -1
  182. package/app/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
  183. package/app/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +41136 -1566
  184. package/app/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
  185. package/app/v2Containers/Rcs/tests/index.test.js +41 -38
  186. package/app/v2Containers/Rcs/tests/mockData.js +38 -0
  187. package/app/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
  188. package/app/v2Containers/Rcs/tests/utils.test.js +379 -1
  189. package/app/v2Containers/Rcs/utils.js +358 -10
  190. package/app/v2Containers/Sms/Create/index.js +122 -39
  191. package/app/v2Containers/Sms/Create/messages.js +4 -0
  192. package/app/v2Containers/Sms/Edit/index.js +37 -3
  193. package/app/v2Containers/Sms/commonMethods.js +3 -6
  194. package/app/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  195. package/app/v2Containers/Sms/tests/commonMethods.test.js +122 -0
  196. package/app/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  197. package/app/v2Containers/SmsTrai/Create/index.js +9 -4
  198. package/app/v2Containers/SmsTrai/Create/index.scss +1 -1
  199. package/app/v2Containers/SmsTrai/Edit/constants.js +2 -0
  200. package/app/v2Containers/SmsTrai/Edit/index.js +667 -160
  201. package/app/v2Containers/SmsTrai/Edit/index.scss +121 -0
  202. package/app/v2Containers/SmsTrai/Edit/messages.js +9 -4
  203. package/app/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4590 -2436
  204. package/app/v2Containers/SmsWrapper/index.js +41 -8
  205. package/app/v2Containers/TagList/index.js +63 -2
  206. package/app/v2Containers/TagList/messages.js +8 -0
  207. package/app/v2Containers/TagList/tests/TagList.test.js +122 -20
  208. package/app/v2Containers/TagList/tests/mockdata.js +17 -0
  209. package/app/v2Containers/Templates/TemplatesActionBar.js +101 -0
  210. package/app/v2Containers/Templates/_templates.scss +61 -2
  211. package/app/v2Containers/Templates/actions.js +11 -0
  212. package/app/v2Containers/Templates/constants.js +2 -0
  213. package/app/v2Containers/Templates/index.js +90 -40
  214. package/app/v2Containers/Templates/reducer.js +3 -1
  215. package/app/v2Containers/Templates/sagas.js +57 -12
  216. package/app/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
  217. package/app/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
  218. package/app/v2Containers/Templates/tests/reducer.test.js +12 -0
  219. package/app/v2Containers/Templates/tests/sagas.test.js +193 -12
  220. package/app/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  221. package/app/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  222. package/app/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  223. package/app/v2Containers/TemplatesV2/index.js +147 -49
  224. package/app/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  225. package/app/v2Containers/Viber/index.js +9 -10
  226. package/app/v2Containers/Viber/index.scss +1 -1
  227. package/app/v2Containers/WebPush/Create/components/BrandIconSection.test.js +264 -0
  228. package/app/v2Containers/WebPush/Create/components/MessageSection.js +78 -19
  229. package/app/v2Containers/WebPush/Create/components/MessageSection.test.js +82 -0
  230. package/app/v2Containers/WebPush/Create/components/__snapshots__/BrandIconSection.test.js.snap +187 -0
  231. package/app/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +25 -17
  232. package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.js +80 -0
  233. package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.test.js +210 -0
  234. package/app/v2Containers/WebPush/Create/hooks/useTagManagement.js +1 -5
  235. package/app/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -7
  236. package/app/v2Containers/WebPush/Create/index.js +36 -6
  237. package/app/v2Containers/WebPush/Create/index.scss +5 -0
  238. package/app/v2Containers/WebPush/Create/messages.js +8 -1
  239. package/app/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +269 -0
  240. package/app/v2Containers/WebPush/Create/utils/validation.js +31 -15
  241. package/app/v2Containers/WebPush/Create/utils/validation.test.js +72 -24
  242. package/app/v2Containers/Whatsapp/index.js +28 -53
  243. package/app/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +26939 -3982
  244. package/app/v2Containers/Whatsapp/tests/index.test.js +172 -0
  245. package/app/v2Containers/Zalo/index.js +5 -11
  246. package/package.json +2 -2
  247. 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 { isEmailUnsubscribeTagMandatory } from '../../../../utils/common';
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
- hasLiquidSupportFeature: (...args) => mockHasLiquidSupportFeature(...args),
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 data-testid="html-editor">
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 data-testid="html-editor">
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
- isEmailUnsubscribeTagMandatory.mockReturnValue(false);
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
- isEmailUnsubscribeTagMandatory.mockReturnValue(false);
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 for non-liquid orgs when tag validation fails', async () => {
1061
- mockHasLiquidSupportFeature.mockReturnValue(false); // Non-liquid org
1062
- validateTags.mockReturnValue({
1063
- valid: false,
1064
- unsupportedTags: ['tag1'],
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: null, // No liquid tags for non-liquid org
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={null} />
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
- // Set subject and content via component interactions
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: true,
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
- // Set subject and content via component interactions
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: true,
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
- // Set subject and content via component interactions
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: true,
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 emailActions = {
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
- // Set subject and content via component interactions
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: true,
1286
- isLiquidEnabled: true,
1267
+ isFullMode: false,
1268
+ isFullMode: false,
1287
1269
  getLiquidTags,
1288
- emailActions,
1289
- templateName: 'New Template',
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} emailActions={emailActions} templateName="New Template" />
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(emailActions.createTemplate).toHaveBeenCalled();
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 <div data-testid="email-html-editor">HTML Editor</div>;
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
- const templateId = params?.id || location?.query?.id || location?.params?.id;
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
- const editTemplateData = Email?.templateDetails || Email?.BEETemplate || templateData;
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
- const isDragDrop = getIsDragDrop(editTemplateData);
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,
@@ -112,6 +112,7 @@ describe('useEmailWrapper - Edge Cases', () => {
112
112
  editor: 'HTML',
113
113
  moduleType: null,
114
114
  eventContextTags: [],
115
+ waitEventContextTags: {},
115
116
  isLoyaltyModule: false,
116
117
  cmsTemplatesLoader: jest.fn(),
117
118
  currentOrgDetails: {},