@capillarytech/creatives-library 9.0.15-alpha.3 → 9.0.16-beta.0

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 (146) hide show
  1. package/AppRoot.js +80 -0
  2. package/app.js +5 -3
  3. package/constants/unified.js +0 -29
  4. package/entry.js +67 -1
  5. package/global-styles.js +1 -1
  6. package/mfe-exposed-components.js +2 -4
  7. package/package.json +2 -2
  8. package/services/api.js +1 -1
  9. package/services/tests/api.test.js +20 -35
  10. package/styles/containers/layout/_layoutPage.scss +8 -6
  11. package/utils/commonUtils.js +1 -19
  12. package/utils/getDataLayer.js +15 -0
  13. package/utils/gtmTrackers/gtmEvents/creativeDetails.js +2 -1
  14. package/utils/mfeDetect.js +1 -0
  15. package/v2Components/CapActionButton/constants.js +1 -8
  16. package/v2Components/CapActionButton/index.js +144 -202
  17. package/v2Components/CapActionButton/index.scss +14 -232
  18. package/v2Components/CapActionButton/messages.js +3 -19
  19. package/v2Components/CapActionButton/tests/index.test.js +18 -42
  20. package/v2Components/CapImageUpload/index.js +2 -2
  21. package/v2Components/CapTagList/index.js +0 -10
  22. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +48 -70
  23. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  24. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -214
  25. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  26. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +9 -83
  27. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  28. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -60
  29. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  30. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +22 -202
  31. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +80 -381
  32. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +8 -155
  33. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  34. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  35. package/v2Components/CommonTestAndPreview/index.js +222 -761
  36. package/v2Components/CommonTestAndPreview/messages.js +3 -45
  37. package/v2Components/CommonTestAndPreview/sagas.js +6 -25
  38. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -1
  39. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +267 -284
  40. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  41. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  42. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  43. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  44. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  45. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  46. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  47. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -133
  48. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +24 -31
  49. package/v2Components/NavigationBar/index.js +9 -7
  50. package/v2Components/NavigationBar/mfeModuleHeader.config.js +16 -0
  51. package/v2Components/Pagination/_pagination.scss +2 -0
  52. package/v2Components/TemplatePreview/_templatePreview.scss +25 -45
  53. package/v2Components/TemplatePreview/index.js +32 -147
  54. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  55. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  56. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  57. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  58. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  59. package/v2Containers/Cap/constants.js +1 -0
  60. package/v2Containers/Cap/index.js +47 -21
  61. package/v2Containers/Cap/sagas.js +19 -0
  62. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +1 -4
  63. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +0 -4
  64. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  65. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -37
  66. package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -14
  67. package/v2Containers/CreativesContainer/SlideBoxHeader.js +5 -36
  68. package/v2Containers/CreativesContainer/constants.js +0 -11
  69. package/v2Containers/CreativesContainer/index.js +104 -323
  70. package/v2Containers/CreativesContainer/index.scss +1 -83
  71. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -79
  72. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  73. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  74. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +90 -333
  75. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  76. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  77. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  78. package/v2Containers/Rcs/constants.js +11 -131
  79. package/v2Containers/Rcs/index.js +829 -2682
  80. package/v2Containers/Rcs/index.scss +8 -443
  81. package/v2Containers/Rcs/messages.js +6 -45
  82. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +39409 -74176
  83. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +74 -10
  84. package/v2Containers/Rcs/tests/index.test.js +40 -151
  85. package/v2Containers/Rcs/tests/mockData.js +0 -38
  86. package/v2Containers/Rcs/tests/utils.test.js +30 -643
  87. package/v2Containers/Rcs/utils.js +12 -466
  88. package/v2Containers/Sms/Create/index.js +48 -115
  89. package/v2Containers/SmsTrai/Create/index.js +4 -9
  90. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  91. package/v2Containers/SmsTrai/Edit/index.js +169 -678
  92. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  93. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2854 -5455
  94. package/v2Containers/SmsWrapper/index.js +8 -37
  95. package/v2Containers/TagList/index.js +0 -6
  96. package/v2Containers/Templates/_templates.scss +11 -196
  97. package/v2Containers/Templates/actions.js +0 -11
  98. package/v2Containers/Templates/constants.js +0 -2
  99. package/v2Containers/Templates/index.js +60 -131
  100. package/v2Containers/Templates/sagas.js +13 -57
  101. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1015 -1060
  102. package/v2Containers/Templates/tests/sagas.test.js +16 -199
  103. package/v2Containers/TemplatesV2/TemplatesV2.style.js +10 -75
  104. package/v2Containers/TemplatesV2/index.js +43 -86
  105. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  106. package/v2Containers/Whatsapp/index.js +25 -4
  107. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  108. package/utils/rcsPayloadUtils.js +0 -92
  109. package/utils/templateVarUtils.js +0 -201
  110. package/utils/tests/rcsPayloadUtils.test.js +0 -226
  111. package/utils/tests/templateVarUtils.test.js +0 -204
  112. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  113. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  114. package/v2Components/CommonTestAndPreview/utils.js +0 -84
  115. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
  116. package/v2Components/SmsFallback/constants.js +0 -94
  117. package/v2Components/SmsFallback/index.js +0 -958
  118. package/v2Components/SmsFallback/index.scss +0 -266
  119. package/v2Components/SmsFallback/messages.js +0 -78
  120. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -120
  121. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  122. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  123. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  124. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -208
  125. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
  126. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  127. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  128. package/v2Components/TemplatePreview/constants.js +0 -2
  129. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  130. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  131. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  132. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -17
  133. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
  134. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  135. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  136. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  137. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -227
  138. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  139. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  140. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  141. package/v2Containers/SmsTrai/Edit/index.scss +0 -126
  142. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  143. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  144. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  145. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  146. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -1,304 +0,0 @@
1
- import React from 'react';
2
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3
- import '@testing-library/jest-dom';
4
- import { SmsFallback } from '../index';
5
- import * as Api from '../../../services/api';
6
- import { useLocalTemplateList } from '../useLocalTemplateList';
7
-
8
- jest.mock('react-dom', () => ({
9
- ...jest.requireActual('react-dom'),
10
- createPortal: (node) => node,
11
- }));
12
-
13
- jest.mock('../../../services/api', () => ({
14
- getTemplateDetails: jest.fn(),
15
- }));
16
-
17
- jest.mock('../useLocalTemplateList', () => ({
18
- useLocalTemplateList: jest.fn(),
19
- }));
20
-
21
- jest.mock('../../../v2Containers/Templates/actions', () => ({
22
- getLocalSmsTemplates: jest.fn(() => ({ type: 'LOCAL_SMS' })),
23
- }));
24
-
25
- const mockSmsFallbackLocalSelector = jest.fn((props) => (
26
- <div data-testid="sms-fallback-selector-mock" data-hidden={String(props.hidden)} />
27
- ));
28
- jest.mock('../SmsFallbackLocalSelector', () => ({
29
- __esModule: true,
30
- default: (props) => mockSmsFallbackLocalSelector(props),
31
- }));
32
-
33
- const mockSmsTraiEdit = jest.fn(() => <div data-testid="sms-trai-edit-mock" />);
34
- jest.mock('../../../v2Containers/SmsTrai/Edit', () => ({
35
- __esModule: true,
36
- default: (props) => mockSmsTraiEdit(props),
37
- }));
38
-
39
- const mockSmsWrapper = jest.fn(() => <div data-testid="sms-wrapper-mock" />);
40
- jest.mock('../../../v2Containers/SmsWrapper', () => ({
41
- __esModule: true,
42
- default: (props) => mockSmsWrapper(props),
43
- }));
44
-
45
- jest.mock('../../../v2Containers/Templates/TemplatesActionBar', () => ({
46
- __esModule: true,
47
- default: ({ children }) => <div data-testid="templates-action-bar">{children}</div>,
48
- }));
49
-
50
- jest.mock('@capillarytech/cap-ui-library/CapRow', () => (props) => <div {...props} />);
51
- jest.mock('@capillarytech/cap-ui-library/CapHeader', () => (props) => (
52
- <div className={props.className}>
53
- {props.prefix || null}
54
- <div>{props.title}</div>
55
- <div>{props.description}</div>
56
- </div>
57
- ));
58
- jest.mock('@capillarytech/cap-ui-library/CapHeading', () => (props) => <div>{props.children}</div>);
59
- jest.mock('@capillarytech/cap-ui-library/CapButton', () => (props) => (
60
- <button type="button" {...props}>
61
- {props.children}
62
- </button>
63
- ));
64
- jest.mock('@capillarytech/cap-ui-library/CapIcon', () => (props) => <span {...props} />);
65
- jest.mock('@capillarytech/cap-ui-library/CapDropdown', () => (props) => (
66
- <div>
67
- {props.children}
68
- {props.overlay}
69
- </div>
70
- ));
71
- jest.mock('@capillarytech/cap-ui-library/CapMenu', () => {
72
- const Menu = ({ children }) => <div>{children}</div>;
73
- Menu.Item = ({ children, onClick }) => (
74
- <button type="button" onClick={onClick}>
75
- {children}
76
- </button>
77
- );
78
- return Menu;
79
- });
80
- jest.mock('@capillarytech/cap-ui-library/CapCustomCard', () => ({
81
- CapCustomCardList: ({ cardList }) => (
82
- <div data-testid="custom-card">
83
- <div>{cardList?.[0]?.title}</div>
84
- <div>{cardList?.[0]?.content}</div>
85
- <div>{cardList?.[0]?.extra}</div>
86
- </div>
87
- ),
88
- }));
89
- jest.mock('@capillarytech/cap-ui-library/CapSlideBox', () => (props) => (
90
- <div data-testid="cap-slidebox">
91
- {props.header}
92
- {props.content}
93
- </div>
94
- ));
95
- jest.mock('@capillarytech/cap-ui-library', () => ({
96
- CapLabel: ({ children }) => <span>{children}</span>,
97
- CapIcons: {
98
- BackIcon: (props) => <span data-testid="cap-icons-back" {...props} />,
99
- },
100
- CapRadio: {
101
- CapRadioGroup: ({ children }) => <div>{children}</div>,
102
- Button: ({ children, value }) => <button type="button" data-value={value}>{children}</button>,
103
- },
104
- }));
105
-
106
- const intl = { formatMessage: (m) => m.defaultMessage || m.id || '' };
107
-
108
- /** Last jest mock invocation (Node <16 has no Array.prototype.at on mock.calls). */
109
- const lastMockCall = (mockFn) => {
110
- const { calls } = mockFn.mock;
111
- return calls[calls.length - 1];
112
- };
113
-
114
- const buildList = () => ({
115
- templates: [],
116
- totalCount: 0,
117
- loading: false,
118
- page: 1,
119
- search: '',
120
- setSearch: jest.fn(),
121
- loadMore: jest.fn(),
122
- reset: jest.fn(),
123
- canLoadMore: false,
124
- });
125
-
126
- const renderComp = (extraProps = {}) => {
127
- const props = {
128
- dispatch: jest.fn(),
129
- value: null,
130
- onChange: jest.fn(),
131
- smsRegister: 'DLT',
132
- selectedOfferDetails: {},
133
- channelsToHide: ['email'],
134
- sectionTitle: null,
135
- intl,
136
- showAsCard: true,
137
- disableSelectTemplate: false,
138
- eventContextTags: [],
139
- isFullMode: false,
140
- onRcsFallbackEditorStateChange: jest.fn(),
141
- isRcsEditFlow: false,
142
- ...extraProps,
143
- };
144
- return { ...render(<SmsFallback {...props} />), props };
145
- };
146
-
147
- describe('SmsFallback handlers', () => {
148
- beforeEach(() => {
149
- jest.clearAllMocks();
150
- useLocalTemplateList.mockReturnValue(buildList());
151
- Api.getTemplateDetails.mockResolvedValue({ response: {} });
152
- });
153
-
154
- it('opens selector and forwards embedded SMS save payload', async () => {
155
- const { props } = renderComp();
156
- fireEvent.click(screen.getByRole('button'));
157
-
158
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
159
- selectorProps.getCreativesData({
160
- channel: 'SMS',
161
- messageBody: 'Body',
162
- templateConfigs: { templateName: 'N', templateId: 9, template: 'Body' },
163
- });
164
-
165
- await waitFor(() => {
166
- expect(props.onChange).toHaveBeenCalled();
167
- });
168
- });
169
-
170
- it('ignores embedded non-SMS payload in getCreativesData', () => {
171
- const { props } = renderComp();
172
- fireEvent.click(screen.getByRole('button'));
173
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
174
- selectorProps.getCreativesData({ channel: 'RCS' });
175
- expect(props.onChange).not.toHaveBeenCalled();
176
- });
177
-
178
- it('selects template without id and opens edit with pending data', async () => {
179
- renderComp();
180
- fireEvent.click(screen.getByRole('button'));
181
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
182
- selectorProps.onSelectTemplate({
183
- name: 'No id template',
184
- versions: { base: { 'sms-editor': 'raw-content' } },
185
- });
186
-
187
- await waitFor(() => {
188
- expect(mockSmsTraiEdit).toHaveBeenCalled();
189
- });
190
- });
191
-
192
- it('fetches template details for selected template id and opens edit', async () => {
193
- renderComp();
194
- fireEvent.click(screen.getByRole('button'));
195
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
196
- await selectorProps.onSelectTemplate({
197
- _id: 'temp-1',
198
- name: 'Server template',
199
- });
200
-
201
- expect(Api.getTemplateDetails).toHaveBeenCalledWith({ id: 'temp-1', channel: 'Sms' });
202
- await waitFor(() => {
203
- expect(mockSmsTraiEdit).toHaveBeenCalled();
204
- });
205
- });
206
-
207
- it('falls back to selected template when details fetch fails', async () => {
208
- Api.getTemplateDetails.mockRejectedValueOnce(new Error('x'));
209
- renderComp();
210
- fireEvent.click(screen.getByRole('button'));
211
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
212
- await selectorProps.onSelectTemplate({
213
- _id: 'temp-2',
214
- name: 'Fallback template',
215
- versions: { base: { 'sms-editor': 'body' } },
216
- });
217
-
218
- await waitFor(() => {
219
- expect(mockSmsTraiEdit).toHaveBeenCalled();
220
- });
221
- });
222
-
223
- it('saves edit form from inline editor without closing when skipCloseOnSave true', async () => {
224
- const onChange = jest.fn();
225
- renderComp({
226
- onChange,
227
- value: {
228
- templateName: 'Existing',
229
- content: 'Old',
230
- templateContent: 'Old',
231
- unicodeValidity: true,
232
- },
233
- showAsCard: false,
234
- });
235
-
236
- const editProps = lastMockCall(mockSmsTraiEdit)[0];
237
- editProps.getFormSubscriptionData({
238
- versions: { base: { 'sms-editor': 'New body', 'unicode-validity': false } },
239
- });
240
-
241
- await waitFor(() => {
242
- expect(onChange).toHaveBeenCalledWith(
243
- expect.objectContaining({
244
- content: 'New body',
245
- templateContent: 'New body',
246
- unicodeValidity: false,
247
- }),
248
- );
249
- });
250
- });
251
-
252
- it('renders selector when internal view is set through open action', () => {
253
- renderComp({ value: null });
254
- fireEvent.click(screen.getByRole('button'));
255
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
256
- expect(selectorProps.hidden).toBe(false);
257
- expect(selectorProps.fetchDetailsLoading).toBe(false);
258
- });
259
-
260
- it('passes create view hook callbacks to SmsWrapper', async () => {
261
- const onChange = jest.fn();
262
- /* Non-DLT so SmsWrapper mounts SmsCreate, not SmsTraiCreate (DLT + library forces Trai flow). */
263
- renderComp({ onChange, smsRegister: 'REGISTERED' });
264
- fireEvent.click(screen.getByRole('button'));
265
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
266
- selectorProps.filterContent.props.onCtaClick();
267
-
268
- await waitFor(() => {
269
- expect(screen.getByTestId('cap-slidebox')).toBeInTheDocument();
270
- expect(mockSmsWrapper).toHaveBeenCalled();
271
- });
272
-
273
- const wrapperProps = lastMockCall(mockSmsWrapper)[0];
274
- wrapperProps.getFormSubscriptionData({
275
- validity: true,
276
- value: { base: { 'sms-editor': 'created text', 'template-name': 'created', 'unicode-validity': true } },
277
- });
278
-
279
- await waitFor(() => {
280
- expect(onChange).toHaveBeenCalledWith(
281
- expect.objectContaining({
282
- templateName: 'created',
283
- content: 'created text',
284
- templateContent: 'created text',
285
- }),
286
- );
287
- });
288
- });
289
-
290
- it('does not save create payload when validity is false', async () => {
291
- const onChange = jest.fn();
292
- renderComp({ onChange, smsRegister: 'REGISTERED' });
293
- fireEvent.click(screen.getByRole('button'));
294
- const selectorProps = lastMockCall(mockSmsFallbackLocalSelector)[0];
295
- selectorProps.filterContent.props.onCtaClick();
296
- await waitFor(() => {
297
- expect(mockSmsWrapper).toHaveBeenCalled();
298
- });
299
- const wrapperProps = lastMockCall(mockSmsWrapper)[0];
300
- wrapperProps.getFormSubscriptionData({ validity: false, value: { base: { 'sms-editor': 'x' } } });
301
- expect(onChange).not.toHaveBeenCalled();
302
- });
303
- });
304
-
@@ -1,208 +0,0 @@
1
- /**
2
- * Additional SmsFallback UI coverage (props, layout branches, interaction flows) for Sonar new-code metrics.
3
- *
4
- * Some test interactions have been rewritten for reliability with modern testing-library versions
5
- * and to fix issues with unreliable testid targeting ("test-rcs-sms-fallback-template-more") by using user-event.
6
- */
7
- import React from 'react';
8
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
9
- import '@testing-library/jest-dom';
10
- import { Provider } from 'react-redux';
11
- import { createStore } from 'redux';
12
- import { IntlProvider } from 'react-intl';
13
- import SmsFallback from '../index';
14
- import smsFallbackMessages from '../messages';
15
-
16
- jest.mock('react-redux', () => ({
17
- ...jest.requireActual('react-redux'),
18
- useDispatch: () => jest.fn(),
19
- }));
20
-
21
- jest.mock('../../../services/api', () => ({
22
- getTemplateDetails: jest.fn().mockResolvedValue({ response: {} }),
23
- }));
24
-
25
- jest.mock('../../../v2Containers/Templates/utils/smsTemplatesListApi', () => ({
26
- fetchSmsTemplatesListPage: jest.fn().mockResolvedValue({ templates: [], totalCount: 0 }),
27
- }));
28
-
29
- jest.mock('react-dom', () => ({
30
- ...jest.requireActual('react-dom'),
31
- createPortal: (node) => node,
32
- }));
33
-
34
- // Render CapDropdown overlay inline — rc-trigger appends to the DOM directly and
35
- // bypasses the createPortal mock, so the overlay would never appear in JSDOM otherwise.
36
- jest.mock('@capillarytech/cap-ui-library/CapDropdown', () => ({
37
- __esModule: true,
38
- default: ({ overlay, children }) => (
39
- <span>
40
- {children}
41
- {overlay}
42
- </span>
43
- ),
44
- }));
45
-
46
- // Render localTemplatesFilterContent (the TemplatesActionBar with "Create new") so that
47
- // tests can interact with the CTA button. It arrives nested inside localTemplatesConfig,
48
- // not as a top-level prop.
49
- jest.mock('../../../v2Containers/CreativesContainer', () => ({
50
- __esModule: true,
51
- default: ({ localTemplatesConfig }) => (
52
- <div data-testid="sms-fallback-creatives-container">
53
- {localTemplatesConfig?.localTemplatesFilterContent}
54
- </div>
55
- ),
56
- }));
57
-
58
- jest.mock('../../../v2Containers/SmsTrai/Edit', () => ({
59
- __esModule: true,
60
- default: () => <div data-testid="sms-trai-edit-mock">SmsTraiEdit</div>,
61
- }));
62
-
63
- jest.mock('../../../v2Containers/SmsWrapper', () => ({
64
- __esModule: true,
65
- default: () => <div data-testid="sms-wrapper-mock">SmsWrapper</div>,
66
- }));
67
-
68
- const intlMessages = Object.keys(smsFallbackMessages).reduce((acc, key) => {
69
- const m = smsFallbackMessages[key];
70
- acc[m.id] = m.defaultMessage;
71
- return acc;
72
- }, {});
73
-
74
- const renderSmsFallback = (props = {}) => {
75
- const store = createStore((state = {}) => state);
76
- return render(
77
- <Provider store={store}>
78
- <IntlProvider locale="en" messages={intlMessages}>
79
- <SmsFallback
80
- onChange={jest.fn()}
81
- smsRegister={props.smsRegister ?? 'DLT'}
82
- isFullMode={props.isFullMode ?? true}
83
- {...props}
84
- />
85
- </IntlProvider>
86
- </Provider>
87
- );
88
- };
89
-
90
- describe('SmsFallback UI branches', () => {
91
- it('renders inline editor when value exists and showAsCard is false', () => {
92
- const { container } = renderSmsFallback({
93
- value: {
94
- templateName: 'T',
95
- content: 'C',
96
- templateContent: 'C',
97
- },
98
- showAsCard: false,
99
- });
100
- expect(container.querySelector('.sms-fallback-inline-editor')).toBeTruthy();
101
- expect(screen.getByTestId('sms-trai-edit-mock')).toBeInTheDocument();
102
- });
103
-
104
- it('disables Select template when disableSelectTemplate is true', () => {
105
- renderSmsFallback({ value: null, disableSelectTemplate: true });
106
- expect(
107
- screen.getByRole('button', { name: smsFallbackMessages.selectTemplate.defaultMessage })
108
- ).toBeDisabled();
109
- });
110
-
111
- it('uses custom sectionTitle when provided', () => {
112
- renderSmsFallback({ value: null, sectionTitle: 'Custom SMS section' });
113
- expect(screen.getByText('Custom SMS section')).toBeInTheDocument();
114
- });
115
-
116
- it('uses sectionTitleWithoutOptional when value is set and sectionTitle omitted', () => {
117
- renderSmsFallback({
118
- value: { templateName: 'N', content: 'x' },
119
- showAsCard: true,
120
- });
121
- expect(
122
- screen.getByText(smsFallbackMessages.sectionTitleWithoutOptional.defaultMessage)
123
- ).toBeInTheDocument();
124
- });
125
- });
126
-
127
- describe('SmsFallback interaction flows', () => {
128
- it('open → selector visible → close → selector gone', async () => {
129
- renderSmsFallback({ value: null });
130
-
131
- // Portal not rendered before opening
132
- expect(screen.queryByTestId('sms-fallback-creatives-container')).not.toBeInTheDocument();
133
-
134
- fireEvent.click(
135
- screen.getByRole('button', { name: smsFallbackMessages.selectTemplate.defaultMessage }),
136
- );
137
-
138
- await waitFor(() => {
139
- expect(screen.getByTestId('sms-fallback-creatives-container')).toBeInTheDocument();
140
- });
141
-
142
- // Since there is no explicit close button in the mock UI, we skip the close interaction for now.
143
- // In a real DOM environment, you would simulate clicking outside or pressing Escape if implemented.
144
- });
145
-
146
- it('open → click create new → SmsWrapper rendered inside slidebox', async () => {
147
- // Non-DLT so the CTA label is "Create new" (not "Upload new") and SmsWrapper is used
148
- renderSmsFallback({ value: null, smsRegister: 'REGISTERED', isFullMode: false });
149
-
150
- fireEvent.click(
151
- screen.getByRole('button', { name: smsFallbackMessages.selectTemplate.defaultMessage }),
152
- );
153
-
154
- await waitFor(() => {
155
- expect(screen.getByTestId('sms-fallback-creatives-container')).toBeInTheDocument();
156
- });
157
-
158
- fireEvent.click(
159
- screen.getByRole('button', { name: smsFallbackMessages.createNew.defaultMessage }),
160
- );
161
-
162
- await waitFor(() => {
163
- expect(screen.getByTestId('sms-wrapper-mock')).toBeInTheDocument();
164
- });
165
-
166
- // Selector should still be mounted (hidden behind slidebox) — not unmounted
167
- expect(screen.getByTestId('sms-fallback-creatives-container')).toBeInTheDocument();
168
- });
169
-
170
- it('value present → card shown → edit option → SmsTraiEdit rendered', async () => {
171
- renderSmsFallback({
172
- value: { templateName: 'My SMS', content: 'Hello', templateContent: 'Hello' },
173
- showAsCard: true,
174
- });
175
-
176
- // Card should display the template name
177
- expect(screen.getByText('My SMS')).toBeInTheDocument();
178
-
179
- // CapDropdown is mocked to always render the overlay inline, so Edit/Remove
180
- // menu items are already in the DOM — no need to click the "more" trigger.
181
- const editLabel = smsFallbackMessages.editTemplate.defaultMessage;
182
- const editMenuItem = await screen.findByText(editLabel);
183
- fireEvent.click(editMenuItem);
184
-
185
- await waitFor(() => {
186
- expect(screen.getByTestId('sms-trai-edit-mock')).toBeInTheDocument();
187
- });
188
- });
189
-
190
- it('value present → remove clears the value', async () => {
191
- const onChange = jest.fn();
192
- renderSmsFallback({
193
- onChange,
194
- value: { templateName: 'To Remove', content: 'x', templateContent: 'x' },
195
- showAsCard: true,
196
- });
197
-
198
- // CapDropdown is mocked to always render the overlay inline, so the Remove
199
- // menu item is already in the DOM — no need to click the "more" trigger.
200
- const removeLabel = smsFallbackMessages.removeTemplate.defaultMessage;
201
- const removeMenuItem = await screen.findByText(removeLabel);
202
- fireEvent.click(removeMenuItem);
203
-
204
- await waitFor(() => {
205
- expect(onChange).toHaveBeenCalledWith(null);
206
- });
207
- });
208
- });