@capillarytech/creatives-library 8.0.318 → 8.0.319
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.
- package/constants/unified.js +1 -0
- package/package.json +1 -1
- package/services/api.js +6 -0
- package/services/tests/api.test.js +7 -0
- package/utils/common.js +6 -1
- package/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
- package/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
- package/v2Containers/CommunicationFlow/constants.js +200 -0
- package/v2Containers/CommunicationFlow/index.js +102 -0
- package/v2Containers/CommunicationFlow/messages.js +346 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
- package/v2Containers/CreativesContainer/constants.js +3 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
render, screen, waitFor, within,
|
|
4
|
+
} from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
|
+
import { IntlProvider } from 'react-intl';
|
|
8
|
+
import SenderDetails, { parseSenderDetailsFromEntity } from '../SenderDetails';
|
|
9
|
+
import * as deliverySettingsConfig from '../deliverySettingsConfig';
|
|
10
|
+
|
|
11
|
+
const { parseEntityForDisplay } = deliverySettingsConfig;
|
|
12
|
+
|
|
13
|
+
/** Shared domainProperties entity shapes (see deliverySettingsConfig). */
|
|
14
|
+
const ENTITIES = {
|
|
15
|
+
smsOk: {
|
|
16
|
+
SMS: [
|
|
17
|
+
{
|
|
18
|
+
domainProperties: {
|
|
19
|
+
id: 'sms-dom-1',
|
|
20
|
+
domainName: 'SMS domain',
|
|
21
|
+
contactInfo: [
|
|
22
|
+
{
|
|
23
|
+
type: 'gsm_sender_id',
|
|
24
|
+
value: '+1002003001',
|
|
25
|
+
valid: true,
|
|
26
|
+
default: true,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
smsTwoDomains: {
|
|
34
|
+
SMS: [
|
|
35
|
+
{
|
|
36
|
+
domainProperties: {
|
|
37
|
+
id: 'sms-a',
|
|
38
|
+
domainName: 'Gateway A',
|
|
39
|
+
contactInfo: [
|
|
40
|
+
{
|
|
41
|
+
type: 'gsm_sender_id', value: '+111', valid: true, default: true,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
domainProperties: {
|
|
48
|
+
id: 'sms-b',
|
|
49
|
+
domainName: 'Gateway B',
|
|
50
|
+
contactInfo: [
|
|
51
|
+
{
|
|
52
|
+
type: 'gsm_sender_id', value: '+222', valid: true, default: true,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
smsTwoSenders: {
|
|
60
|
+
SMS: [
|
|
61
|
+
{
|
|
62
|
+
domainProperties: {
|
|
63
|
+
id: 'sms-dom-1',
|
|
64
|
+
domainName: 'SMS domain',
|
|
65
|
+
contactInfo: [
|
|
66
|
+
{
|
|
67
|
+
type: 'gsm_sender_id', value: '+1002003001', valid: true, default: true,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
type: 'gsm_sender_id', value: '+1002003002', valid: true, default: false,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
emailTwoDomains: {
|
|
78
|
+
EMAIL: [
|
|
79
|
+
{
|
|
80
|
+
domainProperties: {
|
|
81
|
+
id: 'em-a',
|
|
82
|
+
domainName: 'Mail Alpha',
|
|
83
|
+
contactInfo: [
|
|
84
|
+
{
|
|
85
|
+
type: 'sender_id',
|
|
86
|
+
value: 'alpha@brand.com',
|
|
87
|
+
label: 'Alpha Name',
|
|
88
|
+
valid: true,
|
|
89
|
+
default: true,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: 'reply_to_id', value: 'reply-a@brand.com', valid: true, default: true,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
domainProperties: {
|
|
99
|
+
id: 'em-b',
|
|
100
|
+
domainName: 'Mail Beta',
|
|
101
|
+
contactInfo: [
|
|
102
|
+
{
|
|
103
|
+
type: 'sender_id',
|
|
104
|
+
value: 'beta@other.com',
|
|
105
|
+
label: 'Beta Name',
|
|
106
|
+
valid: true,
|
|
107
|
+
default: true,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'reply_to_id', value: 'reply-b@other.com', valid: true, default: true,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
whatsappWaba: {
|
|
118
|
+
WHATSAPP: [
|
|
119
|
+
{
|
|
120
|
+
domainProperties: {
|
|
121
|
+
id: 'wa-dom-99',
|
|
122
|
+
domainName: 'WA Business',
|
|
123
|
+
connectionProperties: { sourceAccountIdentifier: 'waba-xyz' },
|
|
124
|
+
contactInfo: [
|
|
125
|
+
{
|
|
126
|
+
type: 'gsm_sender_id', value: '+91900111222', valid: true, default: true,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'gsm_sender_id', value: '+91900111333', valid: true, default: false,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
rcsBrand: {
|
|
137
|
+
RCS: [
|
|
138
|
+
{
|
|
139
|
+
domainProperties: {
|
|
140
|
+
id: 'rcs-1',
|
|
141
|
+
domainName: 'RCS Brand Co',
|
|
142
|
+
contactInfo: [],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
function defaultSenderProps(override = {}) {
|
|
150
|
+
const { onClose: overrideOnClose, onSave: overrideOnSave, ...rest } = override;
|
|
151
|
+
return {
|
|
152
|
+
show: true,
|
|
153
|
+
channels: ['SMS'],
|
|
154
|
+
preloadedDomainProperties: ENTITIES.smsOk,
|
|
155
|
+
savedFieldValues: null,
|
|
156
|
+
whatsappSourceAccountId: '',
|
|
157
|
+
whatsappAccountName: '',
|
|
158
|
+
...rest,
|
|
159
|
+
onClose: overrideOnClose ?? jest.fn(),
|
|
160
|
+
onSave: overrideOnSave ?? jest.fn(),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function renderSenderDetails(override = {}) {
|
|
165
|
+
const props = defaultSenderProps(override);
|
|
166
|
+
const { onClose, onSave } = props;
|
|
167
|
+
const view = render(
|
|
168
|
+
<IntlProvider locale="en" messages={{}} defaultLocale="en">
|
|
169
|
+
<SenderDetails {...props} />
|
|
170
|
+
</IntlProvider>,
|
|
171
|
+
);
|
|
172
|
+
return { ...view, onClose, onSave };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function openSelectAndChoose(root, comboIndex, optionText) {
|
|
176
|
+
const combos = within(root).getAllByRole('combobox');
|
|
177
|
+
await userEvent.click(combos[comboIndex]);
|
|
178
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
179
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText(optionText));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
describe('SenderDetails', () => {
|
|
183
|
+
it('renders SMS fields when domain properties are preloaded', async () => {
|
|
184
|
+
renderSenderDetails();
|
|
185
|
+
const root = document.querySelector('.sender-details');
|
|
186
|
+
expect(root).toBeInTheDocument();
|
|
187
|
+
await waitFor(() => {
|
|
188
|
+
expect(within(root).getByText('Sender details')).toBeInTheDocument();
|
|
189
|
+
expect(within(root).getByText('SMS Domain')).toBeInTheDocument();
|
|
190
|
+
expect(within(root).getByText('Sender ID')).toBeInTheDocument();
|
|
191
|
+
expect(within(root).getByText('Save changes')).toBeInTheDocument();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('calls onClose when the back control is used', async () => {
|
|
196
|
+
const { onClose } = renderSenderDetails();
|
|
197
|
+
const root = document.querySelector('.sender-details');
|
|
198
|
+
await waitFor(() => {
|
|
199
|
+
expect(within(root).getByLabelText('Back')).toBeInTheDocument();
|
|
200
|
+
});
|
|
201
|
+
await userEvent.click(within(root).getByLabelText('Back'));
|
|
202
|
+
expect(onClose).toHaveBeenCalledTimes(1);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('shows domain gateway error when no SMS domains exist', async () => {
|
|
206
|
+
renderSenderDetails({
|
|
207
|
+
preloadedDomainProperties: { SMS: [] },
|
|
208
|
+
});
|
|
209
|
+
const root = document.querySelector('.sender-details');
|
|
210
|
+
await waitFor(() => {
|
|
211
|
+
expect(
|
|
212
|
+
within(root).getByText(/Domain gateway id is not found for the selected channel/i),
|
|
213
|
+
).toBeInTheDocument();
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('shows sender not configured when the domain has no sender options', async () => {
|
|
218
|
+
renderSenderDetails({
|
|
219
|
+
preloadedDomainProperties: {
|
|
220
|
+
SMS: [
|
|
221
|
+
{
|
|
222
|
+
domainProperties: {
|
|
223
|
+
id: 'sms-empty-senders',
|
|
224
|
+
domainName: 'Gateway without senders',
|
|
225
|
+
contactInfo: [],
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
const root = document.querySelector('.sender-details');
|
|
232
|
+
await waitFor(() => {
|
|
233
|
+
expect(
|
|
234
|
+
within(root).getByText(/Selected domain gateway id is not correct/i),
|
|
235
|
+
).toBeInTheDocument();
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('stays empty of field labels when slidebox is open but preloaded data is missing', () => {
|
|
240
|
+
renderSenderDetails({
|
|
241
|
+
preloadedDomainProperties: null,
|
|
242
|
+
});
|
|
243
|
+
const root = document.querySelector('.sender-details');
|
|
244
|
+
expect(root).toBeInTheDocument();
|
|
245
|
+
expect(screen.queryByText('SMS Domain')).not.toBeInTheDocument();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('applies savedFieldValues over API defaults for SMS sender', async () => {
|
|
249
|
+
renderSenderDetails({
|
|
250
|
+
preloadedDomainProperties: ENTITIES.smsTwoSenders,
|
|
251
|
+
savedFieldValues: { smsSenderId: '+1002003002' },
|
|
252
|
+
});
|
|
253
|
+
const root = document.querySelector('.sender-details');
|
|
254
|
+
await waitFor(() => {
|
|
255
|
+
expect(within(root).getByText('+1002003002')).toBeInTheDocument();
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('saves SMS after changing sender and invokes onSave then onClose', async () => {
|
|
260
|
+
const { onSave, onClose } = renderSenderDetails({
|
|
261
|
+
preloadedDomainProperties: ENTITIES.smsTwoSenders,
|
|
262
|
+
});
|
|
263
|
+
const root = document.querySelector('.sender-details');
|
|
264
|
+
await waitFor(() => expect(within(root).getByText('Sender ID')).toBeInTheDocument());
|
|
265
|
+
|
|
266
|
+
const combos = within(root).getAllByRole('combobox');
|
|
267
|
+
await userEvent.click(combos[1]);
|
|
268
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
269
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText('+1002003002'));
|
|
270
|
+
|
|
271
|
+
const saveBtn = within(root).getByRole('button', { name: /save changes/i });
|
|
272
|
+
await waitFor(() => expect(saveBtn).not.toBeDisabled());
|
|
273
|
+
await userEvent.click(saveBtn);
|
|
274
|
+
|
|
275
|
+
expect(onSave).toHaveBeenCalledTimes(1);
|
|
276
|
+
expect(onSave.mock.calls[0][0]).toMatchObject({
|
|
277
|
+
smsSenderId: '+1002003002',
|
|
278
|
+
});
|
|
279
|
+
expect(onClose).toHaveBeenCalled();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('resets SMS domain when multiple gateways exist', async () => {
|
|
283
|
+
renderSenderDetails({
|
|
284
|
+
preloadedDomainProperties: ENTITIES.smsTwoDomains,
|
|
285
|
+
});
|
|
286
|
+
const root = document.querySelector('.sender-details');
|
|
287
|
+
await waitFor(() => expect(within(root).getByText('Gateway A')).toBeInTheDocument());
|
|
288
|
+
|
|
289
|
+
await openSelectAndChoose(root, 0, 'Gateway B');
|
|
290
|
+
await waitFor(() => expect(within(root).getByText('+222')).toBeInTheDocument());
|
|
291
|
+
|
|
292
|
+
const resetLinks = within(root).getAllByTitle('Reset');
|
|
293
|
+
await userEvent.click(resetLinks[0]);
|
|
294
|
+
|
|
295
|
+
await waitFor(() => {
|
|
296
|
+
expect(within(root).getByText('Gateway A')).toBeInTheDocument();
|
|
297
|
+
expect(within(root).getByText('+111')).toBeInTheDocument();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('updates email sender fields when email domain changes', async () => {
|
|
302
|
+
renderSenderDetails({
|
|
303
|
+
channels: ['EMAIL'],
|
|
304
|
+
preloadedDomainProperties: ENTITIES.emailTwoDomains,
|
|
305
|
+
});
|
|
306
|
+
const root = document.querySelector('.sender-details');
|
|
307
|
+
await waitFor(() => expect(within(root).getByText('Mail Alpha')).toBeInTheDocument());
|
|
308
|
+
|
|
309
|
+
await openSelectAndChoose(root, 0, 'Mail Beta');
|
|
310
|
+
|
|
311
|
+
await waitFor(() => {
|
|
312
|
+
expect(within(root).getByText('beta@other.com')).toBeInTheDocument();
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('resets email domain row back to the first gateway', async () => {
|
|
317
|
+
renderSenderDetails({
|
|
318
|
+
channels: ['EMAIL'],
|
|
319
|
+
preloadedDomainProperties: ENTITIES.emailTwoDomains,
|
|
320
|
+
});
|
|
321
|
+
const root = document.querySelector('.sender-details');
|
|
322
|
+
await waitFor(() => expect(within(root).getByText('Mail Alpha')).toBeInTheDocument());
|
|
323
|
+
|
|
324
|
+
await openSelectAndChoose(root, 0, 'Mail Beta');
|
|
325
|
+
await waitFor(() => expect(within(root).getByText('beta@other.com')).toBeInTheDocument());
|
|
326
|
+
|
|
327
|
+
const resetLinks = within(root).getAllByTitle('Reset');
|
|
328
|
+
await userEvent.click(resetLinks[0]);
|
|
329
|
+
|
|
330
|
+
await waitFor(() => {
|
|
331
|
+
expect(within(root).getByText('alpha@brand.com')).toBeInTheDocument();
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('resets SMS sender ID via generic reset branch', async () => {
|
|
336
|
+
renderSenderDetails({
|
|
337
|
+
preloadedDomainProperties: ENTITIES.smsTwoSenders,
|
|
338
|
+
});
|
|
339
|
+
const root = document.querySelector('.sender-details');
|
|
340
|
+
await waitFor(() => expect(within(root).getByText('+1002003001')).toBeInTheDocument());
|
|
341
|
+
|
|
342
|
+
const combos = within(root).getAllByRole('combobox');
|
|
343
|
+
await userEvent.click(combos[1]);
|
|
344
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
345
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText('+1002003002'));
|
|
346
|
+
|
|
347
|
+
const resetLinks = within(root).getAllByTitle('Reset');
|
|
348
|
+
await userEvent.click(resetLinks[1]);
|
|
349
|
+
|
|
350
|
+
await waitFor(() => expect(within(root).getByText('+1002003001')).toBeInTheDocument());
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('persists whatsappDomainId on save when WABA matches template source id', async () => {
|
|
354
|
+
const { onSave } = renderSenderDetails({
|
|
355
|
+
channels: ['WHATSAPP'],
|
|
356
|
+
preloadedDomainProperties: ENTITIES.whatsappWaba,
|
|
357
|
+
whatsappSourceAccountId: 'waba-xyz',
|
|
358
|
+
whatsappAccountName: 'My Business',
|
|
359
|
+
});
|
|
360
|
+
const root = document.querySelector('.sender-details');
|
|
361
|
+
await waitFor(() => expect(within(root).getByText('My Business')).toBeInTheDocument());
|
|
362
|
+
|
|
363
|
+
const combos = within(root).getAllByRole('combobox');
|
|
364
|
+
await userEvent.click(combos[combos.length - 1]);
|
|
365
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
366
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText('+91900111333'));
|
|
367
|
+
|
|
368
|
+
const saveBtn = within(root).getByRole('button', { name: /save changes/i });
|
|
369
|
+
await waitFor(() => expect(saveBtn).not.toBeDisabled());
|
|
370
|
+
await userEvent.click(saveBtn);
|
|
371
|
+
|
|
372
|
+
expect(onSave).toHaveBeenCalledWith(
|
|
373
|
+
expect.objectContaining({
|
|
374
|
+
whatsappDomainId: 'wa-dom-99',
|
|
375
|
+
whatsappSenderNumber: '+91900111333',
|
|
376
|
+
}),
|
|
377
|
+
);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('shows RCS account name from preloaded entity', async () => {
|
|
381
|
+
renderSenderDetails({
|
|
382
|
+
channels: ['RCS'],
|
|
383
|
+
preloadedDomainProperties: ENTITIES.rcsBrand,
|
|
384
|
+
});
|
|
385
|
+
const root = document.querySelector('.sender-details');
|
|
386
|
+
await waitFor(() => {
|
|
387
|
+
expect(within(root).getByText('RCS Brand Co')).toBeInTheDocument();
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('exposes parseSenderDetailsFromEntity aligned with parseEntityForDisplay', () => {
|
|
392
|
+
expect(parseSenderDetailsFromEntity(ENTITIES.smsOk)).toEqual(
|
|
393
|
+
parseEntityForDisplay(ENTITIES.smsOk, {}),
|
|
394
|
+
);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('renders nothing substantive when channels list is empty', async () => {
|
|
398
|
+
renderSenderDetails({
|
|
399
|
+
channels: [],
|
|
400
|
+
preloadedDomainProperties: ENTITIES.smsOk,
|
|
401
|
+
});
|
|
402
|
+
const root = document.querySelector('.sender-details');
|
|
403
|
+
expect(root).toBeInTheDocument();
|
|
404
|
+
await waitFor(() => {
|
|
405
|
+
expect(within(root).queryByText('SMS Domain')).not.toBeInTheDocument();
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('changing SMS domain auto-populates the sender ID (handleFieldChange cascade)', async () => {
|
|
410
|
+
// Covers lines 102-104: fieldKey === 'smsDomain' && entity → auto-populate smsSenderId
|
|
411
|
+
renderSenderDetails({
|
|
412
|
+
channels: ['SMS'],
|
|
413
|
+
preloadedDomainProperties: ENTITIES.smsTwoDomains,
|
|
414
|
+
});
|
|
415
|
+
const root = document.querySelector('.sender-details');
|
|
416
|
+
await waitFor(() => expect(within(root).getByText('Gateway A')).toBeInTheDocument());
|
|
417
|
+
|
|
418
|
+
const combos = within(root).getAllByRole('combobox');
|
|
419
|
+
await userEvent.click(combos[0]);
|
|
420
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
421
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText('Gateway B'));
|
|
422
|
+
|
|
423
|
+
// The sender ID should now auto-update to Gateway B's sender
|
|
424
|
+
await waitFor(() => expect(within(root).getByText('+222')).toBeInTheDocument());
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('changing EMAIL domain cascades into sender ID, name, and reply-to fields', async () => {
|
|
428
|
+
// Covers lines 106-110: fieldKey === 'emailDomain' && entity → cascade update
|
|
429
|
+
renderSenderDetails({
|
|
430
|
+
channels: ['EMAIL'],
|
|
431
|
+
preloadedDomainProperties: ENTITIES.emailTwoDomains,
|
|
432
|
+
});
|
|
433
|
+
const root = document.querySelector('.sender-details');
|
|
434
|
+
await waitFor(() => expect(within(root).getByText('Mail Alpha')).toBeInTheDocument());
|
|
435
|
+
|
|
436
|
+
// Switch to Mail Beta domain
|
|
437
|
+
const combos = within(root).getAllByRole('combobox');
|
|
438
|
+
await userEvent.click(combos[0]);
|
|
439
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
440
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText('Mail Beta'));
|
|
441
|
+
|
|
442
|
+
// Sender ID should auto-update to beta@other.com
|
|
443
|
+
await waitFor(() => expect(within(root).getByText('beta@other.com')).toBeInTheDocument());
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it('handles WhatsApp domain derivation in handleSave with sourceAccountIdentifier connectionProperties', async () => {
|
|
447
|
+
// Covers lines 147-155: whatsappSourceAccountId && entity → derive whatsappDomainId
|
|
448
|
+
const onSave = jest.fn();
|
|
449
|
+
renderSenderDetails({
|
|
450
|
+
channels: ['WHATSAPP'],
|
|
451
|
+
preloadedDomainProperties: ENTITIES.whatsappWaba,
|
|
452
|
+
whatsappSourceAccountId: 'waba-xyz',
|
|
453
|
+
whatsappAccountName: 'WA Business',
|
|
454
|
+
onSave,
|
|
455
|
+
});
|
|
456
|
+
const root = document.querySelector('.sender-details');
|
|
457
|
+
await waitFor(() => expect(within(root).getByText('WA Business')).toBeInTheDocument());
|
|
458
|
+
|
|
459
|
+
// Change sender to enable save
|
|
460
|
+
const combos = within(root).getAllByRole('combobox');
|
|
461
|
+
const senderCombo = combos[combos.length - 1];
|
|
462
|
+
await userEvent.click(senderCombo);
|
|
463
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
464
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText('+91900111333'));
|
|
465
|
+
|
|
466
|
+
const saveBtn = within(root).getByRole('button', { name: /save changes/i });
|
|
467
|
+
await waitFor(() => expect(saveBtn).not.toBeDisabled());
|
|
468
|
+
await userEvent.click(saveBtn);
|
|
469
|
+
|
|
470
|
+
// Should have called onSave with whatsappDomainId derived from the matched WABA domain
|
|
471
|
+
expect(onSave).toHaveBeenCalledWith(
|
|
472
|
+
expect.objectContaining({ whatsappDomainId: 'wa-dom-99' }),
|
|
473
|
+
);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('resets viberSenderId via the else branch in handleReset (non-domain field)', async () => {
|
|
477
|
+
// Covers lines 136-138: else branch in handleReset for non-smsDomain/emailDomain fields
|
|
478
|
+
const viberEntity = {
|
|
479
|
+
VIBER: [{
|
|
480
|
+
id: 'vgw',
|
|
481
|
+
domainProperties: {
|
|
482
|
+
id: 0,
|
|
483
|
+
domainName: 'Viber GW',
|
|
484
|
+
contactInfo: [
|
|
485
|
+
{ type: 'gsm_sender_id', value: '+viber-def', valid: true, default: true },
|
|
486
|
+
{ type: 'gsm_sender_id', value: '+viber-alt', valid: true, default: false },
|
|
487
|
+
],
|
|
488
|
+
},
|
|
489
|
+
}],
|
|
490
|
+
};
|
|
491
|
+
renderSenderDetails({
|
|
492
|
+
channels: ['VIBER'],
|
|
493
|
+
preloadedDomainProperties: viberEntity,
|
|
494
|
+
});
|
|
495
|
+
const root = document.querySelector('.sender-details');
|
|
496
|
+
await waitFor(() => expect(within(root).getByText('Sender ID')).toBeInTheDocument());
|
|
497
|
+
|
|
498
|
+
// Change to an alternate sender
|
|
499
|
+
const combos = within(root).getAllByRole('combobox');
|
|
500
|
+
const senderCombo = combos[combos.length - 1];
|
|
501
|
+
await userEvent.click(senderCombo);
|
|
502
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
503
|
+
await userEvent.click(within(screen.getByRole('listbox')).getByText('+viber-alt'));
|
|
504
|
+
|
|
505
|
+
await waitFor(() => expect(within(root).getByText('+viber-alt')).toBeInTheDocument());
|
|
506
|
+
|
|
507
|
+
// Now click reset — for viberSenderId the else branch in handleReset is hit
|
|
508
|
+
// (viberSenderId is not smsDomain/emailDomain, so getDefaultValueForField returns '')
|
|
509
|
+
const resetLinks = within(root).getAllByTitle('Reset');
|
|
510
|
+
await userEvent.click(resetLinks[resetLinks.length - 1]);
|
|
511
|
+
// After reset, the field goes to the default value returned by getDefaultValueForField
|
|
512
|
+
// For viberSenderId this is '' (no specific default handler)
|
|
513
|
+
await waitFor(() => expect(within(root).queryByText('+viber-alt')).not.toBeInTheDocument());
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it('renders a DISPLAY-type field as a read-only heading (no select or reset)', async () => {
|
|
517
|
+
// Covers line 227-231: type === FIELD_TYPE.DISPLAY rendering path
|
|
518
|
+
jest.spyOn(deliverySettingsConfig, 'getFieldsForChannels').mockReturnValue([
|
|
519
|
+
{
|
|
520
|
+
channel: 'EMAIL',
|
|
521
|
+
fieldKey: 'emailDomainDisplay',
|
|
522
|
+
messageKey: 'emailDomainLabel',
|
|
523
|
+
type: deliverySettingsConfig.FIELD_TYPE.DISPLAY,
|
|
524
|
+
getValue: () => 'Transactional domain',
|
|
525
|
+
getOptions: () => [],
|
|
526
|
+
},
|
|
527
|
+
]);
|
|
528
|
+
renderSenderDetails({
|
|
529
|
+
preloadedDomainProperties: ENTITIES.smsOk,
|
|
530
|
+
});
|
|
531
|
+
const root = document.querySelector('.sender-details');
|
|
532
|
+
await waitFor(() => {
|
|
533
|
+
expect(within(root).getByText('Email Domain')).toBeInTheDocument();
|
|
534
|
+
});
|
|
535
|
+
// DISPLAY type should not show a combobox
|
|
536
|
+
expect(within(root).queryByRole('combobox')).not.toBeInTheDocument();
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
it('returns null (renders nothing) for a field with an unknown type', async () => {
|
|
540
|
+
// Covers line 271: return null fallthrough at end of renderField
|
|
541
|
+
jest.spyOn(deliverySettingsConfig, 'getFieldsForChannels').mockReturnValue([
|
|
542
|
+
{
|
|
543
|
+
channel: 'SMS',
|
|
544
|
+
fieldKey: 'unknownField',
|
|
545
|
+
messageKey: 'smsDomain',
|
|
546
|
+
type: 'not-a-real-type',
|
|
547
|
+
getValue: () => '',
|
|
548
|
+
getOptions: () => [],
|
|
549
|
+
},
|
|
550
|
+
]);
|
|
551
|
+
renderSenderDetails({
|
|
552
|
+
preloadedDomainProperties: ENTITIES.smsOk,
|
|
553
|
+
});
|
|
554
|
+
const root = document.querySelector('.sender-details');
|
|
555
|
+
await waitFor(() => expect(within(root).getByText('Sender details')).toBeInTheDocument());
|
|
556
|
+
// No combobox should be rendered for an unknown field type
|
|
557
|
+
expect(within(root).queryByRole('combobox')).not.toBeInTheDocument();
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it('reset link click when only one option available does not call handleReset (isSingleOption guard)', async () => {
|
|
561
|
+
// Covers line 259: onClick: if (!isSingleOption) handleReset(fieldKey) — single option branch
|
|
562
|
+
// Ensure no active spies from previous tests interfere
|
|
563
|
+
jest.restoreAllMocks();
|
|
564
|
+
renderSenderDetails({
|
|
565
|
+
preloadedDomainProperties: ENTITIES.smsOk,
|
|
566
|
+
});
|
|
567
|
+
const root = document.querySelector('.sender-details');
|
|
568
|
+
await waitFor(() => expect(within(root).getByText('Sender ID')).toBeInTheDocument());
|
|
569
|
+
|
|
570
|
+
// smsOk has exactly 1 sender option — clicking reset should be a no-op
|
|
571
|
+
const resetLinks = within(root).getAllByTitle('Reset');
|
|
572
|
+
const lastReset = resetLinks[resetLinks.length - 1];
|
|
573
|
+
await userEvent.click(lastReset);
|
|
574
|
+
// Value should remain the same (no state change)
|
|
575
|
+
await waitFor(() => expect(within(root).getByText('+1002003001')).toBeInTheDocument());
|
|
576
|
+
});
|
|
577
|
+
});
|