@capillarytech/creatives-library 8.0.345-alpha.12 → 8.0.345-alpha.13

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 (138) hide show
  1. package/constants/unified.js +0 -29
  2. package/package.json +1 -1
  3. package/services/api.js +20 -0
  4. package/services/tests/api.test.js +59 -13
  5. package/utils/commonUtils.js +1 -19
  6. package/v2Components/CapActionButton/constants.js +0 -7
  7. package/v2Components/CapActionButton/index.js +109 -167
  8. package/v2Components/CapActionButton/index.scss +6 -157
  9. package/v2Components/CapActionButton/messages.js +3 -19
  10. package/v2Components/CapActionButton/tests/index.test.js +17 -41
  11. package/v2Components/CapCustomSkeleton/index.js +1 -1
  12. package/v2Components/CapCustomSkeleton/tests/__snapshots__/index.test.js.snap +12 -12
  13. package/v2Components/CapTagList/index.js +0 -10
  14. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -70
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -207
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
  21. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  22. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -160
  23. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -341
  24. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
  25. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  26. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  27. package/v2Components/CommonTestAndPreview/index.js +186 -676
  28. package/v2Components/CommonTestAndPreview/messages.js +3 -49
  29. package/v2Components/CommonTestAndPreview/sagas.js +6 -15
  30. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
  31. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  32. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  33. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  34. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  35. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  36. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  37. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  38. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
  39. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
  40. package/v2Components/FormBuilder/index.js +10 -8
  41. package/v2Components/TemplatePreview/_templatePreview.scss +23 -33
  42. package/v2Components/TemplatePreview/index.js +28 -143
  43. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  44. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  45. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  46. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  47. package/v2Containers/Assets/images/archive_Empty_Illustration.svg +9 -0
  48. package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
  49. package/v2Containers/CreativesContainer/SlideBoxFooter.js +4 -11
  50. package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
  51. package/v2Containers/CreativesContainer/constants.js +0 -9
  52. package/v2Containers/CreativesContainer/index.js +108 -300
  53. package/v2Containers/CreativesContainer/index.scss +1 -51
  54. package/v2Containers/CreativesContainer/messages.js +4 -0
  55. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
  56. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  57. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  58. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
  59. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +18 -20
  60. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  61. package/v2Containers/Rcs/constants.js +8 -119
  62. package/v2Containers/Rcs/index.js +812 -2375
  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 +70345 -98302
  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/ChannelTypeIllustration.js +23 -6
  80. package/v2Containers/Templates/_templates.scss +126 -181
  81. package/v2Containers/Templates/actions.js +36 -11
  82. package/v2Containers/Templates/constants.js +23 -2
  83. package/v2Containers/Templates/index.js +333 -142
  84. package/v2Containers/Templates/messages.js +68 -0
  85. package/v2Containers/Templates/reducer.js +68 -0
  86. package/v2Containers/Templates/sagas.js +98 -55
  87. package/v2Containers/Templates/selectors.js +12 -0
  88. package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +12 -0
  89. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1256 -1042
  90. package/v2Containers/Templates/tests/index.test.js +6 -0
  91. package/v2Containers/Templates/tests/reducer.test.js +178 -0
  92. package/v2Containers/Templates/tests/sagas.test.js +436 -200
  93. package/v2Containers/Templates/tests/selector.test.js +32 -0
  94. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  95. package/v2Containers/TemplatesV2/index.js +23 -86
  96. package/v2Containers/Whatsapp/index.js +20 -3
  97. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  98. package/utils/rcsPayloadUtils.js +0 -92
  99. package/utils/templateVarUtils.js +0 -201
  100. package/utils/tests/templateVarUtils.test.js +0 -204
  101. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js.rej +0 -18
  102. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  103. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  104. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -87
  105. package/v2Components/SmsFallback/constants.js +0 -73
  106. package/v2Components/SmsFallback/index.js +0 -955
  107. package/v2Components/SmsFallback/index.scss +0 -265
  108. package/v2Components/SmsFallback/messages.js +0 -78
  109. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -118
  110. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  111. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  112. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  113. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -197
  114. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -277
  115. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  116. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  117. package/v2Components/TemplatePreview/constants.js +0 -2
  118. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  119. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  120. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  121. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
  122. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -67
  123. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  124. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  125. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  126. package/v2Containers/Rcs/index.js.rej +0 -1336
  127. package/v2Containers/Rcs/index.scss.rej +0 -74
  128. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
  129. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap.rej +0 -128
  130. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  131. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  132. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  133. package/v2Containers/SmsTrai/Edit/index.scss +0 -121
  134. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  135. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  136. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  137. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  138. 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,197 +0,0 @@
1
- /**
2
- * Additional SmsFallback UI coverage (props, layout branches, interaction flows) for Sonar new-code metrics.
3
- */
4
- import React from 'react';
5
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
6
- import '@testing-library/jest-dom';
7
- import { Provider } from 'react-redux';
8
- import { createStore } from 'redux';
9
- import { IntlProvider } from 'react-intl';
10
- import SmsFallback from '../index';
11
- import smsFallbackMessages from '../messages';
12
-
13
- jest.mock('react-redux', () => ({
14
- ...jest.requireActual('react-redux'),
15
- useDispatch: () => jest.fn(),
16
- }));
17
-
18
- jest.mock('../../../services/api', () => ({
19
- getTemplateDetails: jest.fn().mockResolvedValue({ response: {} }),
20
- }));
21
-
22
- jest.mock('../../../v2Containers/Templates/utils/smsTemplatesListApi', () => ({
23
- fetchSmsTemplatesListPage: jest.fn().mockResolvedValue({ templates: [], totalCount: 0 }),
24
- }));
25
-
26
- jest.mock('react-dom', () => ({
27
- ...jest.requireActual('react-dom'),
28
- createPortal: (node) => node,
29
- }));
30
-
31
- // Render CapDropdown overlay inline — rc-trigger appends to the DOM directly and
32
- // bypasses the createPortal mock, so the overlay would never appear in JSDOM otherwise.
33
- jest.mock('@capillarytech/cap-ui-library/CapDropdown', () => ({
34
- __esModule: true,
35
- default: ({ overlay, children }) => (
36
- <span>
37
- {children}
38
- {overlay}
39
- </span>
40
- ),
41
- }));
42
-
43
- // Render localTemplatesFilterContent (the TemplatesActionBar with "Create new") so that
44
- // tests can interact with the CTA button. It arrives nested inside localTemplatesConfig,
45
- // not as a top-level prop.
46
- jest.mock('../../../v2Containers/CreativesContainer', () => ({
47
- __esModule: true,
48
- default: ({ localTemplatesConfig }) => (
49
- <div data-testid="sms-fallback-creatives-container">
50
- {localTemplatesConfig?.localTemplatesFilterContent}
51
- </div>
52
- ),
53
- }));
54
-
55
- jest.mock('../../../v2Containers/SmsTrai/Edit', () => ({
56
- __esModule: true,
57
- default: () => <div data-testid="sms-trai-edit-mock">SmsTraiEdit</div>,
58
- }));
59
-
60
- jest.mock('../../../v2Containers/SmsWrapper', () => ({
61
- __esModule: true,
62
- default: () => <div data-testid="sms-wrapper-mock">SmsWrapper</div>,
63
- }));
64
-
65
- const intlMessages = Object.keys(smsFallbackMessages).reduce((acc, key) => {
66
- const m = smsFallbackMessages[key];
67
- acc[m.id] = m.defaultMessage;
68
- return acc;
69
- }, {});
70
-
71
- const renderSmsFallback = (props = {}) => {
72
- const store = createStore((state = {}) => state);
73
- return render(
74
- <Provider store={store}>
75
- <IntlProvider locale="en" messages={intlMessages}>
76
- <SmsFallback
77
- onChange={jest.fn()}
78
- smsRegister={props.smsRegister ?? 'DLT'}
79
- isFullMode={props.isFullMode ?? true}
80
- {...props}
81
- />
82
- </IntlProvider>
83
- </Provider>
84
- );
85
- };
86
-
87
- describe('SmsFallback UI branches', () => {
88
- it('renders inline editor when value exists and showAsCard is false', () => {
89
- const { container } = renderSmsFallback({
90
- value: {
91
- templateName: 'T',
92
- content: 'C',
93
- templateContent: 'C',
94
- },
95
- showAsCard: false,
96
- });
97
- expect(container.querySelector('.sms-fallback-inline-editor')).toBeTruthy();
98
- expect(screen.getByTestId('sms-trai-edit-mock')).toBeInTheDocument();
99
- });
100
-
101
- it('disables Select template when disableSelectTemplate is true', () => {
102
- renderSmsFallback({ value: null, disableSelectTemplate: true });
103
- expect(
104
- screen.getByRole('button', { name: smsFallbackMessages.selectTemplate.defaultMessage })
105
- ).toBeDisabled();
106
- });
107
-
108
- it('uses custom sectionTitle when provided', () => {
109
- renderSmsFallback({ value: null, sectionTitle: 'Custom SMS section' });
110
- expect(screen.getByText('Custom SMS section')).toBeInTheDocument();
111
- });
112
-
113
- it('uses sectionTitleWithoutOptional when value is set and sectionTitle omitted', () => {
114
- renderSmsFallback({
115
- value: { templateName: 'N', content: 'x' },
116
- showAsCard: true,
117
- });
118
- expect(
119
- screen.getByText(smsFallbackMessages.sectionTitleWithoutOptional.defaultMessage)
120
- ).toBeInTheDocument();
121
- });
122
- });
123
-
124
- describe('SmsFallback interaction flows', () => {
125
- it('open → selector visible → close → selector gone', async () => {
126
- renderSmsFallback({ value: null });
127
-
128
- // Portal not rendered before opening
129
- expect(screen.queryByTestId('sms-fallback-creatives-container')).not.toBeInTheDocument();
130
-
131
- fireEvent.click(
132
- screen.getByRole('button', { name: smsFallbackMessages.selectTemplate.defaultMessage }),
133
- );
134
-
135
- await waitFor(() => {
136
- expect(screen.getByTestId('sms-fallback-creatives-container')).toBeInTheDocument();
137
- });
138
- });
139
-
140
- it('open → click create new → SmsWrapper rendered inside slidebox', async () => {
141
- // Non-DLT so the CTA label is "Create new" (not "Upload new") and SmsWrapper is used
142
- renderSmsFallback({ value: null, smsRegister: 'REGISTERED', isFullMode: false });
143
-
144
- fireEvent.click(
145
- screen.getByRole('button', { name: smsFallbackMessages.selectTemplate.defaultMessage }),
146
- );
147
-
148
- await waitFor(() => {
149
- expect(screen.getByTestId('sms-fallback-creatives-container')).toBeInTheDocument();
150
- });
151
-
152
- fireEvent.click(
153
- screen.getByRole('button', { name: smsFallbackMessages.createNew.defaultMessage }),
154
- );
155
-
156
- await waitFor(() => {
157
- expect(screen.getByTestId('sms-wrapper-mock')).toBeInTheDocument();
158
- });
159
-
160
- // Selector should still be mounted (hidden behind slidebox) — not unmounted
161
- expect(screen.getByTestId('sms-fallback-creatives-container')).toBeInTheDocument();
162
- });
163
-
164
- it('value present → card shown → edit option → SmsTraiEdit rendered', async () => {
165
- const { container } = renderSmsFallback({
166
- value: { templateName: 'My SMS', content: 'Hello', templateContent: 'Hello' },
167
- showAsCard: true,
168
- });
169
-
170
- // Card should display the template name
171
- expect(screen.getByText('My SMS')).toBeInTheDocument();
172
-
173
- // The "more" trigger is a CapIcon rendered as an <i> (no accessible role) — query by class.
174
- fireEvent.click(container.querySelector('.cap-icon-v2-more'));
175
- // CapMenu.Item renders as <li> — find by visible text.
176
- fireEvent.click(screen.getByText(smsFallbackMessages.editTemplate.defaultMessage));
177
-
178
- await waitFor(() => {
179
- expect(screen.getByTestId('sms-trai-edit-mock')).toBeInTheDocument();
180
- });
181
- });
182
-
183
- it('value present → remove clears the value', async () => {
184
- const onChange = jest.fn();
185
- const { container } = renderSmsFallback({
186
- onChange,
187
- value: { templateName: 'To Remove', content: 'x', templateContent: 'x' },
188
- showAsCard: true,
189
- });
190
-
191
- fireEvent.click(container.querySelector('.cap-icon-v2-more'));
192
- // CapMenu.Item renders as <li> — find by visible text.
193
- fireEvent.click(screen.getByText(smsFallbackMessages.removeTemplate.defaultMessage));
194
-
195
- expect(onChange).toHaveBeenCalledWith(null);
196
- });
197
- });