@capillarytech/creatives-library 8.0.345-alpha.15 → 8.0.345-alpha.16

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 (130) hide show
  1. package/constants/unified.js +0 -29
  2. package/package.json +1 -1
  3. package/services/tests/api.test.js +0 -13
  4. package/utils/commonUtils.js +1 -19
  5. package/v2Components/CapActionButton/constants.js +0 -7
  6. package/v2Components/CapActionButton/index.js +109 -167
  7. package/v2Components/CapActionButton/index.scss +6 -157
  8. package/v2Components/CapActionButton/messages.js +3 -19
  9. package/v2Components/CapActionButton/tests/index.test.js +17 -41
  10. package/v2Components/CapTagList/index.js +0 -10
  11. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -70
  12. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  13. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -207
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
  18. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  19. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -160
  20. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -341
  21. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
  22. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  23. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  24. package/v2Components/CommonTestAndPreview/index.js +186 -676
  25. package/v2Components/CommonTestAndPreview/messages.js +3 -49
  26. package/v2Components/CommonTestAndPreview/sagas.js +6 -15
  27. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
  28. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  29. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  30. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  31. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  32. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  33. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  34. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  35. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
  36. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
  37. package/v2Components/FormBuilder/index.js +10 -8
  38. package/v2Components/TemplatePreview/_templatePreview.scss +23 -33
  39. package/v2Components/TemplatePreview/index.js +28 -143
  40. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  41. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  42. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  43. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  44. package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
  45. package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
  46. package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
  47. package/v2Containers/CreativesContainer/constants.js +0 -9
  48. package/v2Containers/CreativesContainer/index.js +103 -300
  49. package/v2Containers/CreativesContainer/index.scss +1 -51
  50. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
  51. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  52. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  53. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
  54. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  55. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  56. package/v2Containers/Email/reducer.js +12 -3
  57. package/v2Containers/Email/sagas.js +9 -4
  58. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +4 -0
  59. package/v2Containers/Email/tests/reducer.test.js +47 -0
  60. package/v2Containers/Email/tests/sagas.test.js +146 -6
  61. package/v2Containers/Rcs/constants.js +8 -119
  62. package/v2Containers/Rcs/index.js +811 -2383
  63. package/v2Containers/Rcs/index.scss +6 -276
  64. package/v2Containers/Rcs/messages.js +3 -38
  65. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +70073 -98018
  66. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
  67. package/v2Containers/Rcs/tests/index.test.js +121 -152
  68. package/v2Containers/Rcs/tests/mockData.js +0 -38
  69. package/v2Containers/Rcs/tests/utils.test.js +30 -646
  70. package/v2Containers/Rcs/utils.js +11 -478
  71. package/v2Containers/Sms/Create/index.js +40 -100
  72. package/v2Containers/SmsTrai/Create/index.js +4 -9
  73. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  74. package/v2Containers/SmsTrai/Edit/index.js +130 -636
  75. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  76. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2296 -4249
  77. package/v2Containers/SmsWrapper/index.js +8 -37
  78. package/v2Containers/TagList/index.js +0 -6
  79. package/v2Containers/Templates/_templates.scss +2 -163
  80. package/v2Containers/Templates/actions.js +0 -11
  81. package/v2Containers/Templates/constants.js +0 -2
  82. package/v2Containers/Templates/index.js +54 -119
  83. package/v2Containers/Templates/sagas.js +12 -57
  84. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1079 -1043
  85. package/v2Containers/Templates/tests/sagas.test.js +123 -193
  86. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  87. package/v2Containers/TemplatesV2/index.js +23 -86
  88. package/v2Containers/Whatsapp/index.js +20 -3
  89. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  90. package/utils/rcsPayloadUtils.js +0 -92
  91. package/utils/templateVarUtils.js +0 -201
  92. package/utils/tests/templateVarUtils.test.js +0 -204
  93. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js.rej +0 -18
  94. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  95. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  96. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -87
  97. package/v2Components/SmsFallback/constants.js +0 -73
  98. package/v2Components/SmsFallback/index.js +0 -955
  99. package/v2Components/SmsFallback/index.scss +0 -265
  100. package/v2Components/SmsFallback/messages.js +0 -78
  101. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -118
  102. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  103. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  104. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  105. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -197
  106. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -277
  107. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  108. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  109. package/v2Components/TemplatePreview/constants.js +0 -2
  110. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  111. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  112. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  113. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
  114. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -67
  115. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  116. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  117. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  118. package/v2Containers/Rcs/index.js.rej +0 -1336
  119. package/v2Containers/Rcs/index.scss.rej +0 -74
  120. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
  121. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap.rej +0 -128
  122. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  123. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  124. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  125. package/v2Containers/SmsTrai/Edit/index.scss +0 -121
  126. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  127. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  128. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  129. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  130. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -8,7 +8,7 @@ import React from 'react';
8
8
  import { render, screen } from '@testing-library/react';
9
9
  import { IntlProvider, injectIntl } from 'react-intl';
10
10
  import RcsPreviewContent from '../../UnifiedPreview/RcsPreviewContent';
11
- import { ANDROID, IOS, MEDIA_TYPE_VIDEO } from '../../constants';
11
+ import { ANDROID, IOS } from '../../constants';
12
12
  import messages from '../../messages';
13
13
 
14
14
  // Mock constants
@@ -42,13 +42,6 @@ const TestWrapper = ({ children }) => (
42
42
  </IntlProvider>
43
43
  );
44
44
 
45
- const renderRcsPreview = (props) =>
46
- render(
47
- <TestWrapper>
48
- <ComponentToRender {...props} />
49
- </TestWrapper>,
50
- );
51
-
52
45
  describe('RcsPreviewContent', () => {
53
46
  const defaultProps = {
54
47
  content: {
@@ -67,10 +60,33 @@ describe('RcsPreviewContent', () => {
67
60
  });
68
61
 
69
62
  describe('Loading State', () => {
70
- it('should render loading state and spinner when isUpdating is true', () => {
71
- const props = { ...defaultProps, isUpdating: true };
72
- const { container } = renderRcsPreview(props);
63
+ it('should render loading state when isUpdating is true', () => {
64
+ const props = {
65
+ ...defaultProps,
66
+ isUpdating: true,
67
+ };
68
+
69
+ render(
70
+ <TestWrapper>
71
+ <ComponentToRender {...props} />
72
+ </TestWrapper>
73
+ );
74
+
73
75
  expect(screen.getByText('Updating preview with the latest changes')).toBeTruthy();
76
+ });
77
+
78
+ it('should show loading spinner', () => {
79
+ const props = {
80
+ ...defaultProps,
81
+ isUpdating: true,
82
+ };
83
+
84
+ const { container } = render(
85
+ <TestWrapper>
86
+ <ComponentToRender {...props} />
87
+ </TestWrapper>
88
+ );
89
+
74
90
  expect(container.querySelector('.ant-spin')).toBeTruthy();
75
91
  });
76
92
  });
@@ -82,16 +98,50 @@ describe('RcsPreviewContent', () => {
82
98
  error: 'Failed to load preview',
83
99
  };
84
100
 
85
- renderRcsPreview(props);
101
+ render(
102
+ <TestWrapper>
103
+ <ComponentToRender {...props} />
104
+ </TestWrapper>
105
+ );
86
106
 
87
107
  expect(screen.getAllByText('Failed to load preview')).toHaveLength(2);
88
108
  });
89
109
  });
90
110
 
91
111
  describe('Text Preview Content', () => {
92
- it('should render templateHeader and templateMessage (default text content)', () => {
93
- renderRcsPreview(defaultProps);
112
+ it('should render templateHeader as title', () => {
113
+ const props = {
114
+ ...defaultProps,
115
+ content: {
116
+ templateHeader: 'RCS Title',
117
+ templateMessage: 'RCS Description',
118
+ },
119
+ };
120
+
121
+ render(
122
+ <TestWrapper>
123
+ <ComponentToRender {...props} />
124
+ </TestWrapper>
125
+ );
126
+
94
127
  expect(screen.getByText('RCS Title')).toBeTruthy();
128
+ });
129
+
130
+ it('should render templateMessage as description', () => {
131
+ const props = {
132
+ ...defaultProps,
133
+ content: {
134
+ templateHeader: 'RCS Title',
135
+ templateMessage: 'RCS Description',
136
+ },
137
+ };
138
+
139
+ render(
140
+ <TestWrapper>
141
+ <ComponentToRender {...props} />
142
+ </TestWrapper>
143
+ );
144
+
95
145
  expect(screen.getByText('RCS Description')).toBeTruthy();
96
146
  });
97
147
 
@@ -104,7 +154,11 @@ describe('RcsPreviewContent', () => {
104
154
  },
105
155
  };
106
156
 
107
- renderRcsPreview(props);
157
+ render(
158
+ <TestWrapper>
159
+ <ComponentToRender {...props} />
160
+ </TestWrapper>
161
+ );
108
162
 
109
163
  expect(screen.getByText('Fallback Title')).toBeTruthy();
110
164
  });
@@ -118,13 +172,30 @@ describe('RcsPreviewContent', () => {
118
172
  },
119
173
  };
120
174
 
121
- renderRcsPreview(props);
175
+ render(
176
+ <TestWrapper>
177
+ <ComponentToRender {...props} />
178
+ </TestWrapper>
179
+ );
122
180
 
123
181
  expect(screen.getByText('Fallback Description')).toBeTruthy();
124
182
  });
125
183
 
126
184
  it('should render divider after title', () => {
127
- const { container } = renderRcsPreview(defaultProps);
185
+ const props = {
186
+ ...defaultProps,
187
+ content: {
188
+ templateHeader: 'Title',
189
+ templateMessage: 'Description',
190
+ },
191
+ };
192
+
193
+ const { container } = render(
194
+ <TestWrapper>
195
+ <ComponentToRender {...props} />
196
+ </TestWrapper>
197
+ );
198
+
128
199
  expect(container.querySelector('.whatsapp-divider')).toBeTruthy();
129
200
  });
130
201
 
@@ -136,7 +207,11 @@ describe('RcsPreviewContent', () => {
136
207
  },
137
208
  };
138
209
 
139
- renderRcsPreview(props);
210
+ render(
211
+ <TestWrapper>
212
+ <ComponentToRender {...props} />
213
+ </TestWrapper>
214
+ );
140
215
 
141
216
  expect(screen.queryByText(/Title/)).toBeFalsy();
142
217
  });
@@ -151,7 +226,11 @@ describe('RcsPreviewContent', () => {
151
226
  },
152
227
  };
153
228
 
154
- const { container } = renderRcsPreview(props);
229
+ const { container } = render(
230
+ <TestWrapper>
231
+ <ComponentToRender {...props} />
232
+ </TestWrapper>
233
+ );
155
234
 
156
235
  const image = container.querySelector('.rcs-image');
157
236
  expect(image).toBeTruthy();
@@ -167,7 +246,11 @@ describe('RcsPreviewContent', () => {
167
246
  },
168
247
  };
169
248
 
170
- const { container } = renderRcsPreview(props);
249
+ const { container } = render(
250
+ <TestWrapper>
251
+ <ComponentToRender {...props} />
252
+ </TestWrapper>
253
+ );
171
254
 
172
255
  expect(container.querySelector('.video-preview')).toBeTruthy();
173
256
  expect(container.querySelector('.video-icon')).toBeTruthy();
@@ -181,7 +264,11 @@ describe('RcsPreviewContent', () => {
181
264
  },
182
265
  };
183
266
 
184
- const { container } = renderRcsPreview(props);
267
+ const { container } = render(
268
+ <TestWrapper>
269
+ <ComponentToRender {...props} />
270
+ </TestWrapper>
271
+ );
185
272
 
186
273
  const image = container.querySelector('.rcs-image');
187
274
  expect(image.getAttribute('src')).toBe('https://video.url');
@@ -197,320 +284,165 @@ describe('RcsPreviewContent', () => {
197
284
  },
198
285
  };
199
286
 
200
- renderRcsPreview(props);
287
+ render(
288
+ <TestWrapper>
289
+ <ComponentToRender {...props} />
290
+ </TestWrapper>
291
+ );
201
292
 
202
293
  expect(screen.getByText('Title')).toBeTruthy();
203
294
  expect(screen.getByText('Description')).toBeTruthy();
204
295
  });
205
296
  });
206
297
 
207
- describe('Carousel Preview Content', () => {
208
- it('should render carousel cards when carouselData is present', () => {
298
+ describe('RCS Suggestions', () => {
299
+ it('should render QUICK_REPLY suggestion', () => {
209
300
  const props = {
210
301
  ...defaultProps,
211
302
  content: {
212
- carouselData: [
213
- {
214
- mediaType: 'image',
215
- imageSrc: 'https://image.1/url',
216
- title: 'Card 1',
217
- bodyText: 'Body 1',
218
- suggestions: [{ type: 'CTA', text: 'Visit' }],
219
- },
220
- {
221
- mediaType: 'video',
222
- videoPreviewImg: 'https://thumb.2/url',
223
- title: 'Card 2',
224
- bodyText: 'Body 2',
225
- suggestions: [{ type: 'QUICK_REPLY', text: 'Yes' }],
226
- },
303
+ templateHeader: 'Title',
304
+ templateMessage: 'Description',
305
+ suggestions: [
306
+ { type: 'QUICK_REPLY', text: 'Yes' },
227
307
  ],
228
308
  },
229
309
  };
230
310
 
231
- const { container } = renderRcsPreview(props);
232
-
233
- expect(container.querySelectorAll('.message-pop-carousel').length).toBe(2);
234
- expect(container.querySelector('.scroll-container')).toBeTruthy();
235
- expect(screen.getByText('Card 1')).toBeTruthy();
236
- expect(screen.getByText('Card 2')).toBeTruthy();
237
- expect(container.querySelector('.video-preview')).toBeTruthy();
238
- expect(container.querySelector('.video-icon')).toBeTruthy();
239
- expect(screen.getByText('Visit')).toBeTruthy();
311
+ const { container } = render(
312
+ <TestWrapper>
313
+ <ComponentToRender {...props} />
314
+ </TestWrapper>
315
+ );
240
316
  expect(screen.getByText('Yes')).toBeTruthy();
241
- expect(container.querySelectorAll('.rcs-carousel-cta-stack').length).toBe(2);
242
- expect(container.querySelector('.rcs-cta-preview--carousel-bar')).toBeTruthy();
317
+ expect(container.querySelector('.cap-icon-v2-small-link')).toBeTruthy();
243
318
  });
244
319
 
245
- it('should apply carouselPreviewDimensions as aspect-ratio on image and video media wraps', () => {
320
+ it('should render CTA suggestion', () => {
246
321
  const props = {
247
322
  ...defaultProps,
248
323
  content: {
249
- carouselPreviewDimensions: {
250
- imageWidth: 1160,
251
- imageHeight: 720,
252
- videoThumbWidth: 718,
253
- videoThumbHeight: 448,
254
- },
255
- carouselData: [
256
- {
257
- mediaType: 'image',
258
- imageSrc: 'https://image.1/url',
259
- title: 'Card 1',
260
- bodyText: 'Body 1',
261
- suggestions: [],
262
- },
263
- {
264
- mediaType: 'video',
265
- videoPreviewImg: 'https://thumb.2/url',
266
- title: 'Card 2',
267
- bodyText: 'Body 2',
268
- suggestions: [],
269
- },
324
+ templateHeader: 'Title',
325
+ templateMessage: 'Description',
326
+ suggestions: [
327
+ { type: 'CTA', text: 'Visit Website' },
270
328
  ],
271
329
  },
272
330
  };
273
- const { container } = renderRcsPreview(props);
274
- const wraps = container.querySelectorAll('.whatsapp-image.rcs-carousel-media-wrap');
275
- expect(wraps.length).toBe(2);
276
- expect(wraps[0].style.aspectRatio).toBe('1160 / 720');
277
- expect(wraps[1].style.aspectRatio).toBe('718 / 448');
278
- });
279
331
 
280
- it('should use text preview when carouselData is not an array', () => {
281
- const props = {
282
- ...defaultProps,
283
- content: {
284
- carouselData: { invalid: true },
285
- templateHeader: 'Fallback title',
286
- templateMessage: 'Fallback body',
287
- },
288
- };
289
- const { container } = renderRcsPreview(props);
290
- expect(container.querySelector('.scroll-container')).toBeFalsy();
291
- expect(screen.getByText('Fallback title')).toBeTruthy();
292
- expect(screen.getByText('Fallback body')).toBeTruthy();
293
- });
332
+ const { container } = render(
333
+ <TestWrapper>
334
+ <ComponentToRender {...props} />
335
+ </TestWrapper>
336
+ );
294
337
 
295
- it('should use text preview when carouselData is an empty array', () => {
296
- const props = {
297
- ...defaultProps,
298
- content: {
299
- carouselData: [],
300
- templateHeader: 'No cards',
301
- templateMessage: 'Use text',
302
- },
303
- };
304
- const { container } = renderRcsPreview(props);
305
- expect(container.querySelector('.scroll-container')).toBeFalsy();
306
- expect(screen.getByText('No cards')).toBeTruthy();
338
+ expect(screen.getByText('Visit Website')).toBeTruthy();
307
339
  });
308
340
 
309
- it('should render image branch when mediaType is undefined (not video)', () => {
341
+ it('should render PHONE_NUMBER suggestion', () => {
310
342
  const props = {
311
343
  ...defaultProps,
312
344
  content: {
313
- carouselData: [
314
- {
315
- title: 'T',
316
- bodyText: 'B',
317
- imageSrc: '',
318
- suggestions: [],
319
- },
345
+ templateHeader: 'Title',
346
+ templateMessage: 'Description',
347
+ suggestions: [
348
+ { type: 'PHONE_NUMBER', text: 'Call Us' },
320
349
  ],
321
350
  },
322
351
  };
323
- const { container } = renderRcsPreview(props);
324
- expect(container.querySelector('.video-preview')).toBeFalsy();
325
- const img = container.querySelector('.rcs-carousel-img');
326
- expect(img).toBeTruthy();
327
- expect(img.getAttribute('src')).toBeTruthy();
328
- });
329
352
 
330
- it('should treat MEDIA_TYPE_VIDEO as video regardless of case', () => {
331
- const props = {
332
- ...defaultProps,
333
- content: {
334
- carouselData: [
335
- {
336
- mediaType: MEDIA_TYPE_VIDEO,
337
- videoPreviewImg: 'https://thumb/video',
338
- title: 'Vid',
339
- bodyText: 'Clip',
340
- suggestions: [],
341
- },
342
- ],
343
- },
344
- };
345
- const { container } = renderRcsPreview(props);
346
- expect(container.querySelector('.video-preview')).toBeTruthy();
347
- expect(container.querySelector('.whatsapp-image.rcs-carousel-media-wrap .rcs-carousel-img')?.getAttribute('src')).toBe(
348
- 'https://thumb/video',
353
+ const { container } = render(
354
+ <TestWrapper>
355
+ <ComponentToRender {...props} />
356
+ </TestWrapper>
349
357
  );
350
- });
351
358
 
352
- it('should use empty video placeholder when video card has no videoPreviewImg', () => {
353
- const props = {
354
- ...defaultProps,
355
- content: {
356
- carouselData: [
357
- {
358
- mediaType: 'video',
359
- title: 'V',
360
- bodyText: 'No thumb',
361
- suggestions: [],
362
- },
363
- ],
364
- },
365
- };
366
- const { container } = renderRcsPreview(props);
367
- const vidImg = container.querySelector('.video-preview .rcs-carousel-img');
368
- expect(vidImg).toBeTruthy();
369
- expect(vidImg.getAttribute('src')).toBeTruthy();
359
+ expect(screen.getByText('Call Us')).toBeTruthy();
370
360
  });
371
361
 
372
- it('should not render per-card suggestions block when suggestions is null or non-array', () => {
362
+ it('should render multiple suggestions', () => {
373
363
  const props = {
374
364
  ...defaultProps,
375
365
  content: {
376
- carouselData: [
377
- {
378
- mediaType: 'image',
379
- imageSrc: 'https://x.png',
380
- title: 'A',
381
- bodyText: 'B',
382
- suggestions: null,
383
- },
384
- {
385
- mediaType: 'image',
386
- imageSrc: 'https://y.png',
387
- title: 'C',
388
- bodyText: 'D',
389
- suggestions: 'not-an-array',
390
- },
366
+ templateHeader: 'Title',
367
+ templateMessage: 'Description',
368
+ suggestions: [
369
+ { type: 'QUICK_REPLY', text: 'Yes' },
370
+ { type: 'CTA', text: 'Visit' },
371
+ { type: 'PHONE_NUMBER', text: 'Call' },
391
372
  ],
392
373
  },
393
374
  };
394
- const { container } = renderRcsPreview(props);
395
- expect(container.querySelectorAll('.message-pop-carousel').length).toBe(2);
396
- const ctas = container.querySelectorAll('.rcs-cta-preview');
397
- expect(ctas.length).toBe(0);
375
+
376
+ render(
377
+ <TestWrapper>
378
+ <ComponentToRender {...props} />
379
+ </TestWrapper>
380
+ );
381
+
382
+ expect(screen.getByText('Yes')).toBeTruthy();
383
+ expect(screen.getByText('Visit')).toBeTruthy();
384
+ expect(screen.getByText('Call')).toBeTruthy();
398
385
  });
399
386
 
400
- it('should render title-only card with body placeholder', () => {
387
+ it('should render dividers between suggestions', () => {
401
388
  const props = {
402
389
  ...defaultProps,
403
390
  content: {
404
- carouselData: [
405
- {
406
- mediaType: 'image',
407
- imageSrc: 'https://only-title.png',
408
- title: 'OnlyTitle',
409
- suggestions: [],
410
- },
391
+ templateHeader: 'Title',
392
+ templateMessage: 'Description',
393
+ suggestions: [
394
+ { type: 'QUICK_REPLY', text: 'Yes' },
395
+ { type: 'CTA', text: 'Visit' },
411
396
  ],
412
397
  },
413
398
  };
414
- renderRcsPreview(props);
415
- expect(screen.getByText('OnlyTitle')).toBeTruthy();
416
- expect(screen.getByText('Card description')).toBeTruthy();
417
- expect(document.querySelector('.carousel-message.rcs-carousel-field-placeholder')).toBeTruthy();
399
+
400
+ const { container } = render(
401
+ <TestWrapper>
402
+ <ComponentToRender {...props} />
403
+ </TestWrapper>
404
+ );
405
+
406
+ const dividers = container.querySelectorAll('.whatsapp-divider');
407
+ expect(dividers.length).toBeGreaterThan(0);
418
408
  });
419
409
 
420
- it('should render body-only card with title placeholder', () => {
410
+ it('should not render suggestions when array is empty', () => {
421
411
  const props = {
422
412
  ...defaultProps,
423
413
  content: {
424
- carouselData: [
425
- {
426
- mediaType: 'image',
427
- imageSrc: 'https://only-body.png',
428
- bodyText: 'OnlyBody',
429
- suggestions: [],
430
- },
431
- ],
414
+ templateHeader: 'Title',
415
+ templateMessage: 'Description',
416
+ suggestions: [],
432
417
  },
433
418
  };
434
- renderRcsPreview(props);
435
- expect(screen.getByText('OnlyBody')).toBeTruthy();
436
- expect(screen.getByText('Card title')).toBeTruthy();
437
- expect(document.querySelector('.carousel-title.rcs-carousel-field-placeholder')).toBeTruthy();
419
+
420
+ render(
421
+ <TestWrapper>
422
+ <ComponentToRender {...props} />
423
+ </TestWrapper>
424
+ );
425
+
426
+ expect(screen.getByText('Title')).toBeTruthy();
438
427
  });
439
428
 
440
- it('should show title and body placeholders when card has no title or body', () => {
429
+ it('should handle suggestion without text', () => {
441
430
  const props = {
442
431
  ...defaultProps,
443
432
  content: {
444
- carouselData: [
445
- {
446
- mediaType: 'image',
447
- imageSrc: 'https://silent.png',
448
- suggestions: [],
449
- },
433
+ templateHeader: 'Title',
434
+ templateMessage: 'Description',
435
+ suggestions: [
436
+ { type: 'QUICK_REPLY', text: null },
450
437
  ],
451
438
  },
452
439
  };
453
- const { container } = renderRcsPreview(props);
454
- expect(container.querySelector('.carousel-content')).toBeTruthy();
455
- expect(screen.getByText('Card title')).toBeTruthy();
456
- expect(screen.getByText('Card description')).toBeTruthy();
457
- expect(container.querySelectorAll('.rcs-carousel-field-placeholder').length).toBe(2);
458
- });
459
- });
460
-
461
- describe('RCS Suggestions', () => {
462
- const withTextBodySuggestions = (suggestions) => ({
463
- ...defaultProps,
464
- content: { templateHeader: 'Title', templateMessage: 'Description', suggestions },
465
- });
466
-
467
- it.each([
468
- ['QUICK_REPLY', 'Yes', true],
469
- ['CTA', 'Visit Website', false],
470
- ['PHONE_NUMBER', 'Call Us', false],
471
- ])('should render %s suggestion', (type, text, expectQuickReplyIcon) => {
472
- const props = withTextBodySuggestions([{ type, text }]);
473
- const { container } = renderRcsPreview(props);
474
- expect(screen.getByText(text)).toBeTruthy();
475
- if (expectQuickReplyIcon) {
476
- expect(container.querySelector('.cap-icon-v2-small-link')).toBeTruthy();
477
- }
478
- });
479
-
480
- it('should render multiple suggestions', () => {
481
- const props = withTextBodySuggestions([
482
- { type: 'QUICK_REPLY', text: 'Yes' },
483
- { type: 'CTA', text: 'Visit' },
484
- { type: 'PHONE_NUMBER', text: 'Call' },
485
- ]);
486
-
487
- renderRcsPreview(props);
488
-
489
- expect(screen.getByText('Yes')).toBeTruthy();
490
- expect(screen.getByText('Visit')).toBeTruthy();
491
- expect(screen.getByText('Call')).toBeTruthy();
492
- });
493
440
 
494
- it('should render dividers between suggestions', () => {
495
- const props = withTextBodySuggestions([
496
- { type: 'QUICK_REPLY', text: 'Yes' },
497
- { type: 'CTA', text: 'Visit' },
498
- ]);
499
-
500
- const { container } = renderRcsPreview(props);
501
-
502
- const dividers = container.querySelectorAll('.whatsapp-divider');
503
- expect(dividers.length).toBeGreaterThan(0);
504
- });
505
-
506
- it('should not render suggestions when array is empty', () => {
507
- renderRcsPreview(withTextBodySuggestions([]));
508
-
509
- expect(screen.getByText('Title')).toBeTruthy();
510
- });
511
-
512
- it('should handle suggestion without text', () => {
513
- renderRcsPreview(withTextBodySuggestions([{ type: 'QUICK_REPLY', text: null }]));
441
+ render(
442
+ <TestWrapper>
443
+ <ComponentToRender {...props} />
444
+ </TestWrapper>
445
+ );
514
446
 
515
447
  // Should not crash
516
448
  expect(screen.getByText('Title')).toBeTruthy();
@@ -518,13 +450,32 @@ describe('RcsPreviewContent', () => {
518
450
  });
519
451
 
520
452
  describe('Device Handling', () => {
453
+ it('should use Android device image for ANDROID device', () => {
454
+ const props = {
455
+ ...defaultProps,
456
+ device: ANDROID,
457
+ };
458
+
459
+ const { container } = render(
460
+ <TestWrapper>
461
+ <ComponentToRender {...props} />
462
+ </TestWrapper>
463
+ );
464
+
465
+ expect(container.querySelector('.sms-device-image')).toBeTruthy();
466
+ });
467
+
521
468
  it('should use iOS device image for IOS device', () => {
522
469
  const props = {
523
470
  ...defaultProps,
524
471
  device: IOS,
525
472
  };
526
473
 
527
- const { container } = renderRcsPreview(props);
474
+ const { container } = render(
475
+ <TestWrapper>
476
+ <ComponentToRender {...props} />
477
+ </TestWrapper>
478
+ );
528
479
 
529
480
  expect(container.querySelector('.sms-device-image')).toBeTruthy();
530
481
  });
@@ -537,7 +488,11 @@ describe('RcsPreviewContent', () => {
537
488
  senderId: 'MY_SENDER_ID',
538
489
  };
539
490
 
540
- renderRcsPreview(props);
491
+ render(
492
+ <TestWrapper>
493
+ <ComponentToRender {...props} />
494
+ </TestWrapper>
495
+ );
541
496
 
542
497
  expect(screen.getByText('MY_SENDER_ID')).toBeTruthy();
543
498
  });
@@ -548,7 +503,11 @@ describe('RcsPreviewContent', () => {
548
503
  senderId: null,
549
504
  };
550
505
 
551
- renderRcsPreview(props);
506
+ render(
507
+ <TestWrapper>
508
+ <ComponentToRender {...props} />
509
+ </TestWrapper>
510
+ );
552
511
 
553
512
  expect(screen.getByText('Sender ID')).toBeTruthy();
554
513
  });
@@ -556,7 +515,11 @@ describe('RcsPreviewContent', () => {
556
515
 
557
516
  describe('Timestamp', () => {
558
517
  it('should display timestamp', () => {
559
- renderRcsPreview(defaultProps);
518
+ render(
519
+ <TestWrapper>
520
+ <ComponentToRender {...defaultProps} />
521
+ </TestWrapper>
522
+ );
560
523
 
561
524
  // Timestamp format: "H:MM AM/PM"
562
525
  const timestamp = screen.getByText(/\d{1,2}:\d{2} (AM|PM)/);
@@ -574,17 +537,44 @@ describe('RcsPreviewContent', () => {
574
537
  },
575
538
  };
576
539
 
577
- const { container } = renderRcsPreview(props);
540
+ const { container } = render(
541
+ <TestWrapper>
542
+ <ComponentToRender {...props} />
543
+ </TestWrapper>
544
+ );
578
545
 
579
546
  // Should prioritize video when both are present
580
547
  expect(container.querySelector('.video-preview')).toBeTruthy();
581
548
  });
582
549
 
583
- it.each([
584
- ['empty object', {}],
585
- ['null', null],
586
- ])('should render structure when content is %s', (_, contentValue) => {
587
- renderRcsPreview({ ...defaultProps, content: contentValue });
550
+ it('should handle empty content object', () => {
551
+ const props = {
552
+ ...defaultProps,
553
+ content: {},
554
+ };
555
+
556
+ render(
557
+ <TestWrapper>
558
+ <ComponentToRender {...props} />
559
+ </TestWrapper>
560
+ );
561
+
562
+ // Should render structure
563
+ expect(screen.getByText('Today')).toBeTruthy();
564
+ });
565
+
566
+ it('should handle null content', () => {
567
+ const props = {
568
+ ...defaultProps,
569
+ content: null,
570
+ };
571
+
572
+ render(
573
+ <TestWrapper>
574
+ <ComponentToRender {...props} />
575
+ </TestWrapper>
576
+ );
577
+
588
578
  expect(screen.getByText('Today')).toBeTruthy();
589
579
  });
590
580
 
@@ -600,7 +590,11 @@ describe('RcsPreviewContent', () => {
600
590
  },
601
591
  };
602
592
 
603
- renderRcsPreview(props);
593
+ render(
594
+ <TestWrapper>
595
+ <ComponentToRender {...props} />
596
+ </TestWrapper>
597
+ );
604
598
 
605
599
  // Should not crash, but may not render the suggestion
606
600
  expect(screen.getByText('Title')).toBeTruthy();
@@ -613,7 +607,11 @@ describe('RcsPreviewContent', () => {
613
607
  formatMessage: jest.fn((msg) => msg.defaultMessage || msg.id),
614
608
  };
615
609
 
616
- renderRcsPreview(minimalProps);
610
+ render(
611
+ <TestWrapper>
612
+ <ComponentToRender {...minimalProps} />
613
+ </TestWrapper>
614
+ );
617
615
 
618
616
  expect(screen.getByText('Today')).toBeTruthy();
619
617
  });
@@ -623,7 +621,11 @@ describe('RcsPreviewContent', () => {
623
621
  it('should accept all required props without warnings', () => {
624
622
  const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
625
623
 
626
- renderRcsPreview(defaultProps);
624
+ render(
625
+ <TestWrapper>
626
+ <ComponentToRender {...defaultProps} />
627
+ </TestWrapper>
628
+ );
627
629
 
628
630
  expect(consoleSpy).not.toHaveBeenCalled();
629
631
  consoleSpy.mockRestore();