@capillarytech/creatives-library 8.0.290-alpha.3 → 8.0.290

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 (76) hide show
  1. package/constants/unified.js +1 -0
  2. package/initialState.js +2 -0
  3. package/package.json +1 -1
  4. package/utils/common.js +8 -5
  5. package/utils/commonUtils.js +85 -4
  6. package/utils/tagValidations.js +222 -84
  7. package/utils/tests/commonUtil.test.js +124 -147
  8. package/utils/tests/tagValidations.test.js +358 -280
  9. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +33 -0
  10. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +397 -0
  11. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.scss +35 -0
  12. package/v2Components/CommonTestAndPreview/DeliverySettings/TECH_DETAILING_DELIVERY_SETTINGS.md +725 -0
  13. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +92 -0
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +243 -0
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +111 -0
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +91 -0
  17. package/v2Components/CommonTestAndPreview/SendTestMessage.js +33 -1
  18. package/v2Components/CommonTestAndPreview/actions.js +20 -0
  19. package/v2Components/CommonTestAndPreview/constants.js +10 -0
  20. package/v2Components/CommonTestAndPreview/index.js +133 -15
  21. package/v2Components/CommonTestAndPreview/reducer.js +47 -0
  22. package/v2Components/CommonTestAndPreview/sagas.js +60 -0
  23. package/v2Components/CommonTestAndPreview/selectors.js +51 -0
  24. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +782 -0
  25. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +200 -0
  26. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +235 -0
  27. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +127 -0
  28. package/v2Components/CommonTestAndPreview/tests/actions.test.js +50 -0
  29. package/v2Components/CommonTestAndPreview/tests/constants.test.js +18 -0
  30. package/v2Components/CommonTestAndPreview/tests/index.test.js +214 -1
  31. package/v2Components/CommonTestAndPreview/tests/reducer.test.js +118 -0
  32. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +145 -0
  33. package/v2Components/CommonTestAndPreview/tests/selectors.test.js +146 -0
  34. package/v2Components/ErrorInfoNote/index.js +5 -2
  35. package/v2Components/FormBuilder/index.js +162 -84
  36. package/v2Components/FormBuilder/messages.js +8 -0
  37. package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
  38. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  39. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
  40. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
  41. package/v2Components/TestAndPreviewSlidebox/index.js +14 -0
  42. package/v2Containers/Cap/mockData.js +14 -0
  43. package/v2Containers/Cap/reducer.js +55 -3
  44. package/v2Containers/Cap/tests/reducer.test.js +102 -0
  45. package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -3
  46. package/v2Containers/CreativesContainer/index.js +6 -19
  47. package/v2Containers/Email/index.js +5 -1
  48. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +62 -10
  49. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +115 -12
  50. package/v2Containers/FTP/index.js +51 -2
  51. package/v2Containers/FTP/messages.js +4 -0
  52. package/v2Containers/InApp/index.js +96 -1
  53. package/v2Containers/InApp/tests/index.test.js +6 -17
  54. package/v2Containers/InappAdvance/index.js +103 -2
  55. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +24 -3
  56. package/v2Containers/Line/Container/Text/index.js +1 -0
  57. package/v2Containers/MobilePush/Create/index.js +16 -6
  58. package/v2Containers/MobilePush/Edit/index.js +16 -6
  59. package/v2Containers/MobilePushNew/index.js +33 -2
  60. package/v2Containers/Rcs/index.js +37 -12
  61. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +667 -16
  62. package/v2Containers/Sms/Create/index.js +3 -35
  63. package/v2Containers/Sms/Create/messages.js +0 -4
  64. package/v2Containers/Sms/Edit/index.js +3 -33
  65. package/v2Containers/Sms/commonMethods.js +6 -6
  66. package/v2Containers/SmsTrai/Edit/index.js +47 -6
  67. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +147 -6
  68. package/v2Containers/Viber/index.js +1 -0
  69. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
  70. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
  71. package/v2Containers/WebPush/Create/index.js +2 -2
  72. package/v2Containers/WebPush/Create/utils/validation.js +2 -17
  73. package/v2Containers/WebPush/Create/utils/validation.test.js +24 -0
  74. package/v2Containers/Whatsapp/index.js +18 -10
  75. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +25849 -3524
  76. package/v2Containers/Zalo/index.js +11 -3
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Tests for DeliverySettings component (sender ID / delivery settings summary + slidebox)
3
+ * @jest-environment jsdom
4
+ */
5
+
6
+ import React from 'react';
7
+ import { render, screen, fireEvent } from '@testing-library/react';
8
+ import { IntlProvider } from 'react-intl';
9
+ import DeliverySettings from '../../DeliverySettings';
10
+ import { CHANNELS } from '../../constants';
11
+
12
+ jest.mock('../../DeliverySettings/DeliverySettings.scss', () => ({}));
13
+
14
+ jest.mock('@capillarytech/cap-ui-library', () => ({
15
+ CapRow: ({ children, className, ...rest }) => <div className={className} data-testid="cap-row" {...rest}>{children}</div>,
16
+ CapHeading: ({ children }) => <div data-testid="cap-heading">{children}</div>,
17
+ CapIcon: ({ onClick, className, 'data-testid': testId }) => <button type="button" onClick={onClick} className={className} data-testid={testId || 'cap-icon'} aria-label="edit" />,
18
+ CapLabel: ({ children, type }) => <span data-type={type}>{children}</span>,
19
+ CapSlideBox: ({ show, content, handleClose }) => (show ? (
20
+ <div data-testid="cap-slidebox">
21
+ <button type="button" onClick={handleClose} data-testid="slidebox-close">Close</button>
22
+ {content}
23
+ </div>
24
+ ) : null),
25
+ }));
26
+
27
+ const mockModifyDeliverySettings = jest.fn();
28
+ jest.mock('../../DeliverySettings/ModifyDeliverySettings', () => function MockModifyDeliverySettings(props) {
29
+ mockModifyDeliverySettings(props);
30
+ return (
31
+ <div data-testid="modify-delivery-settings">
32
+ <button type="button" onClick={() => props.onSaveDeliverySettings({ domainId: 1 })} data-testid="modify-done">Done</button>
33
+ <button type="button" onClick={props.onClose} data-testid="modify-close">Cancel</button>
34
+ </div>
35
+ );
36
+ });
37
+
38
+ const defaultFormatMessage = (msg) => msg?.defaultMessage || msg?.id || '';
39
+
40
+ describe('DeliverySettings', () => {
41
+ const defaultProps = {
42
+ channel: CHANNELS.SMS,
43
+ deliverySettings: {},
44
+ senderDetailsOptions: [],
45
+ wecrmAccounts: [],
46
+ onSaveDeliverySettings: jest.fn(),
47
+ isLoadingSenderDetails: false,
48
+ formatMessage: defaultFormatMessage,
49
+ whatsappAccountFromForm: undefined,
50
+ };
51
+
52
+ beforeEach(() => {
53
+ jest.clearAllMocks();
54
+ });
55
+
56
+ describe('channel visibility', () => {
57
+ it('should return null when channel is not in CHANNELS_WITH_DELIVERY_SETTINGS', () => {
58
+ const { container } = render(
59
+ <DeliverySettings {...defaultProps} channel="INAPP" />
60
+ );
61
+ expect(container.firstChild).toBeNull();
62
+ });
63
+
64
+ it('should render when channel is SMS', () => {
65
+ render(<DeliverySettings {...defaultProps} channel={CHANNELS.SMS} />);
66
+ expect(screen.getByTestId('cap-heading')).toBeTruthy();
67
+ });
68
+
69
+ it('should render when channel is EMAIL', () => {
70
+ render(<DeliverySettings {...defaultProps} channel={CHANNELS.EMAIL} />);
71
+ expect(screen.getByTestId('cap-heading')).toBeTruthy();
72
+ });
73
+
74
+ it('should render when channel is WHATSAPP', () => {
75
+ render(<DeliverySettings {...defaultProps} channel={CHANNELS.WHATSAPP} />);
76
+ expect(screen.getByTestId('cap-heading')).toBeTruthy();
77
+ });
78
+ });
79
+
80
+ describe('summary display', () => {
81
+ it('should show not configured when no delivery values for SMS', () => {
82
+ render(<DeliverySettings {...defaultProps} channel={CHANNELS.SMS} />);
83
+ expect(screen.getByText('Not configured')).toBeTruthy();
84
+ });
85
+
86
+ it('should show summary values for SMS when deliverySettings and senderDetailsOptions match', () => {
87
+ const senderDetailsOptions = [{ domainId: 1, domainName: 'SMS Domain' }];
88
+ const deliverySettings = { domainId: 1, gsmSenderId: 'SENDER1' };
89
+ render(
90
+ <DeliverySettings
91
+ {...defaultProps}
92
+ channel={CHANNELS.SMS}
93
+ deliverySettings={deliverySettings}
94
+ senderDetailsOptions={senderDetailsOptions}
95
+ />
96
+ );
97
+ expect(screen.getAllByText(/SMS Domain/).length).toBeGreaterThan(0);
98
+ expect(screen.getAllByText(/SENDER1/).length).toBeGreaterThan(0);
99
+ });
100
+
101
+ it('should show not configured for EMAIL when empty', () => {
102
+ render(<DeliverySettings {...defaultProps} channel={CHANNELS.EMAIL} />);
103
+ expect(screen.getByText('Not configured')).toBeTruthy();
104
+ });
105
+
106
+ it('should show summary for EMAIL when has domain and sender', () => {
107
+ const senderDetailsOptions = [{ domainId: 2, domainName: 'Email Domain' }];
108
+ const deliverySettings = {
109
+ domainId: 2,
110
+ senderEmail: 'noreply@test.com',
111
+ senderLabel: 'Test',
112
+ senderReplyTo: 'reply@test.com',
113
+ };
114
+ render(
115
+ <DeliverySettings
116
+ {...defaultProps}
117
+ channel={CHANNELS.EMAIL}
118
+ deliverySettings={deliverySettings}
119
+ senderDetailsOptions={senderDetailsOptions}
120
+ />
121
+ );
122
+ expect(screen.getAllByText(/Email Domain/).length).toBeGreaterThan(0);
123
+ expect(screen.getAllByText(/noreply@test\.com/).length).toBeGreaterThan(0);
124
+ });
125
+
126
+ it('should show summary for WHATSAPP when has account and sender', () => {
127
+ const wecrmAccounts = [{ name: 'WABA One', sourceAccountIdentifier: 'waba-1' }];
128
+ const deliverySettings = {
129
+ sourceAccountIdentifier: 'waba-1',
130
+ senderMobNum: '+1234567890',
131
+ };
132
+ render(
133
+ <DeliverySettings
134
+ {...defaultProps}
135
+ channel={CHANNELS.WHATSAPP}
136
+ deliverySettings={deliverySettings}
137
+ wecrmAccounts={wecrmAccounts}
138
+ />
139
+ );
140
+ expect(screen.getAllByText(/WABA One/).length).toBeGreaterThan(0);
141
+ expect(screen.getAllByText(/\+1234567890/).length).toBeGreaterThan(0);
142
+ });
143
+ });
144
+
145
+ describe('edit and slidebox', () => {
146
+ it('should open slidebox when edit icon is clicked', () => {
147
+ render(<DeliverySettings {...defaultProps} channel={CHANNELS.SMS} />);
148
+ expect(screen.queryByTestId('cap-slidebox')).toBeNull();
149
+ fireEvent.click(screen.getByTestId('delivery-settings-edit'));
150
+ expect(screen.getByTestId('cap-slidebox')).toBeTruthy();
151
+ expect(screen.getByTestId('modify-delivery-settings')).toBeTruthy();
152
+ });
153
+
154
+ it('should pass correct props to ModifyDeliverySettings', () => {
155
+ render(<DeliverySettings {...defaultProps} channel={CHANNELS.SMS} />);
156
+ fireEvent.click(screen.getByTestId('delivery-settings-edit'));
157
+ expect(mockModifyDeliverySettings).toHaveBeenCalledWith(
158
+ expect.objectContaining({
159
+ channel: CHANNELS.SMS,
160
+ deliverySettings: {},
161
+ senderDetailsOptions: [],
162
+ wecrmAccounts: [],
163
+ isLoading: false,
164
+ whatsappAccountFromForm: undefined,
165
+ })
166
+ );
167
+ });
168
+
169
+ it('should call onSaveDeliverySettings and close slidebox when Done is clicked', () => {
170
+ const onSave = jest.fn();
171
+ render(
172
+ <DeliverySettings
173
+ {...defaultProps}
174
+ channel={CHANNELS.SMS}
175
+ onSaveDeliverySettings={onSave}
176
+ />
177
+ );
178
+ fireEvent.click(screen.getByTestId('delivery-settings-edit'));
179
+ fireEvent.click(screen.getByTestId('modify-done'));
180
+ expect(onSave).toHaveBeenCalledWith({ domainId: 1 });
181
+ expect(screen.queryByTestId('cap-slidebox')).toBeNull();
182
+ });
183
+
184
+ it('should pass whatsappAccountFromForm to ModifyDeliverySettings', () => {
185
+ render(
186
+ <DeliverySettings
187
+ {...defaultProps}
188
+ channel={CHANNELS.WHATSAPP}
189
+ whatsappAccountFromForm={{ accountName: 'My WABA' }}
190
+ />
191
+ );
192
+ fireEvent.click(screen.getByTestId('delivery-settings-edit'));
193
+ expect(mockModifyDeliverySettings).toHaveBeenCalledWith(
194
+ expect.objectContaining({
195
+ whatsappAccountFromForm: { accountName: 'My WABA' },
196
+ })
197
+ );
198
+ });
199
+ });
200
+ });
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Tests for parseSenderDetailsResponse
3
+ * Covers sender ID / delivery settings response parsing for SMS, EMAIL, WHATSAPP
4
+ */
5
+
6
+ import { parseSenderDetailsResponse } from '../../../DeliverySettings/utils/parseSenderDetailsResponse';
7
+
8
+ describe('parseSenderDetailsResponse', () => {
9
+ describe('when entity is missing or null', () => {
10
+ it('should return empty domains when response is null', () => {
11
+ expect(parseSenderDetailsResponse('SMS', null)).toEqual({ domains: [] });
12
+ });
13
+
14
+ it('should return empty domains when response is undefined', () => {
15
+ expect(parseSenderDetailsResponse('SMS', undefined)).toEqual({ domains: [] });
16
+ });
17
+
18
+ it('should return empty domains when entity is missing', () => {
19
+ expect(parseSenderDetailsResponse('SMS', {})).toEqual({ domains: [] });
20
+ });
21
+ });
22
+
23
+ describe('when entity is object with channel key', () => {
24
+ it('should parse SMS channel entity array', () => {
25
+ const response = {
26
+ entity: {
27
+ SMS: [
28
+ {
29
+ id: 10,
30
+ priority: 1,
31
+ domainProperties: {
32
+ domainName: 'SMS Domain 1',
33
+ id: 100,
34
+ contactInfo: [
35
+ { type: 'gsm_sender_id', valid: true, value: 'GSM1', default: true },
36
+ { type: 'cdma_sender_id', valid: true, value: 'CDMA1' },
37
+ ],
38
+ connectionProperties: {},
39
+ },
40
+ },
41
+ ],
42
+ },
43
+ };
44
+ const result = parseSenderDetailsResponse('SMS', response);
45
+ expect(result.domains).toHaveLength(1);
46
+ expect(result.domains[0]).toMatchObject({
47
+ dgmId: 10,
48
+ domainName: 'SMS Domain 1',
49
+ domainId: 100,
50
+ priority: 1,
51
+ });
52
+ expect(result.domains[0].gsmSenders).toHaveLength(1);
53
+ expect(result.domains[0].gsmSenders[0].value).toBe('GSM1');
54
+ expect(result.domains[0].cdmaSenders).toHaveLength(1);
55
+ expect(result.domains[0].cdmaSenders[0].value).toBe('CDMA1');
56
+ });
57
+
58
+ it('should parse EMAIL channel entity array', () => {
59
+ const response = {
60
+ entity: {
61
+ EMAIL: [
62
+ {
63
+ id: 20,
64
+ priority: 0,
65
+ domainProperties: {
66
+ domainName: 'Email Domain',
67
+ id: 200,
68
+ contactInfo: [
69
+ { type: 'sender_id', valid: true, value: 'noreply@example.com' },
70
+ { type: 'reply_to_id', valid: true, value: 'reply@example.com' },
71
+ ],
72
+ },
73
+ },
74
+ ],
75
+ },
76
+ };
77
+ const result = parseSenderDetailsResponse('EMAIL', response);
78
+ expect(result.domains).toHaveLength(1);
79
+ expect(result.domains[0]).toMatchObject({
80
+ dgmId: 20,
81
+ domainName: 'Email Domain',
82
+ domainId: 200,
83
+ priority: 0,
84
+ });
85
+ expect(result.domains[0].emailSenders).toHaveLength(1);
86
+ expect(result.domains[0].emailSenders[0].value).toBe('noreply@example.com');
87
+ expect(result.domains[0].emailRepliers).toHaveLength(1);
88
+ expect(result.domains[0].emailRepliers[0].value).toBe('reply@example.com');
89
+ });
90
+
91
+ it('should parse WHATSAPP channel with sourceAccountIdentifier', () => {
92
+ const response = {
93
+ entity: {
94
+ WHATSAPP: [
95
+ {
96
+ id: 30,
97
+ priority: 0,
98
+ domainProperties: {
99
+ domainName: 'WABA Domain',
100
+ id: 300,
101
+ contactInfo: [],
102
+ connectionProperties: {
103
+ sourceAccountIdentifier: 'waba-123',
104
+ },
105
+ },
106
+ },
107
+ ],
108
+ },
109
+ };
110
+ const result = parseSenderDetailsResponse('WHATSAPP', response);
111
+ expect(result.domains).toHaveLength(1);
112
+ expect(result.domains[0].sourceAccountIdentifier).toBe('waba-123');
113
+ expect(result.domains[0].gsmSenders).toEqual([]);
114
+ expect(result.domains[0].cdmaSenders).toEqual([]);
115
+ });
116
+ });
117
+
118
+ describe('when entity is direct array', () => {
119
+ it('should use entity as channelSenderDetails when entity is array', () => {
120
+ const response = {
121
+ entity: [
122
+ {
123
+ id: 1,
124
+ priority: 0,
125
+ domainProperties: { domainName: 'Direct Domain', id: 1 },
126
+ },
127
+ ],
128
+ };
129
+ const result = parseSenderDetailsResponse('SMS', response);
130
+ expect(result.domains).toHaveLength(1);
131
+ expect(result.domains[0].domainName).toBe('Direct Domain');
132
+ });
133
+ });
134
+
135
+ describe('filtering and sorting', () => {
136
+ it('should filter contactInfo by type and valid', () => {
137
+ const response = {
138
+ entity: {
139
+ SMS: [
140
+ {
141
+ id: 1,
142
+ priority: 0,
143
+ domainProperties: {
144
+ domainName: 'D1',
145
+ id: 1,
146
+ contactInfo: [
147
+ { type: 'gsm_sender_id', valid: true, value: 'A' },
148
+ { type: 'gsm_sender_id', valid: false, value: 'B' },
149
+ { type: 'other', valid: true, value: 'C' },
150
+ ],
151
+ },
152
+ },
153
+ ],
154
+ },
155
+ };
156
+ const result = parseSenderDetailsResponse('SMS', response);
157
+ expect(result.domains[0].gsmSenders).toHaveLength(1);
158
+ expect(result.domains[0].gsmSenders[0].value).toBe('A');
159
+ });
160
+
161
+ it('should sort domains by priority', () => {
162
+ const response = {
163
+ entity: {
164
+ SMS: [
165
+ { id: 1, priority: 2, domainProperties: { domainName: 'Second', id: 1 } },
166
+ { id: 2, priority: 0, domainProperties: { domainName: 'First', id: 2 } },
167
+ ],
168
+ },
169
+ };
170
+ const result = parseSenderDetailsResponse('SMS', response);
171
+ expect(result.domains[0].domainName).toBe('First');
172
+ expect(result.domains[1].domainName).toBe('Second');
173
+ });
174
+
175
+ it('should dedupe by domainName keeping first occurrence', () => {
176
+ const response = {
177
+ entity: {
178
+ SMS: [
179
+ { id: 1, priority: 0, domainProperties: { domainName: 'Same', id: 1 } },
180
+ { id: 2, priority: 1, domainProperties: { domainName: 'Same', id: 2 } },
181
+ ],
182
+ },
183
+ };
184
+ const result = parseSenderDetailsResponse('SMS', response);
185
+ expect(result.domains).toHaveLength(1);
186
+ expect(result.domains[0].domainId).toBe(1);
187
+ });
188
+ });
189
+
190
+ describe('edge cases', () => {
191
+ it('should return empty domains when channel key has no array', () => {
192
+ const response = { entity: { SMS: null } };
193
+ expect(parseSenderDetailsResponse('SMS', response)).toEqual({ domains: [] });
194
+ });
195
+
196
+ it('should return empty domains when channel key is missing and entity is not array', () => {
197
+ const response = { entity: { EMAIL: [] } };
198
+ expect(parseSenderDetailsResponse('SMS', response)).toEqual({ domains: [] });
199
+ });
200
+
201
+ it('should handle missing domainProperties with defaults', () => {
202
+ const response = {
203
+ entity: {
204
+ SMS: [{ id: 1, priority: 0 }],
205
+ },
206
+ };
207
+ const result = parseSenderDetailsResponse('SMS', response);
208
+ expect(result.domains).toHaveLength(1);
209
+ expect(result.domains[0].domainId).toBe(-1);
210
+ expect(result.domains[0].domainName).toBeUndefined();
211
+ expect(result.domains[0].gsmSenders).toEqual([]);
212
+ expect(result.domains[0].cdmaSenders).toEqual([]);
213
+ });
214
+
215
+ it('should use wabaId when sourceAccountIdentifier missing for WHATSAPP', () => {
216
+ const response = {
217
+ entity: {
218
+ WHATSAPP: [
219
+ {
220
+ id: 1,
221
+ priority: 0,
222
+ domainProperties: {
223
+ domainName: 'W',
224
+ id: 1,
225
+ connectionProperties: { wabaId: 'waba-456' },
226
+ },
227
+ },
228
+ ],
229
+ },
230
+ };
231
+ const result = parseSenderDetailsResponse('WHATSAPP', response);
232
+ expect(result.domains[0].sourceAccountIdentifier).toBe('waba-456');
233
+ });
234
+ });
235
+ });
@@ -2,6 +2,7 @@
2
2
  * Tests for SendTestMessage Component
3
3
  *
4
4
  * Tests the component that handles sending test messages
5
+ * @jest-environment jsdom
5
6
  */
6
7
 
7
8
  import React from 'react';
@@ -11,8 +12,32 @@ import {
11
12
  import { IntlProvider } from 'react-intl';
12
13
  import PropTypes from 'prop-types';
13
14
  import isEmpty from 'lodash/isEmpty';
15
+ // Mock cap-ui-library so SendTestMessage can load (Jest hoists mocks)
16
+ jest.mock('@capillarytech/cap-ui-library/CapRow', () => ({ children, ...rest }) => <div {...rest}>{children}</div>);
17
+ jest.mock('@capillarytech/cap-ui-library/CapButton', () => ({ children, ...rest }) => <button type="button" {...rest}>{children}</button>);
18
+ jest.mock('@capillarytech/cap-ui-library/CapHeader', () => ({ title, description }) => <div><span>{title}</span>{description}</div>);
19
+ jest.mock('@capillarytech/cap-ui-library/CapTreeSelect', () => ({ treeData, onChange, value, placeholder }) => (
20
+ <div data-testid="cap-tree-select"><input onChange={(e) => onChange && onChange(e.target.value)} placeholder={placeholder} /></div>
21
+ ));
22
+
14
23
  import SendTestMessage from '../SendTestMessage';
15
24
 
25
+ // Mock DeliverySettings to assert props
26
+ jest.mock('../DeliverySettings', () => function MockDeliverySettings(props) {
27
+ return (
28
+ <div data-testid="delivery-settings" data-props={JSON.stringify({
29
+ channel: props.channel,
30
+ hasDeliverySettings: !!props.deliverySettings,
31
+ senderDetailsLength: (props.senderDetailsOptions || []).length,
32
+ wecrmAccountsLength: (props.wecrmAccounts || []).length,
33
+ hasOnSave: typeof props.onSaveDeliverySettings === 'function',
34
+ isLoadingSenderDetails: props.isLoadingSenderDetails,
35
+ whatsappAccountFromForm: props.whatsappAccountFromForm,
36
+ })}
37
+ />
38
+ );
39
+ });
40
+
16
41
  // Mock CapStepsAccordian to always render content expanded
17
42
  jest.mock('@capillarytech/cap-ui-library/CapStepsAccordian', () => {
18
43
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
@@ -100,6 +125,12 @@ describe('SendTestMessage', () => {
100
125
  },
101
126
  isSendingTestMessage: false,
102
127
  formatMessage: jest.fn((msg) => msg.defaultMessage || msg.id),
128
+ channel: 'EMAIL',
129
+ deliverySettings: {},
130
+ senderDetailsOptions: [],
131
+ wecrmAccounts: [],
132
+ onSaveDeliverySettings: jest.fn(),
133
+ isLoadingSenderDetails: false,
103
134
  };
104
135
 
105
136
  beforeEach(() => {
@@ -162,6 +193,102 @@ describe('SendTestMessage', () => {
162
193
  });
163
194
  });
164
195
 
196
+ describe('DeliverySettings (sender ID / delivery settings)', () => {
197
+ it('should render DeliverySettings when channel is SMS', () => {
198
+ render(
199
+ <TestWrapper>
200
+ <SendTestMessage {...defaultProps} channel="SMS" />
201
+ </TestWrapper>
202
+ );
203
+ const el = screen.getByTestId('delivery-settings');
204
+ expect(el).toBeTruthy();
205
+ const data = JSON.parse(el.getAttribute('data-props'));
206
+ expect(data.channel).toBe('SMS');
207
+ expect(data.hasOnSave).toBe(true);
208
+ });
209
+
210
+ it('should render DeliverySettings when channel is EMAIL', () => {
211
+ render(
212
+ <TestWrapper>
213
+ <SendTestMessage {...defaultProps} channel="EMAIL" />
214
+ </TestWrapper>
215
+ );
216
+ expect(screen.getByTestId('delivery-settings')).toBeTruthy();
217
+ });
218
+
219
+ it('should render DeliverySettings when channel is WHATSAPP', () => {
220
+ render(
221
+ <TestWrapper>
222
+ <SendTestMessage {...defaultProps} channel="WHATSAPP" />
223
+ </TestWrapper>
224
+ );
225
+ expect(screen.getByTestId('delivery-settings')).toBeTruthy();
226
+ });
227
+
228
+ it('should not render DeliverySettings when channel is INAPP', () => {
229
+ render(
230
+ <TestWrapper>
231
+ <SendTestMessage {...defaultProps} channel="INAPP" />
232
+ </TestWrapper>
233
+ );
234
+ expect(screen.queryByTestId('delivery-settings')).toBeNull();
235
+ });
236
+
237
+ it('should pass whatsappAccountFromForm when channel is WHATSAPP and formData has accountName', () => {
238
+ render(
239
+ <TestWrapper>
240
+ <SendTestMessage
241
+ {...defaultProps}
242
+ channel="WHATSAPP"
243
+ formData={{ ...defaultProps.formData, accountName: 'My WABA' }}
244
+ />
245
+ </TestWrapper>
246
+ );
247
+ const el = screen.getByTestId('delivery-settings');
248
+ const data = JSON.parse(el.getAttribute('data-props'));
249
+ expect(data.whatsappAccountFromForm).toEqual({ accountName: 'My WABA' });
250
+ });
251
+
252
+ it('should pass whatsappAccountFromForm undefined when channel is WHATSAPP and formData has no accountName', () => {
253
+ render(
254
+ <TestWrapper>
255
+ <SendTestMessage
256
+ {...defaultProps}
257
+ channel="WHATSAPP"
258
+ formData={{ ...defaultProps.formData, accountName: undefined }}
259
+ />
260
+ </TestWrapper>
261
+ );
262
+ const el = screen.getByTestId('delivery-settings');
263
+ const data = JSON.parse(el.getAttribute('data-props'));
264
+ expect(data.whatsappAccountFromForm).toBeUndefined();
265
+ });
266
+
267
+ it('should pass delivery props to DeliverySettings', () => {
268
+ const onSave = jest.fn();
269
+ render(
270
+ <TestWrapper>
271
+ <SendTestMessage
272
+ {...defaultProps}
273
+ channel="SMS"
274
+ deliverySettings={{ domainId: 1 }}
275
+ senderDetailsOptions={[{ domainId: 1, domainName: 'SMS Dom' }]}
276
+ wecrmAccounts={[]}
277
+ onSaveDeliverySettings={onSave}
278
+ isLoadingSenderDetails={true}
279
+ />
280
+ </TestWrapper>
281
+ );
282
+ const el = screen.getByTestId('delivery-settings');
283
+ const data = JSON.parse(el.getAttribute('data-props'));
284
+ expect(data.hasDeliverySettings).toBe(true);
285
+ expect(data.senderDetailsLength).toBe(1);
286
+ expect(data.wecrmAccountsLength).toBe(0);
287
+ expect(data.hasOnSave).toBe(true);
288
+ expect(data.isLoadingSenderDetails).toBe(true);
289
+ });
290
+ });
291
+
165
292
  describe('Loading States', () => {
166
293
  it('should show loading when fetching test customers', () => {
167
294
  const props = {
@@ -17,6 +17,8 @@ import {
17
17
  getPrefilledValuesRequested,
18
18
  clearPrefilledValues,
19
19
  clearPreviewErrors,
20
+ getSenderDetailsRequested,
21
+ getWeCrmAccountsRequested,
20
22
  } from '../actions';
21
23
 
22
24
  import {
@@ -32,6 +34,8 @@ import {
32
34
  GET_PREFILLED_VALUES_REQUESTED,
33
35
  CLEAR_PREFILLED_VALUES,
34
36
  CLEAR_PREVIEW_ERRORS,
37
+ GET_SENDER_DETAILS_REQUESTED,
38
+ GET_WECRM_ACCOUNTS_REQUESTED,
35
39
  } from '../constants';
36
40
 
37
41
  describe('CommonTestAndPreview Actions', () => {
@@ -321,4 +325,50 @@ describe('CommonTestAndPreview Actions', () => {
321
325
  expect(clearPreviewErrors()).toEqual(expectedAction);
322
326
  });
323
327
  });
328
+
329
+ describe('getSenderDetailsRequested', () => {
330
+ it('should create an action to request sender details with channel and orgUnitId', () => {
331
+ const payload = { channel: 'SMS', orgUnitId: 123 };
332
+ const expectedAction = {
333
+ type: GET_SENDER_DETAILS_REQUESTED,
334
+ payload,
335
+ };
336
+ expect(getSenderDetailsRequested(payload)).toEqual(expectedAction);
337
+ });
338
+
339
+ it('should handle EMAIL channel', () => {
340
+ const payload = { channel: 'EMAIL', orgUnitId: -1 };
341
+ expect(getSenderDetailsRequested(payload)).toEqual({
342
+ type: GET_SENDER_DETAILS_REQUESTED,
343
+ payload,
344
+ });
345
+ });
346
+
347
+ it('should handle WHATSAPP channel', () => {
348
+ const payload = { channel: 'WHATSAPP', orgUnitId: 456 };
349
+ expect(getSenderDetailsRequested(payload)).toEqual({
350
+ type: GET_SENDER_DETAILS_REQUESTED,
351
+ payload,
352
+ });
353
+ });
354
+ });
355
+
356
+ describe('getWeCrmAccountsRequested', () => {
357
+ it('should create an action to request WeCRM accounts with sourceName', () => {
358
+ const payload = { sourceName: 'WHATSAPP' };
359
+ const expectedAction = {
360
+ type: GET_WECRM_ACCOUNTS_REQUESTED,
361
+ payload,
362
+ };
363
+ expect(getWeCrmAccountsRequested(payload)).toEqual(expectedAction);
364
+ });
365
+
366
+ it('should handle empty payload', () => {
367
+ const payload = {};
368
+ expect(getWeCrmAccountsRequested(payload)).toEqual({
369
+ type: GET_WECRM_ACCOUNTS_REQUESTED,
370
+ payload: {},
371
+ });
372
+ });
373
+ });
324
374
  });
@@ -30,6 +30,12 @@ import {
30
30
  GET_PREFILLED_VALUES_REQUESTED,
31
31
  GET_PREFILLED_VALUES_SUCCESS,
32
32
  GET_PREFILLED_VALUES_FAILURE,
33
+ GET_SENDER_DETAILS_REQUESTED,
34
+ GET_SENDER_DETAILS_SUCCESS,
35
+ GET_SENDER_DETAILS_FAILURE,
36
+ GET_WECRM_ACCOUNTS_REQUESTED,
37
+ GET_WECRM_ACCOUNTS_SUCCESS,
38
+ GET_WECRM_ACCOUNTS_FAILURE,
33
39
  CLEAR_CUSTOMER_SEARCH_STATE,
34
40
  CLEAR_SEARCH_RESULTS,
35
41
  CLEAR_PREFILLED_VALUES,
@@ -137,6 +143,18 @@ describe('CommonTestAndPreview Constants', () => {
137
143
  expect(GET_PREFILLED_VALUES_FAILURE).toBe('app/CommonTestAndPreview/GET_PREFILLED_VALUES_FAILURE');
138
144
  });
139
145
 
146
+ it('should export all get sender details action types', () => {
147
+ expect(GET_SENDER_DETAILS_REQUESTED).toBe('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED');
148
+ expect(GET_SENDER_DETAILS_SUCCESS).toBe('app/CommonTestAndPreview/GET_SENDER_DETAILS_SUCCESS');
149
+ expect(GET_SENDER_DETAILS_FAILURE).toBe('app/CommonTestAndPreview/GET_SENDER_DETAILS_FAILURE');
150
+ });
151
+
152
+ it('should export all get wecrm accounts action types', () => {
153
+ expect(GET_WECRM_ACCOUNTS_REQUESTED).toBe('app/CommonTestAndPreview/GET_WECRM_ACCOUNTS_REQUESTED');
154
+ expect(GET_WECRM_ACCOUNTS_SUCCESS).toBe('app/CommonTestAndPreview/GET_WECRM_ACCOUNTS_SUCCESS');
155
+ expect(GET_WECRM_ACCOUNTS_FAILURE).toBe('app/CommonTestAndPreview/GET_WECRM_ACCOUNTS_FAILURE');
156
+ });
157
+
140
158
  it('should export all clear action types', () => {
141
159
  expect(CLEAR_CUSTOMER_SEARCH_STATE).toBe('app/CommonTestAndPreview/CLEAR_CUSTOMER_SEARCH_STATE');
142
160
  expect(CLEAR_SEARCH_RESULTS).toBe('app/CommonTestAndPreview/CLEAR_SEARCH_RESULTS');