@capillarytech/creatives-library 8.0.255-alpha.4 → 8.0.255

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 (278) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +2 -2
  4. package/initialReducer.js +2 -0
  5. package/package.json +1 -1
  6. package/services/api.js +10 -5
  7. package/services/tests/api.test.js +34 -0
  8. package/translations/en.json +3 -4
  9. package/utils/common.js +5 -6
  10. package/utils/commonUtils.js +28 -5
  11. package/utils/tests/commonUtil.test.js +224 -0
  12. package/utils/tests/transformerUtils.test.js +0 -297
  13. package/utils/transformTemplateConfig.js +0 -10
  14. package/utils/transformerUtils.js +0 -40
  15. package/v2Components/CapDeviceContent/index.js +61 -56
  16. package/v2Components/CapImageUpload/constants.js +0 -2
  17. package/v2Components/CapImageUpload/index.js +16 -65
  18. package/v2Components/CapImageUpload/index.scss +1 -4
  19. package/v2Components/CapImageUpload/messages.js +1 -5
  20. package/v2Components/CapTagList/index.js +6 -1
  21. package/v2Components/CapTagListWithInput/index.js +5 -1
  22. package/v2Components/CapTagListWithInput/messages.js +1 -1
  23. package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
  24. package/v2Components/ErrorInfoNote/constants.js +1 -0
  25. package/v2Components/ErrorInfoNote/index.js +457 -72
  26. package/v2Components/ErrorInfoNote/messages.js +36 -6
  27. package/v2Components/ErrorInfoNote/style.scss +282 -6
  28. package/v2Components/FormBuilder/tests/index.test.js +13 -4
  29. package/v2Components/HtmlEditor/HTMLEditor.js +547 -94
  30. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +874 -0
  31. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1441 -133
  32. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
  33. package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
  34. package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
  35. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +23 -102
  36. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +148 -140
  37. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
  38. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  39. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +9 -0
  40. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +4 -4
  41. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +22 -0
  42. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
  43. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
  44. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
  45. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  46. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
  47. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +3 -6
  48. package/v2Components/HtmlEditor/components/PreviewPane/index.js +22 -43
  49. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  50. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +1 -0
  51. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +49 -31
  52. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +50 -34
  53. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +6 -0
  54. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +70 -41
  55. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +255 -0
  56. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +364 -0
  57. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
  58. package/v2Components/HtmlEditor/constants.js +42 -20
  59. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
  60. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +103 -0
  61. package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
  62. package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
  63. package/v2Components/HtmlEditor/hooks/useValidation.js +189 -53
  64. package/v2Components/HtmlEditor/index.js +1 -1
  65. package/v2Components/HtmlEditor/messages.js +92 -94
  66. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +94 -45
  67. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +134 -0
  68. package/v2Components/HtmlEditor/utils/contentSanitizer.js +40 -41
  69. package/v2Components/HtmlEditor/utils/htmlValidator.js +71 -72
  70. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +134 -102
  71. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
  72. package/v2Components/HtmlEditor/utils/validationAdapter.js +66 -41
  73. package/v2Components/HtmlEditor/utils/validationConstants.js +40 -0
  74. package/v2Components/MobilePushPreviewV2/index.js +32 -7
  75. package/v2Components/TemplatePreview/_templatePreview.scss +55 -24
  76. package/v2Components/TemplatePreview/index.js +47 -32
  77. package/v2Components/TemplatePreview/messages.js +4 -0
  78. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +1 -0
  79. package/v2Containers/App/constants.js +0 -5
  80. package/v2Containers/BeeEditor/index.js +172 -90
  81. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +14 -0
  82. package/v2Containers/BeePopupEditor/constants.js +10 -0
  83. package/v2Containers/BeePopupEditor/index.js +194 -0
  84. package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
  85. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +3 -4
  86. package/v2Containers/CreativesContainer/SlideBoxContent.js +129 -107
  87. package/v2Containers/CreativesContainer/SlideBoxFooter.js +163 -13
  88. package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
  89. package/v2Containers/CreativesContainer/constants.js +1 -3
  90. package/v2Containers/CreativesContainer/index.js +239 -214
  91. package/v2Containers/CreativesContainer/messages.js +8 -4
  92. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +0 -210
  93. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +11 -2
  94. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -354
  95. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +106 -0
  96. package/v2Containers/Email/actions.js +7 -0
  97. package/v2Containers/Email/constants.js +5 -1
  98. package/v2Containers/Email/index.js +234 -29
  99. package/v2Containers/Email/messages.js +32 -0
  100. package/v2Containers/Email/reducer.js +12 -1
  101. package/v2Containers/Email/sagas.js +61 -7
  102. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
  103. package/v2Containers/Email/tests/reducer.test.js +46 -0
  104. package/v2Containers/Email/tests/sagas.test.js +320 -29
  105. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1285 -0
  106. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +211 -21
  107. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
  108. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +1880 -0
  109. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +520 -0
  110. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
  111. package/v2Containers/EmailWrapper/constants.js +2 -0
  112. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +629 -77
  113. package/v2Containers/EmailWrapper/index.js +103 -23
  114. package/v2Containers/EmailWrapper/messages.js +65 -1
  115. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +643 -0
  116. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +594 -77
  117. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
  118. package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
  119. package/v2Containers/InApp/actions.js +7 -0
  120. package/v2Containers/InApp/constants.js +20 -4
  121. package/v2Containers/InApp/index.js +802 -359
  122. package/v2Containers/InApp/index.scss +4 -3
  123. package/v2Containers/InApp/messages.js +7 -3
  124. package/v2Containers/InApp/reducer.js +21 -3
  125. package/v2Containers/InApp/sagas.js +29 -9
  126. package/v2Containers/InApp/selectors.js +25 -5
  127. package/v2Containers/InApp/tests/index.test.js +154 -50
  128. package/v2Containers/InApp/tests/reducer.test.js +34 -0
  129. package/v2Containers/InApp/tests/sagas.test.js +61 -9
  130. package/v2Containers/InApp/tests/selectors.test.js +612 -0
  131. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +151 -0
  132. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
  133. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +23 -0
  134. package/v2Containers/InAppWrapper/constants.js +16 -0
  135. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
  136. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
  137. package/v2Containers/InAppWrapper/index.js +148 -0
  138. package/v2Containers/InAppWrapper/messages.js +49 -0
  139. package/v2Containers/InappAdvance/index.js +1099 -0
  140. package/v2Containers/InappAdvance/index.scss +10 -0
  141. package/v2Containers/InappAdvance/tests/index.test.js +448 -0
  142. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +15 -36
  143. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +8 -8
  144. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +77 -100
  145. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +63 -72
  146. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +190 -250
  147. package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +12 -16
  148. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +40 -48
  149. package/v2Containers/TagList/index.js +62 -19
  150. package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
  151. package/v2Containers/Templates/_templates.scss +56 -202
  152. package/v2Containers/Templates/actions.js +1 -2
  153. package/v2Containers/Templates/constants.js +0 -1
  154. package/v2Containers/Templates/index.js +123 -278
  155. package/v2Containers/Templates/messages.js +4 -24
  156. package/v2Containers/Templates/reducer.js +0 -2
  157. package/v2Containers/Templates/tests/index.test.js +0 -10
  158. package/v2Containers/TemplatesV2/index.js +7 -15
  159. package/v2Containers/TemplatesV2/messages.js +0 -4
  160. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +768 -1272
  161. package/utils/imageUrlUpload.js +0 -141
  162. package/v2Components/CapImageUrlUpload/constants.js +0 -26
  163. package/v2Components/CapImageUrlUpload/index.js +0 -365
  164. package/v2Components/CapImageUrlUpload/index.scss +0 -35
  165. package/v2Components/CapImageUrlUpload/messages.js +0 -47
  166. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +0 -152
  167. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
  168. package/v2Containers/WebPush/Create/components/BrandIconSection.js +0 -108
  169. package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -172
  170. package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
  171. package/v2Containers/WebPush/Create/components/ButtonList.js +0 -145
  172. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +0 -164
  173. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +0 -463
  174. package/v2Containers/WebPush/Create/components/FormActions.js +0 -54
  175. package/v2Containers/WebPush/Create/components/FormActions.test.js +0 -163
  176. package/v2Containers/WebPush/Create/components/MediaSection.js +0 -142
  177. package/v2Containers/WebPush/Create/components/MediaSection.test.js +0 -341
  178. package/v2Containers/WebPush/Create/components/MessageSection.js +0 -103
  179. package/v2Containers/WebPush/Create/components/MessageSection.test.js +0 -268
  180. package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +0 -87
  181. package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +0 -210
  182. package/v2Containers/WebPush/Create/components/TemplateNameSection.js +0 -54
  183. package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +0 -143
  184. package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +0 -86
  185. package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +0 -16
  186. package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +0 -41
  187. package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +0 -54
  188. package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +0 -37
  189. package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +0 -21
  190. package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
  191. package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
  192. package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
  193. package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -633
  194. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
  195. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
  196. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -78
  197. package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +0 -138
  198. package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +0 -406
  199. package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +0 -30
  200. package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +0 -151
  201. package/v2Containers/WebPush/Create/hooks/useImageUpload.js +0 -104
  202. package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +0 -538
  203. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -122
  204. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -633
  205. package/v2Containers/WebPush/Create/index.js +0 -1148
  206. package/v2Containers/WebPush/Create/index.scss +0 -134
  207. package/v2Containers/WebPush/Create/messages.js +0 -203
  208. package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -228
  209. package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -294
  210. package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -90
  211. package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -305
  212. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -23
  213. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -155
  214. package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
  215. package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
  216. package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +0 -9
  217. package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +0 -9
  218. package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
  219. package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
  220. package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +0 -106
  221. package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
  222. package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +0 -9
  223. package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +0 -9
  224. package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
  225. package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
  226. package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +0 -9
  227. package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +0 -9
  228. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -47
  229. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -141
  230. package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
  231. package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -68
  232. package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -61
  233. package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -99
  234. package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -733
  235. package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +0 -571
  236. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -81
  237. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +0 -81
  238. package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -50
  239. package/v2Containers/WebPush/Create/preview/constants.js +0 -637
  240. package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -79
  241. package/v2Containers/WebPush/Create/preview/preview.scss +0 -351
  242. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -370
  243. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
  244. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
  245. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
  246. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -47
  247. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
  248. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
  249. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
  250. package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -207
  251. package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -153
  252. package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
  253. package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -101
  254. package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -229
  255. package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
  256. package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1081
  257. package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
  258. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -1327
  259. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -131
  260. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -112
  261. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
  262. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -129
  263. package/v2Containers/WebPush/Create/utils/payloadBuilder.js +0 -96
  264. package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +0 -396
  265. package/v2Containers/WebPush/Create/utils/previewUtils.js +0 -89
  266. package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -115
  267. package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
  268. package/v2Containers/WebPush/Create/utils/validation.js +0 -75
  269. package/v2Containers/WebPush/Create/utils/validation.test.js +0 -283
  270. package/v2Containers/WebPush/actions.js +0 -60
  271. package/v2Containers/WebPush/constants.js +0 -132
  272. package/v2Containers/WebPush/index.js +0 -2
  273. package/v2Containers/WebPush/reducer.js +0 -104
  274. package/v2Containers/WebPush/sagas.js +0 -119
  275. package/v2Containers/WebPush/selectors.js +0 -65
  276. package/v2Containers/WebPush/tests/reducer.test.js +0 -863
  277. package/v2Containers/WebPush/tests/sagas.test.js +0 -566
  278. package/v2Containers/WebPush/tests/selectors.test.js +0 -960
@@ -1,152 +0,0 @@
1
- /**
2
- * ValidationErrorDisplay Component Tests
3
- *
4
- * Tests for the ValidationErrorDisplay component that integrates with ErrorInfoNote.
5
- */
6
-
7
- import React from 'react';
8
- import { render, screen } from '@testing-library/react';
9
- import '@testing-library/jest-dom';
10
- import ValidationErrorDisplay from '../index';
11
-
12
- // Mock ErrorInfoNote component
13
- jest.mock('../../../../ErrorInfoNote', () => {
14
- return function MockErrorInfoNote({ errorMessages }) {
15
- const liquidErrors = errorMessages?.LIQUID_ERROR_MSG || [];
16
- const standardErrors = errorMessages?.STANDARD_ERROR_MSG || [];
17
- const hasErrors = liquidErrors.length > 0 || standardErrors.length > 0;
18
-
19
- if (!hasErrors) return null;
20
-
21
- return (
22
- <div data-testid="error-info-note">
23
- {liquidErrors.map((msg, index) => (
24
- <div key={`liquid-${index}`} data-testid="error-message">
25
- {msg}
26
- </div>
27
- ))}
28
- {standardErrors.map((msg, index) => (
29
- <div key={`standard-${index}`} data-testid="error-message">
30
- {msg}
31
- </div>
32
- ))}
33
- </div>
34
- );
35
- };
36
- });
37
-
38
- describe('ValidationErrorDisplay', () => {
39
- it('renders standard errors when validation has issues', () => {
40
- const mockValidation = {
41
- getAllIssues: () => [
42
- { message: 'Missing closing tag', severity: 'error', line: 5, column: 10 },
43
- { message: 'Invalid attribute', severity: 'error', line: 7 }
44
- ],
45
- isClean: () => false,
46
- isValidating: false
47
- };
48
-
49
- render(<ValidationErrorDisplay validation={mockValidation} />);
50
-
51
- expect(screen.getByTestId('error-info-note')).toBeInTheDocument();
52
- const errorMessages = screen.getAllByTestId('error-message');
53
- expect(errorMessages).toHaveLength(2);
54
- expect(errorMessages[0]).toHaveTextContent('Missing closing tag Line 5, Char 10.');
55
- expect(errorMessages[1]).toHaveTextContent('Invalid attribute Line 7.');
56
- });
57
-
58
- it('renders liquid errors separately', () => {
59
- const mockValidation = {
60
- getAllIssues: () => [
61
- { message: 'Invalid liquid syntax', severity: 'error', source: 'liquid-validator', line: 3 },
62
- { message: 'HTML error', severity: 'error', source: 'htmlhint', line: 10 }
63
- ],
64
- isClean: () => false,
65
- isValidating: false
66
- };
67
-
68
- render(<ValidationErrorDisplay validation={mockValidation} />);
69
-
70
- expect(screen.getByTestId('error-info-note')).toBeInTheDocument();
71
- const errorMessages = screen.getAllByTestId('error-message');
72
- expect(errorMessages).toHaveLength(2);
73
- // First should be liquid error, second should be standard error
74
- expect(errorMessages[0]).toHaveTextContent('Invalid liquid syntax Line 3.');
75
- expect(errorMessages[1]).toHaveTextContent('HTML error Line 10.');
76
- });
77
-
78
- it('does not render when validation has no errors', () => {
79
- const mockValidation = {
80
- getAllIssues: () => [],
81
- isClean: () => true,
82
- isValidating: false
83
- };
84
-
85
- const { container } = render(<ValidationErrorDisplay validation={mockValidation} />);
86
-
87
- expect(screen.queryByTestId('error-info-note')).not.toBeInTheDocument();
88
- expect(container.firstChild).toBeNull();
89
- });
90
-
91
- it('does not render when validation is null', () => {
92
- const { container } = render(<ValidationErrorDisplay validation={null} />);
93
-
94
- expect(screen.queryByTestId('error-info-note')).not.toBeInTheDocument();
95
- expect(container.firstChild).toBeNull();
96
- });
97
-
98
- it('does not render when validation is in progress', () => {
99
- const mockValidation = {
100
- getAllIssues: () => [],
101
- isClean: () => false,
102
- isValidating: true
103
- };
104
-
105
- const { container } = render(<ValidationErrorDisplay validation={mockValidation} />);
106
-
107
- expect(screen.queryByTestId('error-info-note')).not.toBeInTheDocument();
108
- expect(container.firstChild).toBeNull();
109
- });
110
-
111
- it('applies custom className', () => {
112
- const mockValidation = {
113
- getAllIssues: () => [{ message: 'Error', severity: 'error' }],
114
- isClean: () => false,
115
- isValidating: false
116
- };
117
-
118
- const { container } = render(
119
- <ValidationErrorDisplay validation={mockValidation} className="custom-class" />
120
- );
121
-
122
- const wrapper = container.querySelector('.validation-error-display');
123
- expect(wrapper).toHaveClass('custom-class');
124
- });
125
-
126
- it('handles inapp variant correctly', () => {
127
- const mockValidation = {
128
- getAllIssues: () => [{ message: 'Mobile error', severity: 'error' }],
129
- isClean: () => false,
130
- isValidating: false
131
- };
132
-
133
- render(<ValidationErrorDisplay validation={mockValidation} variant="inapp" />);
134
-
135
- expect(screen.getByTestId('error-info-note')).toBeInTheDocument();
136
- expect(screen.getByTestId('error-message')).toHaveTextContent('Mobile error');
137
- });
138
-
139
- it('includes rule information in error messages when available', () => {
140
- const mockValidation = {
141
- getAllIssues: () => [
142
- { message: 'Alt attribute required', severity: 'error', rule: 'alt-require', line: 5 }
143
- ],
144
- isClean: () => false,
145
- isValidating: false
146
- };
147
-
148
- render(<ValidationErrorDisplay validation={mockValidation} />);
149
-
150
- expect(screen.getByTestId('error-message')).toHaveTextContent('Alt attribute required Line 5. • alt-require');
151
- });
152
- });
@@ -1,214 +0,0 @@
1
- import React from 'react';
2
- import { render, fireEvent, within, screen } from '@testing-library/react';
3
- import '@testing-library/jest-dom';
4
- import { IntlProvider } from 'react-intl';
5
- import { Provider } from 'react-redux';
6
- import { configureStore } from '@capillarytech/vulcan-react-sdk/utils'
7
- import { initialReducer } from '../../../initialReducer';
8
- import EmailWrapperView from '../components/EmailWrapperView';
9
- import { EmailWrapperViewMockProps } from '../mockdata/mockdata';
10
- import { EMAIL_CREATE_MODES } from '../constants';
11
- import history from '../../../utils/history';
12
-
13
- // This mock needs to be before any imports
14
- jest.mock('../../../v2Containers/Email', () => ({
15
- __esModule: true,
16
- default: () => <div data-testid="email-create-container" />,
17
- }));
18
-
19
- // Mock react-router
20
- jest.mock('react-router-dom', () => ({
21
- ...jest.requireActual('react-router-dom'),
22
- useHistory: () => ({
23
- push: jest.fn(),
24
- replace: jest.fn(),
25
- go: jest.fn(),
26
- goBack: jest.fn(),
27
- goForward: jest.fn(),
28
- location: { search: '' }
29
- }),
30
- }));
31
-
32
- // Mock redux-auth-wrapper
33
- jest.mock('redux-auth-wrapper/history4/redirect', () => ({
34
- connectedRouterRedirect: () => (Component) => Component,
35
- }));
36
-
37
- // Mock react-router
38
- jest.mock('connected-react-router', () => ({
39
- push: jest.fn(),
40
- replace: jest.fn(),
41
- go: jest.fn(),
42
- goBack: jest.fn(),
43
- goForward: jest.fn(),
44
- }));
45
-
46
- // Mock the saga injector
47
- jest.mock('@capillarytech/vulcan-react-sdk/utils/injectSaga', () => ({
48
- __esModule: true,
49
- default: () => (Component) => Component,
50
- }));
51
-
52
-
53
- const initialState = {
54
- cap: { loading: false, error: null },
55
- router: { location: { pathname: '/' } }
56
- };
57
-
58
- describe('EmailWrapperView', () => {
59
- let store;
60
-
61
- beforeAll(() => {
62
- store = configureStore(initialState, initialReducer, history);
63
- });
64
-
65
- const renderWithProviders = (component) => {
66
- return render(
67
- <Provider store={store}>
68
- <IntlProvider locale="en" messages={{}}>
69
- {component}
70
- </IntlProvider>
71
- </Provider>
72
- );
73
- };
74
-
75
- it('renders mode selection UI when step is modeSelection', () => {
76
- const props = {
77
- ...EmailWrapperViewMockProps,
78
- step: 'modeSelection',
79
- };
80
-
81
- const { getByText } = renderWithProviders(<EmailWrapperView {...props} />);
82
- expect(getByText('Create using editor')).toBeInTheDocument();
83
- expect(getByText('Upload zip file')).toBeInTheDocument();
84
- });
85
-
86
- it('shows template name input in full mode', () => {
87
- const props = {
88
- ...EmailWrapperViewMockProps,
89
- isFullMode: true,
90
- step: 'modeSelection',
91
- };
92
-
93
- const { container } = renderWithProviders(<EmailWrapperView {...props} />);
94
- const input = container.querySelector('.ant-input');
95
- expect(input).toBeInTheDocument();
96
- expect(input.value).toBe(props.templateName);
97
- });
98
-
99
- it('handles template name changes', () => {
100
- const props = {
101
- ...EmailWrapperViewMockProps,
102
- isFullMode: true,
103
- step: 'modeSelection',
104
- onTemplateNameChange: jest.fn(),
105
- };
106
-
107
- const { container } = renderWithProviders(<EmailWrapperView {...props} />);
108
- const input = container.querySelector('.ant-input');
109
- expect(input).toBeInTheDocument();
110
-
111
- // Create a change event and fire it
112
- fireEvent.change(input, { target: { value: 'New Template Name' } });
113
-
114
- // Just verify that the function was called
115
- expect(props.onTemplateNameChange).toHaveBeenCalled();
116
- });
117
-
118
- it('shows upload button when in upload mode', () => {
119
- const props = {
120
- ...EmailWrapperViewMockProps,
121
- step: 'modeSelection',
122
- emailCreateMode: EMAIL_CREATE_MODES.UPLOAD,
123
- uploadButtonLabel: 'Upload',
124
- };
125
-
126
- const { getByText, container } = renderWithProviders(<EmailWrapperView {...props} />);
127
-
128
- // Find the "Upload zip file" section
129
- const modeSelectionSection = getByText('Upload zip file').closest('div');
130
-
131
- // Find any button in the upload section
132
- const uploadButton = container.querySelector('.ant-btn');
133
-
134
- // Verify that we found an upload button
135
- expect(uploadButton).toBeInTheDocument();
136
- expect(uploadButton.textContent).toContain('Upload');
137
- });
138
-
139
- it('shows loading spinner when uploading', () => {
140
- const props = {
141
- ...EmailWrapperViewMockProps,
142
- isUploading: true,
143
- emailCreateMode: EMAIL_CREATE_MODES.UPLOAD,
144
- step: 'modeSelection',
145
- };
146
-
147
- const { container } = renderWithProviders(<EmailWrapperView {...props} />);
148
- const spinner = container.querySelector('.ant-spin');
149
- expect(spinner).toBeInTheDocument();
150
- });
151
-
152
- it('shows content creation UI when not in mode selection', () => {
153
- const props = {
154
- ...EmailWrapperViewMockProps,
155
- step: 'contentCreation',
156
- isShowEmailCreate: true,
157
- };
158
-
159
- const { getByTestId } = renderWithProviders(<EmailWrapperView {...props} />);
160
- expect(getByTestId('email-create-container')).toBeInTheDocument();
161
- });
162
-
163
- it('disables upload button when template name is empty in full mode', () => {
164
- const props = {
165
- ...EmailWrapperViewMockProps,
166
- isFullMode: true,
167
- step: 'modeSelection',
168
- emailCreateMode: EMAIL_CREATE_MODES.UPLOAD,
169
- templateName: '',
170
- isTemplateNameEmpty: true,
171
- uploadButtonLabel: 'Upload',
172
- };
173
-
174
- const { getByText, container } = renderWithProviders(<EmailWrapperView {...props} />);
175
-
176
- // Find the Upload section
177
- getByText('Upload zip file');
178
-
179
- // Find button in the container
180
- const uploadButton = container.querySelector('.ant-btn');
181
-
182
- // Check if the button is disabled
183
- expect(uploadButton).toBeDisabled();
184
- });
185
-
186
- it('shows error message when template name is empty during upload', () => {
187
- const props = {
188
- ...EmailWrapperViewMockProps,
189
- isFullMode: true,
190
- step: 'modeSelection',
191
- emailCreateMode: EMAIL_CREATE_MODES.UPLOAD,
192
- templateName: '',
193
- isTemplateNameEmpty: true,
194
- // Add errorMessage directly to the props
195
- errorMessage: 'Please enter template name',
196
- intl: {
197
- formatMessage: () => 'Please enter template name',
198
- },
199
- };
200
-
201
- const { container } = renderWithProviders(<EmailWrapperView {...props} />);
202
-
203
- // Look for error feedback in the Ant Design form
204
- const errorElement = container.querySelector('.ant-form-item-explain');
205
-
206
- if (errorElement) {
207
- expect(errorElement.textContent).toContain('Please enter template name');
208
- } else {
209
- // If the standard error element is not found, look for any element containing the error text
210
- const allText = container.textContent;
211
- expect(allText).toContain('Please enter template name');
212
- }
213
- });
214
- });
@@ -1,108 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import { FormattedMessage } from 'react-intl';
4
- import CapRow from '@capillarytech/cap-ui-library/CapRow';
5
- import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
6
- import CapRadioGroup from '@capillarytech/cap-ui-library/CapRadioGroup';
7
- import CapDivider from '@capillarytech/cap-ui-library/CapDivider';
8
- import CapImageUpload from '../../../../v2Components/CapImageUpload';
9
- import { WEBPUSH_BRAND_ICON } from '../../../CreativesContainer/constants';
10
- import {
11
- BRAND_ICON_OPTIONS,
12
- ALLOWED_IMAGE_EXTENSIONS_REGEX,
13
- WEBPUSH_BRAND_ICON_SIZE,
14
- WEBPUSH_BRAND_ICON_RECOMMENDED_DIMENSIONS,
15
- } from '../../constants';
16
-
17
- /**
18
- * BrandIconSection component - Brand icon/logo upload options
19
- */
20
- export const BrandIconSection = ({
21
- brandIconOption,
22
- onBrandIconChange,
23
- brandIconUpload,
24
- isLocked,
25
- isAnyUploadActive,
26
- formatMessage,
27
- messages,
28
- webPush,
29
- isFullMode,
30
- }) => {
31
- const {
32
- imageSrc: brandIconSrc,
33
- uploadAsset: uploadBrandIconAsset,
34
- setUpdateImageSrc: setUpdateBrandIconSrc,
35
- updateOnReUpload: updateOnBrandIconReUpload,
36
- } = brandIconUpload;
37
-
38
- const brandIconOptions = [
39
- { value: BRAND_ICON_OPTIONS.DONT_SHOW, label: formatMessage(messages.dontShow) },
40
- { value: BRAND_ICON_OPTIONS.UPLOAD_IMAGE, label: formatMessage(messages.uploadImage) },
41
- // NOTE: Commented out due to technical blocker - "Add image URL" option for Brand icon/logo
42
- // { value: BRAND_ICON_OPTIONS.ADD_IMAGE_URL, label: formatMessage(messages.addImageUrl) },
43
- ];
44
-
45
- return (
46
- <>
47
- <CapRow className="creatives-webpush-brand-icon">
48
- <CapHeading type="h4" className="webpush-brand-icon">
49
- <FormattedMessage {...messages.brandIconLogo} />
50
- </CapHeading>
51
- <CapRadioGroup
52
- options={brandIconOptions}
53
- value={brandIconOption}
54
- onChange={onBrandIconChange}
55
- disabled={isAnyUploadActive}
56
- />
57
- </CapRow>
58
- {brandIconOption === BRAND_ICON_OPTIONS.UPLOAD_IMAGE && (
59
- <CapRow
60
- className="webpush-brand-icon-upload-section"
61
- style={isLocked ? { pointerEvents: 'none', opacity: 0.5 } : undefined}
62
- aria-disabled={isLocked}
63
- >
64
- <CapImageUpload
65
- allowedExtensionsRegex={ALLOWED_IMAGE_EXTENSIONS_REGEX}
66
- imgSize={WEBPUSH_BRAND_ICON_SIZE}
67
- uploadAsset={uploadBrandIconAsset}
68
- isFullMode={isFullMode}
69
- imageSrc={brandIconSrc}
70
- updateImageSrc={setUpdateBrandIconSrc}
71
- updateOnReUpload={updateOnBrandIconReUpload}
72
- index={1}
73
- className="cap-custom-image-upload"
74
- key="webpush-brand-icon-uploaded-image"
75
- imageData={webPush}
76
- channel={WEBPUSH_BRAND_ICON}
77
- showReUploadButton
78
- recommendedDimensions={WEBPUSH_BRAND_ICON_RECOMMENDED_DIMENSIONS}
79
- disabled={isLocked}
80
- />
81
- </CapRow>
82
- )}
83
- <CapDivider />
84
- </>
85
- );
86
- };
87
-
88
- BrandIconSection.propTypes = {
89
- brandIconOption: PropTypes.string.isRequired,
90
- onBrandIconChange: PropTypes.func.isRequired,
91
- brandIconUpload: PropTypes.object.isRequired,
92
- isLocked: PropTypes.bool,
93
- isAnyUploadActive: PropTypes.bool,
94
- formatMessage: PropTypes.func.isRequired,
95
- messages: PropTypes.object.isRequired,
96
- webPush: PropTypes.object,
97
- isFullMode: PropTypes.bool,
98
- };
99
-
100
- BrandIconSection.defaultProps = {
101
- isLocked: false,
102
- isAnyUploadActive: false,
103
- webPush: {},
104
- isFullMode: true,
105
- };
106
-
107
- export default BrandIconSection;
108
-
@@ -1,172 +0,0 @@
1
- import React, { useState, useCallback } from 'react';
2
- import PropTypes from 'prop-types';
3
- import { FormattedMessage } from 'react-intl';
4
- import CapRow from '@capillarytech/cap-ui-library/CapRow';
5
- import CapInput from '@capillarytech/cap-ui-library/CapInput';
6
- import CapButton from '@capillarytech/cap-ui-library/CapButton';
7
- import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
8
- import messages from '../messages';
9
- import { isValidHttpUrl } from '../utils/urlValidation';
10
- import { WEBPUSH_BUTTON_TYPES, BUTTON_TEXT_MAX_LENGTH } from '../../constants';
11
-
12
- const ButtonForm = ({
13
- buttonType, // 'primary' or 'secondary'
14
- formatMessage,
15
- onSave,
16
- onCancel,
17
- initialData,
18
- isEditMode,
19
- }) => {
20
- const [buttonText, setButtonText] = useState(initialData?.text || '');
21
- const [buttonUrl, setButtonUrl] = useState(initialData?.url || '');
22
- const [buttonTextError, setButtonTextError] = useState('');
23
- const [buttonUrlError, setButtonUrlError] = useState('');
24
-
25
- const validateButtonText = useCallback((value) => {
26
- if (!value || value.trim() === '') {
27
- return formatMessage(messages.buttonTextRequired);
28
- }
29
- return '';
30
- }, [formatMessage]);
31
-
32
- const validateButtonUrl = useCallback((value) => {
33
- if (!value || value.trim() === '') {
34
- return formatMessage(messages.buttonUrlRequired);
35
- }
36
-
37
- if (!isValidHttpUrl(value)) {
38
- return formatMessage(messages.buttonUrlInvalid);
39
- }
40
-
41
- return '';
42
- }, [formatMessage]);
43
-
44
- const handleButtonTextChange = useCallback((e) => {
45
- const { value } = e.target;
46
- setButtonText(value);
47
- const nextError = validateButtonText(value);
48
- setButtonTextError((prev) => (prev === nextError ? prev : nextError));
49
- }, [validateButtonText]);
50
-
51
- const handleButtonUrlChange = useCallback((e) => {
52
- const { value } = e.target;
53
- setButtonUrl(value);
54
- const nextError = validateButtonUrl(value);
55
- setButtonUrlError((prev) => (prev === nextError ? prev : nextError));
56
- }, [validateButtonUrl]);
57
-
58
- const handleSave = useCallback(() => {
59
- const textError = validateButtonText(buttonText);
60
- const urlError = validateButtonUrl(buttonUrl);
61
-
62
- if (textError || urlError) {
63
- setButtonTextError(textError);
64
- setButtonUrlError(urlError);
65
- return;
66
- }
67
-
68
- onSave({
69
- text: buttonText.trim(),
70
- url: buttonUrl.trim(),
71
- type: buttonType,
72
- });
73
- }, [buttonText, buttonUrl, buttonType, onSave, validateButtonText, validateButtonUrl]);
74
-
75
- const handleCancel = useCallback(() => {
76
- onCancel();
77
- }, [onCancel]);
78
-
79
- const isSaveDisabled = !buttonText.trim() || !buttonUrl.trim() || buttonTextError || buttonUrlError;
80
-
81
- const renderCharacterCountSuffix = () => {
82
- const currentLength = buttonText.length;
83
- const maxLength = BUTTON_TEXT_MAX_LENGTH;
84
-
85
- return (
86
- <span className="button-character-count-suffix">
87
- {`${currentLength}/${maxLength}`}
88
- </span>
89
- );
90
- };
91
-
92
- const handleKeyDown = useCallback((e) => {
93
- if (e.key === 'Enter' && !isSaveDisabled) {
94
- e.preventDefault();
95
- handleSave();
96
- }
97
- }, [handleSave, isSaveDisabled]);
98
-
99
- return (
100
- <div className="webpush-button-form" onKeyDown={handleKeyDown}>
101
- <CapRow className="button-form-row">
102
- <CapHeading type="h4" className="button-form-heading">
103
- <FormattedMessage {...messages.buttonText} />
104
- </CapHeading>
105
- <div className="button-form-field">
106
- <CapInput
107
- id={`webpush-button-text-input-${buttonType}`}
108
- placeholder={formatMessage(messages.buttonTextPlaceholder)}
109
- value={buttonText}
110
- onChange={handleButtonTextChange}
111
- maxLength={BUTTON_TEXT_MAX_LENGTH}
112
- size="default"
113
- status={buttonTextError ? 'error' : ''}
114
- help={buttonTextError || ''}
115
- suffix={renderCharacterCountSuffix()}
116
- />
117
- </div>
118
- </CapRow>
119
- <CapRow className="button-form-row">
120
- <CapHeading type="h4" className="button-form-heading">
121
- <FormattedMessage {...messages.buttonUrlLabel} />
122
- </CapHeading>
123
- <CapInput
124
- id={`webpush-button-url-input-${buttonType}`}
125
- placeholder={formatMessage(messages.buttonUrlPlaceholder)}
126
- value={buttonUrl}
127
- onChange={handleButtonUrlChange}
128
- size="default"
129
- status={buttonUrlError ? 'error' : ''}
130
- help={buttonUrlError || ''}
131
- />
132
- </CapRow>
133
- <CapRow className="button-form-actions">
134
- <CapButton
135
- type="primary"
136
- onClick={handleSave}
137
- disabled={isSaveDisabled}
138
- className="button-form-save"
139
- >
140
- <FormattedMessage {...messages.saveButton} />
141
- </CapButton>
142
- <CapButton
143
- type="secondary"
144
- onClick={handleCancel}
145
- className="button-form-cancel"
146
- >
147
- <FormattedMessage {...(isEditMode ? messages.cancelButton : messages.deleteButton)} />
148
- </CapButton>
149
- </CapRow>
150
- </div>
151
- );
152
- };
153
-
154
- ButtonForm.propTypes = {
155
- buttonType: PropTypes.oneOf([WEBPUSH_BUTTON_TYPES.PRIMARY, WEBPUSH_BUTTON_TYPES.SECONDARY]).isRequired,
156
- formatMessage: PropTypes.func.isRequired,
157
- onSave: PropTypes.func.isRequired,
158
- onCancel: PropTypes.func.isRequired,
159
- initialData: PropTypes.shape({
160
- text: PropTypes.string,
161
- url: PropTypes.string,
162
- }),
163
- isEditMode: PropTypes.bool,
164
- };
165
-
166
- ButtonForm.defaultProps = {
167
- initialData: null,
168
- isEditMode: false,
169
- };
170
-
171
- export default ButtonForm;
172
-