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
@@ -10,7 +10,7 @@ import PropTypes from 'prop-types';
10
10
  import { render, screen, waitFor } from '@testing-library/react';
11
11
  import { IntlProvider } from 'react-intl';
12
12
  import CommonTestAndPreview from '../index';
13
- import { CHANNELS } from '../constants';
13
+ import { CHANNELS, MEDIA_TYPE_CAROUSEL } from '../constants';
14
14
 
15
15
  // Mock html-to-text
16
16
  jest.mock('html-to-text', () => ({
@@ -30,34 +30,41 @@ jest.mock('@capillarytech/cap-ui-library/CapNotification', () => ({
30
30
  }));
31
31
 
32
32
  // Mock child components - must use React.createElement to avoid hoisting issues
33
+ let lastLeftPanelContentProps = null;
33
34
  jest.mock('../LeftPanelContent', () => {
34
35
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
35
36
  const ReactLib = require('react');
36
37
  return {
37
38
  __esModule: true,
38
- default: function MockLeftPanelContent() {
39
- return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel');
39
+ default: function MockLeftPanelContent(props) {
40
+ lastLeftPanelContentProps = props;
41
+ const editorEl = props.renderCustomValuesEditor ? props.renderCustomValuesEditor() : null;
42
+ return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel', editorEl);
40
43
  },
41
44
  };
42
45
  });
43
46
 
47
+ let lastCustomValuesEditorProps = null;
44
48
  jest.mock('../CustomValuesEditor', () => {
45
49
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
46
50
  const ReactLib = require('react');
47
51
  return {
48
52
  __esModule: true,
49
- default: function MockCustomValuesEditor() {
53
+ default: function MockCustomValuesEditor(props) {
54
+ lastCustomValuesEditorProps = props;
50
55
  return ReactLib.createElement('div', { 'data-testid': 'custom-values-editor' }, 'Custom Values Editor');
51
56
  },
52
57
  };
53
58
  });
54
59
 
60
+ let lastSendTestMessageProps = null;
55
61
  jest.mock('../SendTestMessage', () => {
56
62
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
57
63
  const ReactLib = require('react');
58
64
  return {
59
65
  __esModule: true,
60
- default: function MockSendTestMessage() {
66
+ default: function MockSendTestMessage(props) {
67
+ lastSendTestMessageProps = props;
61
68
  return ReactLib.createElement('div', { 'data-testid': 'send-test-message' }, 'Send Test Message');
62
69
  },
63
70
  };
@@ -122,6 +129,8 @@ describe('CommonTestAndPreview', () => {
122
129
  getPrefilledValuesRequested: jest.fn(),
123
130
  clearPrefilledValues: jest.fn(),
124
131
  clearPreviewErrors: jest.fn(),
132
+ getSenderDetailsRequested: jest.fn(),
133
+ getWeCrmAccountsRequested: jest.fn(),
125
134
  };
126
135
 
127
136
  const defaultProps = {
@@ -171,10 +180,17 @@ describe('CommonTestAndPreview', () => {
171
180
  fetchPrefilledValuesErrors: [],
172
181
  isSendingTestMessage: false,
173
182
  currentTab: 1,
183
+ senderDetailsByChannel: {},
184
+ wecrmAccounts: [],
185
+ isLoadingSenderDetails: false,
186
+ orgUnitId: -1,
174
187
  };
175
188
 
176
189
  beforeEach(() => {
177
190
  jest.clearAllMocks();
191
+ lastSendTestMessageProps = null;
192
+ lastLeftPanelContentProps = null;
193
+ lastCustomValuesEditorProps = null;
178
194
  // Reset all mock function implementations
179
195
  Object.values(mockActions).forEach((mockFn) => {
180
196
  if (jest.isMockFunction(mockFn)) {
@@ -183,6 +199,796 @@ describe('CommonTestAndPreview', () => {
183
199
  });
184
200
  });
185
201
 
202
+ describe('Delivery settings / sender ID', () => {
203
+ it('should call getSenderDetailsRequested when show and channel is SMS', async () => {
204
+ render(
205
+ <TestWrapper>
206
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.SMS} />
207
+ </TestWrapper>
208
+ );
209
+ await waitFor(() => {
210
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
211
+ channel: CHANNELS.SMS,
212
+ orgUnitId: -1,
213
+ });
214
+ });
215
+ });
216
+
217
+ it('should call getSenderDetailsRequested when show and channel is EMAIL', async () => {
218
+ render(
219
+ <TestWrapper>
220
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
221
+ </TestWrapper>
222
+ );
223
+ await waitFor(() => {
224
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
225
+ channel: CHANNELS.EMAIL,
226
+ orgUnitId: -1,
227
+ });
228
+ });
229
+ });
230
+
231
+ it('should call getSenderDetailsRequested and getWeCrmAccountsRequested when show and channel is WHATSAPP', async () => {
232
+ render(
233
+ <TestWrapper>
234
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.WHATSAPP} />
235
+ </TestWrapper>
236
+ );
237
+ await waitFor(() => {
238
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
239
+ channel: CHANNELS.WHATSAPP,
240
+ orgUnitId: -1,
241
+ });
242
+ expect(mockActions.getWeCrmAccountsRequested).toHaveBeenCalledWith({
243
+ sourceName: CHANNELS.WHATSAPP,
244
+ });
245
+ });
246
+ });
247
+
248
+ it('should call getSenderDetailsRequested for RCS and SMS when channel is RCS', async () => {
249
+ render(
250
+ <TestWrapper>
251
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.RCS} />
252
+ </TestWrapper>
253
+ );
254
+ await waitFor(() => {
255
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
256
+ channel: CHANNELS.RCS,
257
+ orgUnitId: -1,
258
+ });
259
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
260
+ channel: CHANNELS.SMS,
261
+ orgUnitId: -1,
262
+ });
263
+ });
264
+ });
265
+
266
+ it('should not call getSenderDetailsRequested when channel is INAPP', async () => {
267
+ render(
268
+ <TestWrapper>
269
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.INAPP} />
270
+ </TestWrapper>
271
+ );
272
+ await waitFor(() => {
273
+ expect(screen.getByTestId('left-panel')).toBeTruthy();
274
+ });
275
+ expect(mockActions.getSenderDetailsRequested).not.toHaveBeenCalled();
276
+ expect(mockActions.getWeCrmAccountsRequested).not.toHaveBeenCalled();
277
+ });
278
+
279
+ it('should pass orgUnitId to getSenderDetailsRequested when provided', async () => {
280
+ render(
281
+ <TestWrapper>
282
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.SMS} orgUnitId={100} />
283
+ </TestWrapper>
284
+ );
285
+ await waitFor(() => {
286
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
287
+ channel: CHANNELS.SMS,
288
+ orgUnitId: 100,
289
+ });
290
+ });
291
+ });
292
+
293
+ it('should not call getSenderDetailsRequested when show is false', async () => {
294
+ render(
295
+ <TestWrapper>
296
+ <CommonTestAndPreview {...defaultProps} show={false} channel={CHANNELS.SMS} />
297
+ </TestWrapper>
298
+ );
299
+ await waitFor(() => {
300
+ expect(screen.queryByTestId('left-panel')).toBeNull();
301
+ });
302
+ expect(mockActions.getSenderDetailsRequested).not.toHaveBeenCalled();
303
+ });
304
+
305
+ it('should pass delivery-related props to SendTestMessage for SMS channel', async () => {
306
+ const senderDetailsByChannel = {
307
+ [CHANNELS.SMS]: [{ domainId: 1, domainName: 'SMS Dom', gsmSenders: [], cdmaSenders: [] }],
308
+ };
309
+ render(
310
+ <TestWrapper>
311
+ <CommonTestAndPreview
312
+ {...defaultProps}
313
+ channel={CHANNELS.SMS}
314
+ senderDetailsByChannel={senderDetailsByChannel}
315
+ wecrmAccounts={[]}
316
+ />
317
+ </TestWrapper>
318
+ );
319
+ await waitFor(() => {
320
+ expect(screen.getByTestId('send-test-message')).toBeTruthy();
321
+ });
322
+ expect(lastSendTestMessageProps).toBeDefined();
323
+ expect(lastSendTestMessageProps.deliverySettings).toBeDefined();
324
+ expect(lastSendTestMessageProps.senderDetailsByChannel).toEqual(senderDetailsByChannel);
325
+ expect(lastSendTestMessageProps.wecrmAccounts).toEqual([]);
326
+ expect(typeof lastSendTestMessageProps.onSaveDeliverySettings).toBe('function');
327
+ expect(lastSendTestMessageProps.isLoadingSenderDetails).toBe(false);
328
+ });
329
+
330
+ it('should pass formDataForSendTest (formData when provided) to SendTestMessage', async () => {
331
+ render(
332
+ <TestWrapper>
333
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
334
+ </TestWrapper>
335
+ );
336
+ await waitFor(() => {
337
+ expect(lastSendTestMessageProps).toBeDefined();
338
+ });
339
+ expect(lastSendTestMessageProps.formData).toEqual(defaultProps.formData);
340
+ });
341
+
342
+ it('should auto-set SMS delivery settings from TRAI registered sender IDs when DLT is enabled', async () => {
343
+ const senderDetailsByChannel = {
344
+ [CHANNELS.SMS]: [
345
+ {
346
+ domainId: 1,
347
+ dgmId: 11,
348
+ gsmSenders: [{ value: 'SENDER_A' }],
349
+ cdmaSenders: [{ value: 'CDMA_A' }],
350
+ },
351
+ {
352
+ domainId: 2,
353
+ dgmId: 22,
354
+ gsmSenders: [{ value: 'SENDER_B' }, { value: 'SENDER_C' }],
355
+ cdmaSenders: [{ value: 'CDMA_B' }],
356
+ },
357
+ ],
358
+ };
359
+
360
+ render(
361
+ <TestWrapper>
362
+ <CommonTestAndPreview
363
+ {...defaultProps}
364
+ channel={CHANNELS.SMS}
365
+ formData={{
366
+ templateConfigs: {
367
+ traiDltEnabled: true,
368
+ registeredSenderIds: ['SENDER_B'],
369
+ },
370
+ }}
371
+ senderDetailsByChannel={senderDetailsByChannel}
372
+ />
373
+ </TestWrapper>
374
+ );
375
+
376
+ await waitFor(() => {
377
+ expect(lastSendTestMessageProps.deliverySettings).toEqual({
378
+ domainId: 2,
379
+ domainGatewayMapId: 22,
380
+ gsmSenderId: 'SENDER_B',
381
+ cdmaSenderId: 'CDMA_B',
382
+ });
383
+ });
384
+ });
385
+
386
+ it('should preserve existing SMS auto-set logic when TRAI DLT is not enabled', async () => {
387
+ const senderDetailsByChannel = {
388
+ [CHANNELS.SMS]: [
389
+ {
390
+ domainId: 1,
391
+ dgmId: 11,
392
+ gsmSenders: [{ value: 'SENDER_A' }, { value: 'SENDER_A_DEFAULT', default: true }],
393
+ cdmaSenders: [{ value: 'CDMA_A', default: true }],
394
+ },
395
+ {
396
+ domainId: 2,
397
+ dgmId: 22,
398
+ gsmSenders: [{ value: 'SENDER_B' }],
399
+ cdmaSenders: [{ value: 'CDMA_B' }],
400
+ },
401
+ ],
402
+ };
403
+
404
+ render(
405
+ <TestWrapper>
406
+ <CommonTestAndPreview
407
+ {...defaultProps}
408
+ channel={CHANNELS.SMS}
409
+ formData={{
410
+ templateConfigs: {
411
+ traiDltEnabled: false,
412
+ registeredSenderIds: ['SENDER_B'],
413
+ },
414
+ }}
415
+ senderDetailsByChannel={senderDetailsByChannel}
416
+ />
417
+ </TestWrapper>
418
+ );
419
+
420
+ await waitFor(() => {
421
+ expect(lastSendTestMessageProps.deliverySettings).toEqual({
422
+ domainId: 1,
423
+ domainGatewayMapId: 11,
424
+ gsmSenderId: 'SENDER_A_DEFAULT',
425
+ cdmaSenderId: 'CDMA_A',
426
+ });
427
+ });
428
+ });
429
+
430
+ it('should keep SMS delivery settings empty when DLT is enabled and no registered sender ID matches', async () => {
431
+ const senderDetailsByChannel = {
432
+ [CHANNELS.SMS]: [
433
+ {
434
+ domainId: 1,
435
+ dgmId: 11,
436
+ gsmSenders: [{ value: 'SENDER_A' }],
437
+ cdmaSenders: [{ value: 'CDMA_A' }],
438
+ },
439
+ ],
440
+ };
441
+
442
+ render(
443
+ <TestWrapper>
444
+ <CommonTestAndPreview
445
+ {...defaultProps}
446
+ channel={CHANNELS.SMS}
447
+ formData={{
448
+ templateConfigs: {
449
+ traiDltEnabled: true,
450
+ registeredSenderIds: ['SENDER_X'],
451
+ },
452
+ }}
453
+ senderDetailsByChannel={senderDetailsByChannel}
454
+ />
455
+ </TestWrapper>
456
+ );
457
+
458
+ await waitFor(() => {
459
+ expect(lastSendTestMessageProps).toBeDefined();
460
+ });
461
+
462
+ expect(lastSendTestMessageProps.deliverySettings).toEqual({
463
+ domainId: null,
464
+ domainGatewayMapId: null,
465
+ gsmSenderId: '',
466
+ cdmaSenderId: '',
467
+ });
468
+ });
469
+
470
+ it('should auto-set WhatsApp delivery settings from formData accountName when matching account exists', async () => {
471
+ const senderDetailsByChannel = {
472
+ [CHANNELS.WHATSAPP]: [
473
+ {
474
+ domainId: 1,
475
+ sourceAccountIdentifier: 'waba-1',
476
+ gsmSenders: [{ value: '+1111111111' }],
477
+ },
478
+ {
479
+ domainId: 2,
480
+ sourceAccountIdentifier: 'waba-2',
481
+ gsmSenders: [{ value: '+2222222222' }],
482
+ },
483
+ ],
484
+ };
485
+ const wecrmAccounts = [
486
+ { name: 'Account One', sourceAccountIdentifier: 'waba-1' },
487
+ { name: 'Account Two', sourceAccountIdentifier: 'waba-2' },
488
+ ];
489
+
490
+ render(
491
+ <TestWrapper>
492
+ <CommonTestAndPreview
493
+ {...defaultProps}
494
+ channel={CHANNELS.WHATSAPP}
495
+ formData={{ accountName: 'Account Two', templateMsg: 'WhatsApp test' }}
496
+ senderDetailsByChannel={senderDetailsByChannel}
497
+ wecrmAccounts={wecrmAccounts}
498
+ />
499
+ </TestWrapper>
500
+ );
501
+
502
+ await waitFor(() => {
503
+ expect(lastSendTestMessageProps).toBeDefined();
504
+ expect(lastSendTestMessageProps.deliverySettings).toEqual({
505
+ domainId: 2,
506
+ senderMobNum: '+2222222222',
507
+ sourceAccountIdentifier: 'waba-2',
508
+ });
509
+ });
510
+ });
511
+
512
+ it('should include delivery settings in payload when handleSendTestMessage is called for EMAIL', async () => {
513
+ render(
514
+ <TestWrapper>
515
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.EMAIL} />
516
+ </TestWrapper>
517
+ );
518
+ await waitFor(() => {
519
+ expect(lastSendTestMessageProps).toBeDefined();
520
+ expect(typeof lastSendTestMessageProps.handleSendTestMessage).toBe('function');
521
+ });
522
+ lastSendTestMessageProps.handleSendTestMessage();
523
+ expect(mockActions.createMessageMetaRequested).toHaveBeenCalled();
524
+ const [initialPayload] = mockActions.createMessageMetaRequested.mock.calls[0];
525
+ expect(initialPayload.emailDeliverySettings).toBeDefined();
526
+ expect(initialPayload.emailDeliverySettings.channelSettings).toBeDefined();
527
+ expect(initialPayload.emailDeliverySettings.channelSettings.channel).toBe(CHANNELS.EMAIL);
528
+ });
529
+
530
+ it('should include delivery settings in payload when handleSendTestMessage is called for SMS', async () => {
531
+ render(
532
+ <TestWrapper>
533
+ <CommonTestAndPreview
534
+ {...defaultProps}
535
+ channel={CHANNELS.SMS}
536
+ formData={{ 'sms-editor': 'Test SMS' }}
537
+ />
538
+ </TestWrapper>
539
+ );
540
+ await waitFor(() => {
541
+ expect(lastSendTestMessageProps).toBeDefined();
542
+ });
543
+ lastSendTestMessageProps.handleSendTestMessage();
544
+ expect(mockActions.createMessageMetaRequested).toHaveBeenCalled();
545
+ const [initialPayload] = mockActions.createMessageMetaRequested.mock.calls[0];
546
+ expect(initialPayload.smsDeliverySettings).toBeDefined();
547
+ expect(initialPayload.smsDeliverySettings.channelSettings).toBeDefined();
548
+ expect(initialPayload.smsDeliverySettings.channelSettings.channel).toBe(CHANNELS.SMS);
549
+ });
550
+ });
551
+
552
+ describe('Carousel payload (getCarouselMappedData) - handleSendTestMessage', () => {
553
+ it('should map empty carouselData to empty cards when mediaType is CAROUSEL', async () => {
554
+ const props = {
555
+ ...defaultProps,
556
+ channel: CHANNELS.WHATSAPP,
557
+ formData: {
558
+ templateMsg: 'Message',
559
+ mediaType: MEDIA_TYPE_CAROUSEL,
560
+ carouselData: [],
561
+ },
562
+ };
563
+ render(
564
+ <TestWrapper>
565
+ <CommonTestAndPreview {...props} />
566
+ </TestWrapper>
567
+ );
568
+ await waitFor(() => {
569
+ expect(lastSendTestMessageProps).toBeDefined();
570
+ expect(typeof lastSendTestMessageProps.handleSendTestMessage).toBe('function');
571
+ });
572
+ lastSendTestMessageProps.handleSendTestMessage();
573
+ expect(mockActions.createMessageMetaRequested).toHaveBeenCalled();
574
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
575
+ expect(payload.whatsappMessageContent.templateConfigs.cards).toEqual([]);
576
+ expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('IMAGE');
577
+ });
578
+
579
+ it('should map carousel with IMAGE media and bodyText to cards with media.url', async () => {
580
+ const props = {
581
+ ...defaultProps,
582
+ channel: CHANNELS.WHATSAPP,
583
+ formData: {
584
+ templateMsg: 'Message',
585
+ mediaType: MEDIA_TYPE_CAROUSEL,
586
+ carouselMediaType: 'IMAGE',
587
+ carouselData: [
588
+ {
589
+ bodyText: 'Card body',
590
+ imageUrl: 'https://image.example.com/1.jpg',
591
+ mediaType: 'image',
592
+ buttons: [],
593
+ },
594
+ ],
595
+ },
596
+ };
597
+ render(
598
+ <TestWrapper>
599
+ <CommonTestAndPreview {...props} />
600
+ </TestWrapper>
601
+ );
602
+ await waitFor(() => {
603
+ expect(lastSendTestMessageProps).toBeDefined();
604
+ });
605
+ lastSendTestMessageProps.handleSendTestMessage();
606
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
607
+ const cards = payload.whatsappMessageContent.templateConfigs.cards;
608
+ expect(cards).toHaveLength(1);
609
+ expect(cards[0].body).toBe('Card body');
610
+ expect(cards[0].media).toEqual({ url: 'https://image.example.com/1.jpg' });
611
+ expect(cards[0].mediaType).toBe('IMAGE');
612
+ expect(cards[0].buttons).toEqual([]);
613
+ expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('IMAGE');
614
+ });
615
+
616
+ it('should map carousel with VIDEO media to cards with url and previewUrl', async () => {
617
+ const props = {
618
+ ...defaultProps,
619
+ channel: CHANNELS.WHATSAPP,
620
+ formData: {
621
+ templateMsg: 'Message',
622
+ mediaType: MEDIA_TYPE_CAROUSEL,
623
+ carouselMediaType: 'VIDEO',
624
+ carouselData: [
625
+ {
626
+ bodyText: 'Video card',
627
+ videoUrl: 'https://video.example.com/1.mp4',
628
+ videoPreviewImg: 'https://preview.example.com/1.jpg',
629
+ mediaType: 'video',
630
+ buttons: [],
631
+ },
632
+ ],
633
+ },
634
+ };
635
+ render(
636
+ <TestWrapper>
637
+ <CommonTestAndPreview {...props} />
638
+ </TestWrapper>
639
+ );
640
+ await waitFor(() => {
641
+ expect(lastSendTestMessageProps).toBeDefined();
642
+ });
643
+ lastSendTestMessageProps.handleSendTestMessage();
644
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
645
+ const cards = payload.whatsappMessageContent.templateConfigs.cards;
646
+ expect(cards).toHaveLength(1);
647
+ expect(cards[0].body).toBe('Video card');
648
+ expect(cards[0].media).toEqual({
649
+ url: 'https://video.example.com/1.mp4',
650
+ previewUrl: 'https://preview.example.com/1.jpg',
651
+ });
652
+ expect(cards[0].mediaType).toBe('VIDEO');
653
+ expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('VIDEO');
654
+ });
655
+
656
+ it('should map button type PHONE_NUMBER to buttonObj with phoneNumber', async () => {
657
+ const props = {
658
+ ...defaultProps,
659
+ channel: CHANNELS.WHATSAPP,
660
+ formData: {
661
+ templateMsg: 'Message',
662
+ mediaType: MEDIA_TYPE_CAROUSEL,
663
+ carouselData: [
664
+ {
665
+ bodyText: 'Card',
666
+ mediaType: 'image',
667
+ imageUrl: 'https://img.url',
668
+ buttons: [
669
+ { type: 'PHONE_NUMBER', text: 'Call', phone_number: '+1234567890' },
670
+ ],
671
+ },
672
+ ],
673
+ },
674
+ };
675
+ render(
676
+ <TestWrapper>
677
+ <CommonTestAndPreview {...props} />
678
+ </TestWrapper>
679
+ );
680
+ await waitFor(() => {
681
+ expect(lastSendTestMessageProps).toBeDefined();
682
+ });
683
+ lastSendTestMessageProps.handleSendTestMessage();
684
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
685
+ const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
686
+ expect(buttons).toHaveLength(1);
687
+ expect(buttons[0].type).toBe('PHONE_NUMBER');
688
+ expect(buttons[0].text).toBe('Call');
689
+ expect(buttons[0].index).toBe(0);
690
+ expect(buttons[0].phoneNumber).toBe('+1234567890');
691
+ });
692
+
693
+ it('should map button type URL without DYNAMIC_URL to buttonObj with url only', async () => {
694
+ const props = {
695
+ ...defaultProps,
696
+ channel: CHANNELS.WHATSAPP,
697
+ formData: {
698
+ templateMsg: 'Message',
699
+ mediaType: MEDIA_TYPE_CAROUSEL,
700
+ carouselData: [
701
+ {
702
+ bodyText: 'Card',
703
+ mediaType: 'image',
704
+ imageUrl: 'https://img.url',
705
+ buttons: [
706
+ { type: 'URL', text: 'Open', urlType: 'STATIC', url: 'https://example.com' },
707
+ ],
708
+ },
709
+ ],
710
+ },
711
+ };
712
+ render(
713
+ <TestWrapper>
714
+ <CommonTestAndPreview {...props} />
715
+ </TestWrapper>
716
+ );
717
+ await waitFor(() => {
718
+ expect(lastSendTestMessageProps).toBeDefined();
719
+ });
720
+ lastSendTestMessageProps.handleSendTestMessage();
721
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
722
+ const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
723
+ expect(buttons[0].type).toBe('URL');
724
+ expect(buttons[0].url).toBe('https://example.com');
725
+ expect(buttons[0].dynamicUrlPayload).toBeUndefined();
726
+ });
727
+
728
+ it('should set dynamicUrlPayload when button type URL and urlType DYNAMIC_URL with single template', async () => {
729
+ const props = {
730
+ ...defaultProps,
731
+ channel: CHANNELS.WHATSAPP,
732
+ formData: {
733
+ templateMsg: 'Message',
734
+ mediaType: MEDIA_TYPE_CAROUSEL,
735
+ carouselData: [
736
+ {
737
+ bodyText: 'Card',
738
+ mediaType: 'image',
739
+ imageUrl: 'https://img.url',
740
+ buttons: [
741
+ { type: 'URL', text: 'Open', urlType: 'DYNAMIC_URL', url: 'https://example.com/{{id}}' },
742
+ ],
743
+ },
744
+ ],
745
+ },
746
+ };
747
+ render(
748
+ <TestWrapper>
749
+ <CommonTestAndPreview {...props} />
750
+ </TestWrapper>
751
+ );
752
+ await waitFor(() => {
753
+ expect(lastSendTestMessageProps).toBeDefined();
754
+ });
755
+ lastSendTestMessageProps.handleSendTestMessage();
756
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
757
+ const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
758
+ expect(buttons[0].url).toBe('https://example.com/{{id}}');
759
+ expect(buttons[0].dynamicUrlPayload).toBe('{{id}}');
760
+ });
761
+
762
+ it('should set dynamicUrlPayload to empty when urlType DYNAMIC_URL but multiple or zero matches', async () => {
763
+ const props = {
764
+ ...defaultProps,
765
+ channel: CHANNELS.WHATSAPP,
766
+ formData: {
767
+ templateMsg: 'Message',
768
+ mediaType: MEDIA_TYPE_CAROUSEL,
769
+ carouselData: [
770
+ {
771
+ bodyText: 'Card',
772
+ mediaType: 'image',
773
+ imageUrl: 'https://img.url',
774
+ buttons: [
775
+ { type: 'URL', text: 'Open', urlType: 'DYNAMIC_URL', url: 'https://example.com/{{a}}{{b}}' },
776
+ ],
777
+ },
778
+ ],
779
+ },
780
+ };
781
+ render(
782
+ <TestWrapper>
783
+ <CommonTestAndPreview {...props} />
784
+ </TestWrapper>
785
+ );
786
+ await waitFor(() => {
787
+ expect(lastSendTestMessageProps).toBeDefined();
788
+ });
789
+ lastSendTestMessageProps.handleSendTestMessage();
790
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
791
+ const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
792
+ expect(buttons[0].dynamicUrlPayload).toBe('');
793
+ });
794
+
795
+ it('should set dynamicUrlPayload to empty when urlType DYNAMIC_URL and url is null/undefined', async () => {
796
+ const props = {
797
+ ...defaultProps,
798
+ channel: CHANNELS.WHATSAPP,
799
+ formData: {
800
+ templateMsg: 'Message',
801
+ mediaType: MEDIA_TYPE_CAROUSEL,
802
+ carouselData: [
803
+ {
804
+ bodyText: 'Card',
805
+ mediaType: 'image',
806
+ imageUrl: 'https://img.url',
807
+ buttons: [
808
+ { type: 'URL', text: 'Open', urlType: 'DYNAMIC_URL', url: null },
809
+ ],
810
+ },
811
+ ],
812
+ },
813
+ };
814
+ render(
815
+ <TestWrapper>
816
+ <CommonTestAndPreview {...props} />
817
+ </TestWrapper>
818
+ );
819
+ await waitFor(() => {
820
+ expect(lastSendTestMessageProps).toBeDefined();
821
+ });
822
+ lastSendTestMessageProps.handleSendTestMessage();
823
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
824
+ const buttons = payload.whatsappMessageContent.templateConfigs.cards[0].buttons;
825
+ expect(buttons[0].dynamicUrlPayload).toBe('');
826
+ });
827
+
828
+ it('should pass through cardVarMapped and bodyTemplate on each card', async () => {
829
+ const props = {
830
+ ...defaultProps,
831
+ channel: CHANNELS.WHATSAPP,
832
+ formData: {
833
+ templateMsg: 'Message',
834
+ mediaType: MEDIA_TYPE_CAROUSEL,
835
+ carouselData: [
836
+ {
837
+ bodyText: 'Body',
838
+ cardVarMapped: { foo: 'bar' },
839
+ bodyTemplate: 'Body {{foo}}',
840
+ mediaType: 'image',
841
+ imageUrl: 'https://img.url',
842
+ buttons: [],
843
+ },
844
+ ],
845
+ },
846
+ };
847
+ render(
848
+ <TestWrapper>
849
+ <CommonTestAndPreview {...props} />
850
+ </TestWrapper>
851
+ );
852
+ await waitFor(() => {
853
+ expect(lastSendTestMessageProps).toBeDefined();
854
+ });
855
+ lastSendTestMessageProps.handleSendTestMessage();
856
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
857
+ const card = payload.whatsappMessageContent.templateConfigs.cards[0];
858
+ expect(card.cardVarMapped).toEqual({ foo: 'bar' });
859
+ expect(card.bodyTemplate).toBe('Body {{foo}}');
860
+ });
861
+
862
+ it('should not add media url when mediaType is neither image nor video', async () => {
863
+ const props = {
864
+ ...defaultProps,
865
+ channel: CHANNELS.WHATSAPP,
866
+ formData: {
867
+ templateMsg: 'Message',
868
+ mediaType: MEDIA_TYPE_CAROUSEL,
869
+ carouselData: [
870
+ {
871
+ bodyText: 'Card',
872
+ mediaType: 'DOCUMENT',
873
+ imageUrl: 'https://img.url',
874
+ videoUrl: 'https://video.url',
875
+ buttons: [],
876
+ },
877
+ ],
878
+ },
879
+ };
880
+ render(
881
+ <TestWrapper>
882
+ <CommonTestAndPreview {...props} />
883
+ </TestWrapper>
884
+ );
885
+ await waitFor(() => {
886
+ expect(lastSendTestMessageProps).toBeDefined();
887
+ });
888
+ lastSendTestMessageProps.handleSendTestMessage();
889
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
890
+ const card = payload.whatsappMessageContent.templateConfigs.cards[0];
891
+ expect(card.media).toEqual({});
892
+ expect(card.mediaType).toBe('DOCUMENT');
893
+ });
894
+
895
+ it('should handle multiple carousel cards with mixed button types', async () => {
896
+ const props = {
897
+ ...defaultProps,
898
+ channel: CHANNELS.WHATSAPP,
899
+ formData: {
900
+ templateMsg: 'Message',
901
+ mediaType: MEDIA_TYPE_CAROUSEL,
902
+ carouselData: [
903
+ {
904
+ bodyText: 'First',
905
+ mediaType: 'image',
906
+ imageUrl: 'https://first.jpg',
907
+ buttons: [{ type: 'PHONE_NUMBER', text: 'Call', phone_number: '+111' }],
908
+ },
909
+ {
910
+ bodyText: 'Second',
911
+ mediaType: 'video',
912
+ videoUrl: 'https://second.mp4',
913
+ videoPreviewImg: 'https://second-prev.jpg',
914
+ buttons: [{ type: 'URL', text: 'Link', urlType: 'DYNAMIC_URL', url: 'https://x/{{only}}' }],
915
+ },
916
+ ],
917
+ },
918
+ };
919
+ render(
920
+ <TestWrapper>
921
+ <CommonTestAndPreview {...props} />
922
+ </TestWrapper>
923
+ );
924
+ await waitFor(() => {
925
+ expect(lastSendTestMessageProps).toBeDefined();
926
+ });
927
+ lastSendTestMessageProps.handleSendTestMessage();
928
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
929
+ const cards = payload.whatsappMessageContent.templateConfigs.cards;
930
+ expect(cards).toHaveLength(2);
931
+ expect(cards[0].body).toBe('First');
932
+ expect(cards[0].media.url).toBe('https://first.jpg');
933
+ expect(cards[0].buttons[0].phoneNumber).toBe('+111');
934
+ expect(cards[1].body).toBe('Second');
935
+ expect(cards[1].media.url).toBe('https://second.mp4');
936
+ expect(cards[1].media.previewUrl).toBe('https://second-prev.jpg');
937
+ expect(cards[1].buttons[0].dynamicUrlPayload).toBe('{{only}}');
938
+ });
939
+
940
+ it('should use carouselMediaType for templateConfigs.mediaType when provided', async () => {
941
+ const props = {
942
+ ...defaultProps,
943
+ channel: CHANNELS.WHATSAPP,
944
+ formData: {
945
+ templateMsg: 'Message',
946
+ mediaType: MEDIA_TYPE_CAROUSEL,
947
+ carouselMediaType: 'VIDEO',
948
+ carouselData: [
949
+ { bodyText: 'Card', mediaType: 'image', imageUrl: 'https://img.url', buttons: [] },
950
+ ],
951
+ },
952
+ };
953
+ render(
954
+ <TestWrapper>
955
+ <CommonTestAndPreview {...props} />
956
+ </TestWrapper>
957
+ );
958
+ await waitFor(() => {
959
+ expect(lastSendTestMessageProps).toBeDefined();
960
+ });
961
+ lastSendTestMessageProps.handleSendTestMessage();
962
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
963
+ expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('VIDEO');
964
+ });
965
+
966
+ it('should default templateConfigs.mediaType to IMAGE when carouselMediaType is missing', async () => {
967
+ const props = {
968
+ ...defaultProps,
969
+ channel: CHANNELS.WHATSAPP,
970
+ formData: {
971
+ templateMsg: 'Message',
972
+ mediaType: MEDIA_TYPE_CAROUSEL,
973
+ carouselData: [
974
+ { bodyText: 'Card', mediaType: 'image', imageUrl: 'https://img.url', buttons: [] },
975
+ ],
976
+ },
977
+ };
978
+ render(
979
+ <TestWrapper>
980
+ <CommonTestAndPreview {...props} />
981
+ </TestWrapper>
982
+ );
983
+ await waitFor(() => {
984
+ expect(lastSendTestMessageProps).toBeDefined();
985
+ });
986
+ lastSendTestMessageProps.handleSendTestMessage();
987
+ const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
988
+ expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('IMAGE');
989
+ });
990
+ });
991
+
186
992
  describe('Component Rendering', () => {
187
993
  it('should render when show is true', async () => {
188
994
  render(
@@ -2464,4 +3270,107 @@ describe('CommonTestAndPreview', () => {
2464
3270
  });
2465
3271
  });
2466
3272
  });
3273
+
3274
+ describe('SMS DLT and mustache tag discrimination (smsTemplateHasMustacheTags / buildSyntheticSmsMustacheTags)', () => {
3275
+ it('should return no tags for SMS content that contains only DLT {#var#} tokens', async () => {
3276
+ render(
3277
+ <TestWrapper>
3278
+ <CommonTestAndPreview
3279
+ {...defaultProps}
3280
+ channel={CHANNELS.SMS}
3281
+ formData={{ 0: { 'sms-editor': 'Order {#orderId#} is confirmed' } }}
3282
+ extractedTags={[]}
3283
+ />
3284
+ </TestWrapper>
3285
+ );
3286
+
3287
+ await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3288
+
3289
+ // smsTemplateHasMustacheTags returns false for DLT-only → extractedTags is []
3290
+ expect(lastLeftPanelContentProps.extractedTags).toEqual([]);
3291
+ });
3292
+
3293
+ it('should build synthetic tags from {{mustache}} tokens, excluding DLT {#var#} tokens', async () => {
3294
+ render(
3295
+ <TestWrapper>
3296
+ <CommonTestAndPreview
3297
+ {...defaultProps}
3298
+ channel={CHANNELS.SMS}
3299
+ formData={{ 0: { 'sms-editor': 'Hi {{name}}, order {#orderId#} shipped' } }}
3300
+ extractedTags={[]}
3301
+ />
3302
+ </TestWrapper>
3303
+ );
3304
+
3305
+ await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3306
+
3307
+ const tags = lastLeftPanelContentProps.extractedTags;
3308
+ // Only {{name}} should become a tag — {#orderId#} must be excluded
3309
+ expect(tags).toHaveLength(1);
3310
+ expect(tags[0].name).toBe('name');
3311
+ });
3312
+
3313
+ it('should use API-extracted tags when present instead of building synthetic ones', async () => {
3314
+ const apiTags = [{ name: 'firstName', metaData: { userDriven: true }, children: [] }];
3315
+ render(
3316
+ <TestWrapper>
3317
+ <CommonTestAndPreview
3318
+ {...defaultProps}
3319
+ channel={CHANNELS.SMS}
3320
+ formData={{ 0: { 'sms-editor': 'Hi {{firstName}}' } }}
3321
+ extractedTags={apiTags}
3322
+ />
3323
+ </TestWrapper>
3324
+ );
3325
+
3326
+ await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3327
+
3328
+ // API tags take priority over buildSyntheticSmsMustacheTags
3329
+ expect(lastLeftPanelContentProps.extractedTags).toEqual(apiTags);
3330
+ });
3331
+ });
3332
+
3333
+ describe('handleDiscardCustomValues — preview reset', () => {
3334
+ it('should call updatePreviewRequested when handleDiscardCustomValues is invoked', async () => {
3335
+ render(
3336
+ <TestWrapper>
3337
+ <CommonTestAndPreview
3338
+ {...defaultProps}
3339
+ channel={CHANNELS.SMS}
3340
+ formData={{ 0: { 'sms-editor': 'Hi {{name}}' } }}
3341
+ />
3342
+ </TestWrapper>
3343
+ );
3344
+
3345
+ await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
3346
+
3347
+ lastCustomValuesEditorProps.handleDiscardCustomValues();
3348
+
3349
+ expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
3350
+ });
3351
+
3352
+ it('should call updatePreviewRequested with RCS channel when handleDiscardCustomValues is invoked for RCS with fallback', async () => {
3353
+ render(
3354
+ <TestWrapper>
3355
+ <CommonTestAndPreview
3356
+ {...defaultProps}
3357
+ channel={CHANNELS.RCS}
3358
+ smsFallbackContent={{
3359
+ templateContent: 'Fallback {{name}}',
3360
+ content: 'Fallback {{name}}',
3361
+ }}
3362
+ formData={{}}
3363
+ />
3364
+ </TestWrapper>
3365
+ );
3366
+
3367
+ await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
3368
+
3369
+ lastCustomValuesEditorProps.handleDiscardCustomValues();
3370
+
3371
+ // updatePreviewRequested is called; syncSmsFallbackPreview (which hits Api directly) is NOT called
3372
+ expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
3373
+ });
3374
+ });
2467
3375
  });
3376
+