@capillarytech/creatives-library 9.0.56-alpha.3 → 9.0.56-alpha.4

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 (26) hide show
  1. package/package.json +1 -1
  2. package/v2Components/CommonTestAndPreview/actions.js +13 -0
  3. package/v2Components/CommonTestAndPreview/constants.js +6 -0
  4. package/v2Components/CommonTestAndPreview/index.js +22 -20
  5. package/v2Components/CommonTestAndPreview/reducer.js +20 -0
  6. package/v2Components/CommonTestAndPreview/sagas.js +28 -0
  7. package/v2Components/CommonTestAndPreview/selectors.js +6 -0
  8. package/v2Components/CommonTestAndPreview/tests/actions.test.js +15 -0
  9. package/v2Components/CommonTestAndPreview/tests/index.test.js +101 -0
  10. package/v2Components/CommonTestAndPreview/tests/reducer.test.js +41 -0
  11. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +84 -0
  12. package/v2Components/CommonTestAndPreview/tests/selectors.test.js +12 -0
  13. package/v2Components/TestAndPreviewSlidebox/index.js +3 -0
  14. package/v2Containers/CommunicationFlow/CommunicationFlow.js +26 -21
  15. package/v2Containers/CommunicationFlow/CommunicationFlow.scss +29 -1
  16. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +16 -3
  17. package/v2Containers/CommunicationFlow/constants.js +2 -0
  18. package/v2Containers/CommunicationFlow/index.js +1 -1
  19. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +2 -22
  20. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +4 -0
  21. package/v2Containers/CreativesContainer/index.js +0 -1
  22. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +79 -7
  23. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +18 -0
  24. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +17 -12
  25. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +5 -0
  26. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +204 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "9.0.56-alpha.3",
4
+ "version": "9.0.56-alpha.4",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -10,6 +10,7 @@ import {
10
10
  EXTRACT_TAGS_REQUESTED,
11
11
  UPDATE_PREVIEW_REQUESTED,
12
12
  SEND_TEST_MESSAGE_REQUESTED,
13
+ SEND_CCS_TEST_MESSAGE_REQUESTED,
13
14
  CLEAR_CUSTOMER_SEARCH_STATE,
14
15
  GET_TEST_CUSTOMERS_REQUESTED,
15
16
  GET_TEST_GROUPS_REQUESTED,
@@ -65,6 +66,18 @@ export const sendTestMessageRequested = (payload, callback) => ({
65
66
  callback,
66
67
  });
67
68
 
69
+ /**
70
+ * notify/ui only — send a test message through CCS's send/transaction endpoint
71
+ * against a real CommDefinition, instead of the legacy createMessageMeta/sendTestMessage flow.
72
+ * @param {Object} payload - { commDefinitionId|referenceId, uniqueKey, isTest, recipient }
73
+ * @param {Function} callback - Success/error callback
74
+ */
75
+ export const sendCcsTestMessageRequested = (payload, callback) => ({
76
+ type: SEND_CCS_TEST_MESSAGE_REQUESTED,
77
+ payload,
78
+ callback,
79
+ });
80
+
68
81
  /**
69
82
  * Clear all customer search state
70
83
  */
@@ -29,6 +29,11 @@ export const SEND_TEST_MESSAGE_REQUESTED = 'app/CommonTestAndPreview/SEND_TEST_M
29
29
  export const SEND_TEST_MESSAGE_SUCCESS = 'app/CommonTestAndPreview/SEND_TEST_MESSAGE_SUCCESS';
30
30
  export const SEND_TEST_MESSAGE_FAILURE = 'app/CommonTestAndPreview/SEND_TEST_MESSAGE_FAILURE';
31
31
 
32
+ // Send CCS Test Message (notify/ui — send/transaction against a real CommDefinition)
33
+ export const SEND_CCS_TEST_MESSAGE_REQUESTED = 'app/CommonTestAndPreview/SEND_CCS_TEST_MESSAGE_REQUESTED';
34
+ export const SEND_CCS_TEST_MESSAGE_SUCCESS = 'app/CommonTestAndPreview/SEND_CCS_TEST_MESSAGE_SUCCESS';
35
+ export const SEND_CCS_TEST_MESSAGE_FAILURE = 'app/CommonTestAndPreview/SEND_CCS_TEST_MESSAGE_FAILURE';
36
+
32
37
  // Test Customers
33
38
  export const GET_TEST_CUSTOMERS_REQUESTED = 'app/CommonTestAndPreview/GET_TEST_CUSTOMERS_REQUESTED';
34
39
  export const GET_TEST_CUSTOMERS_SUCCESS = 'app/CommonTestAndPreview/GET_TEST_CUSTOMERS_SUCCESS';
@@ -292,6 +297,7 @@ export const ERROR_MESSAGES = {
292
297
  FAILED_TO_EXTRACT_TAGS: 'Failed to extract tags',
293
298
  FAILED_TO_UPDATE_PREVIEW: 'Failed to update preview',
294
299
  FAILED_TO_SEND_TEST_EMAIL: 'Failed to send test email',
300
+ FAILED_TO_SEND_CCS_TEST_MESSAGE: 'Failed to send test message',
295
301
  PROFILE_IS_EMPTY: 'Profile is empty',
296
302
  NO_TEST_CUSTOMERS_FOUND: 'No test customers found',
297
303
  FAILED_TO_FETCH_TEST_CUSTOMERS: 'Failed to fetch test customers',
@@ -200,6 +200,7 @@ const CommonTestAndPreview = (props) => {
200
200
  messageMetaConfigId,
201
201
  prefilledValues,
202
202
  isSendingTestMessage,
203
+ isSendingCcsTestMessage,
203
204
  updatePreviewError,
204
205
  updatePreviewErrors,
205
206
  fetchPrefilledValuesError,
@@ -233,7 +234,6 @@ const CommonTestAndPreview = (props) => {
233
234
  const [smsFallbackOptionalTags, setSmsFallbackOptionalTags] = useState([]);
234
235
  const [isExtractingSmsFallbackTags, setIsExtractingSmsFallbackTags] = useState(false);
235
236
  const [customValues, setCustomValues] = useState({});
236
- const [isSendingCcsTest, setIsSendingCcsTest] = useState(false);
237
237
  const previewCustomValuesRef = useRef({});
238
238
  const [showJSON, setShowJSON] = useState(false);
239
239
  const [tagsExtracted, setTagsExtracted] = useState(false);
@@ -3630,7 +3630,9 @@ const CommonTestAndPreview = (props) => {
3630
3630
  */
3631
3631
  // notify/ui: send the test through CCS's own send/transaction endpoint against the alert's
3632
3632
  // real CommDefinition, instead of the legacy createMessageMeta/sendTestMessage flow below.
3633
- const handleCcsSendTestMessage = async () => {
3633
+ // Dispatched via the same action/saga pattern as every other API call in this component,
3634
+ // rather than calling Api.sendTransactionalComm directly.
3635
+ const handleCcsSendTestMessage = () => {
3634
3636
  const allUserIds = [];
3635
3637
  selectedTestEntities.forEach((entityId) => {
3636
3638
  const group = testGroups.find((testGroup) => testEntityIdsEqual(testGroup.groupId, entityId));
@@ -3643,9 +3645,8 @@ const CommonTestAndPreview = (props) => {
3643
3645
  const uniqueUserIds = [...new Set(allUserIds)];
3644
3646
  const { commDefinitionId, referenceId } = ccsSendTransaction;
3645
3647
 
3646
- setIsSendingCcsTest(true);
3647
- try {
3648
- const res = await Api.sendTransactionalComm({
3648
+ actions.sendCcsTestMessageRequested(
3649
+ {
3649
3650
  ...(commDefinitionId ? { commDefinitionId } : { referenceId }),
3650
3651
  uniqueKey: `test_${Date.now()}`,
3651
3652
  isTest: true,
@@ -3653,20 +3654,19 @@ const CommonTestAndPreview = (props) => {
3653
3654
  identifiers: uniqueUserIds.map((userId) => ({ type: 'USER_ID', value: String(userId) })),
3654
3655
  tagValues: customValues,
3655
3656
  },
3656
- });
3657
- if (res?.response?.success === false) {
3658
- throw new Error(res?.response?.errors?.[0]?.message || 'Failed to send test message');
3659
- }
3660
- CapNotification.success({
3661
- message: formatMessage(messages.testMessageSent),
3662
- });
3663
- } catch (error) {
3664
- CapNotification.error({
3665
- message: formatMessage(messages.testMessageFailed),
3666
- });
3667
- } finally {
3668
- setIsSendingCcsTest(false);
3669
- }
3657
+ },
3658
+ (success) => {
3659
+ if (success) {
3660
+ CapNotification.success({
3661
+ message: formatMessage(messages.testMessageSent),
3662
+ });
3663
+ } else {
3664
+ CapNotification.error({
3665
+ message: formatMessage(messages.testMessageFailed),
3666
+ });
3667
+ }
3668
+ },
3669
+ );
3670
3670
  };
3671
3671
 
3672
3672
  const handleSendTestMessage = () => {
@@ -3811,7 +3811,7 @@ const CommonTestAndPreview = (props) => {
3811
3811
  formData={formDataForSendTest}
3812
3812
  content={getCurrentContent}
3813
3813
  channel={channel}
3814
- isSendingTestMessage={isSendingTestMessage || isSendingCcsTest}
3814
+ isSendingTestMessage={isSendingTestMessage || isSendingCcsTestMessage}
3815
3815
  renderAddTestCustomerButton={renderAddTestCustomerButton}
3816
3816
  formatMessage={formatMessage}
3817
3817
  deliverySettings={testPreviewDeliverySettings[channel]}
@@ -3961,6 +3961,7 @@ CommonTestAndPreview.propTypes = {
3961
3961
  message: PropTypes.string,
3962
3962
  })),
3963
3963
  isSendingTestMessage: PropTypes.bool.isRequired,
3964
+ isSendingCcsTestMessage: PropTypes.bool,
3964
3965
  intl: PropTypes.object.isRequired,
3965
3966
  senderDetailsByChannel: PropTypes.object,
3966
3967
  wecrmAccounts: PropTypes.array,
@@ -4010,6 +4011,7 @@ CommonTestAndPreview.defaultProps = {
4010
4011
  isLoadingSenderDetails: false,
4011
4012
  orgUnitId: -1,
4012
4013
  ccsSendTransaction: null,
4014
+ isSendingCcsTestMessage: false,
4013
4015
  };
4014
4016
 
4015
4017
  // ============================================
@@ -15,6 +15,9 @@ import {
15
15
  SEND_TEST_MESSAGE_REQUESTED,
16
16
  SEND_TEST_MESSAGE_SUCCESS,
17
17
  SEND_TEST_MESSAGE_FAILURE,
18
+ SEND_CCS_TEST_MESSAGE_REQUESTED,
19
+ SEND_CCS_TEST_MESSAGE_SUCCESS,
20
+ SEND_CCS_TEST_MESSAGE_FAILURE,
18
21
  CLEAR_CUSTOMER_SEARCH_STATE,
19
22
  CLEAR_SEARCH_RESULTS,
20
23
  GET_TEST_CUSTOMERS_REQUESTED,
@@ -69,6 +72,10 @@ const initialState = fromJS({
69
72
  sendTestMessageError: null,
70
73
  testMessageResponse: null,
71
74
 
75
+ // CCS test message state (notify/ui)
76
+ isSendingCcsTestMessage: false,
77
+ sendCcsTestMessageError: null,
78
+
72
79
  tags: {
73
80
  loading: false,
74
81
  error: null,
@@ -194,6 +201,19 @@ const previewAndTestReducer = (state = initialState, action) => {
194
201
  .set('isSendingTestMessage', false)
195
202
  .set('sendTestMessageError', action.payload.error);
196
203
 
204
+ // Send CCS Test Message (notify/ui)
205
+ case SEND_CCS_TEST_MESSAGE_REQUESTED:
206
+ return state.set('isSendingCcsTestMessage', true)
207
+ .set('sendCcsTestMessageError', null);
208
+
209
+ case SEND_CCS_TEST_MESSAGE_SUCCESS:
210
+ return state.set('isSendingCcsTestMessage', false)
211
+ .set('sendCcsTestMessageError', null);
212
+
213
+ case SEND_CCS_TEST_MESSAGE_FAILURE:
214
+ return state.set('isSendingCcsTestMessage', false)
215
+ .set('sendCcsTestMessageError', action.payload.error);
216
+
197
217
  // Clear Actions
198
218
  case CLEAR_SEARCH_RESULTS:
199
219
  return state.set('customers', [])
@@ -21,6 +21,9 @@ import {
21
21
  SEND_TEST_MESSAGE_REQUESTED,
22
22
  SEND_TEST_MESSAGE_SUCCESS,
23
23
  SEND_TEST_MESSAGE_FAILURE,
24
+ SEND_CCS_TEST_MESSAGE_REQUESTED,
25
+ SEND_CCS_TEST_MESSAGE_SUCCESS,
26
+ SEND_CCS_TEST_MESSAGE_FAILURE,
24
27
  GET_TEST_CUSTOMERS_REQUESTED,
25
28
  GET_TEST_GROUPS_REQUESTED,
26
29
  GET_TEST_CUSTOMERS_SUCCESS,
@@ -144,6 +147,26 @@ export function* sendTestMessageSaga(action) {
144
147
  }
145
148
  }
146
149
 
150
+ // notify/ui: Send Test Message via CCS's send/transaction endpoint, against a real
151
+ // CommDefinition, instead of the legacy createMessageMeta/sendTestMessage flow above.
152
+ export function* sendCcsTestMessageSaga(action) {
153
+ try {
154
+ const { callback } = action;
155
+ const res = yield call(Api.sendTransactionalComm, action.payload);
156
+ if (res?.response?.success === false) {
157
+ const error = res?.response?.errors?.[0]?.message || ERROR_MESSAGES.FAILED_TO_SEND_CCS_TEST_MESSAGE;
158
+ yield put({ type: SEND_CCS_TEST_MESSAGE_FAILURE, payload: { error } });
159
+ callback(false);
160
+ } else {
161
+ yield put({ type: SEND_CCS_TEST_MESSAGE_SUCCESS });
162
+ callback(true);
163
+ }
164
+ } catch (error) {
165
+ yield put({ type: SEND_CCS_TEST_MESSAGE_FAILURE, payload: { error: error.message || ERROR_MESSAGES.NETWORK_ERROR } });
166
+ action.callback(false);
167
+ }
168
+ }
169
+
147
170
  export function* getBulkCustomerDetails({fetchedUserIds}) {
148
171
  try {
149
172
  const bulkCustomerDetails = yield call(Api.getBulkCustomerDetails, {
@@ -285,6 +308,10 @@ export function* watchSendTestMessage() {
285
308
  yield takeLatest(SEND_TEST_MESSAGE_REQUESTED, sendTestMessageSaga);
286
309
  }
287
310
 
311
+ export function* watchSendCcsTestMessage() {
312
+ yield takeLatest(SEND_CCS_TEST_MESSAGE_REQUESTED, sendCcsTestMessageSaga);
313
+ }
314
+
288
315
  export function* watchFetchTestCustomers() {
289
316
  yield takeLatest(GET_TEST_CUSTOMERS_REQUESTED, fetchTestCustomersSaga);
290
317
  }
@@ -371,6 +398,7 @@ export function* commonTestAndPreviewSaga() {
371
398
  watchExtractTags(),
372
399
  watchUpdatePreview(),
373
400
  watchSendTestMessage(),
401
+ watchSendCcsTestMessage(),
374
402
  watchFetchTestCustomers(),
375
403
  watchFetchTestGroups(),
376
404
  watchCreateMessageMeta(),
@@ -124,6 +124,11 @@ const makeSelectIsSendingTestMessage = () => createSelector(
124
124
  (substate) => substate.get('isSendingTestMessage'),
125
125
  );
126
126
 
127
+ const makeSelectIsSendingCcsTestMessage = () => createSelector(
128
+ selectCommonTestAndPreviewDomain,
129
+ (substate) => substate.get('isSendingCcsTestMessage'),
130
+ );
131
+
127
132
  const makeSelectUpdatePreviewError = () => createSelector(
128
133
  selectCommonTestAndPreviewDomain,
129
134
  (substate) => substate.get('updatePreviewError'),
@@ -212,6 +217,7 @@ export {
212
217
  makeSelectPrefilledValues,
213
218
  makeSelectTestMessageResponse,
214
219
  makeSelectIsSendingTestMessage,
220
+ makeSelectIsSendingCcsTestMessage,
215
221
  makeSelectUpdatePreviewError,
216
222
  makeSelectUpdatePreviewErrors,
217
223
  makeSelectFetchPrefilledValuesError,
@@ -9,6 +9,7 @@ import {
9
9
  extractTagsRequested,
10
10
  updatePreviewRequested,
11
11
  sendTestMessageRequested,
12
+ sendCcsTestMessageRequested,
12
13
  clearCustomerSearchState,
13
14
  clearSearchResults,
14
15
  getTestCustomersRequested,
@@ -26,6 +27,7 @@ import {
26
27
  EXTRACT_TAGS_REQUESTED,
27
28
  UPDATE_PREVIEW_REQUESTED,
28
29
  SEND_TEST_MESSAGE_REQUESTED,
30
+ SEND_CCS_TEST_MESSAGE_REQUESTED,
29
31
  CLEAR_CUSTOMER_SEARCH_STATE,
30
32
  CLEAR_SEARCH_RESULTS,
31
33
  GET_TEST_CUSTOMERS_REQUESTED,
@@ -205,6 +207,19 @@ describe('CommonTestAndPreview Actions', () => {
205
207
  });
206
208
  });
207
209
 
210
+ describe('sendCcsTestMessageRequested', () => {
211
+ it('should create an action to send a CCS test message with payload and callback', () => {
212
+ const payload = { commDefinitionId: 'cd_123', recipient: { identifiers: [] } };
213
+ const callback = jest.fn();
214
+ const expectedAction = {
215
+ type: SEND_CCS_TEST_MESSAGE_REQUESTED,
216
+ payload,
217
+ callback,
218
+ };
219
+ expect(sendCcsTestMessageRequested(payload, callback)).toEqual(expectedAction);
220
+ });
221
+ });
222
+
208
223
  describe('clearCustomerSearchState', () => {
209
224
  it('should create an action to clear customer search state', () => {
210
225
  const expectedAction = {
@@ -128,6 +128,7 @@ describe('CommonTestAndPreview', () => {
128
128
  extractTagsRequested: jest.fn(),
129
129
  updatePreviewRequested: jest.fn(),
130
130
  sendTestMessageRequested: jest.fn(),
131
+ sendCcsTestMessageRequested: jest.fn(),
131
132
  clearCustomerSearchState: jest.fn(),
132
133
  getTestCustomersRequested: jest.fn(),
133
134
  getTestGroupsRequested: jest.fn(),
@@ -1686,6 +1687,106 @@ describe('CommonTestAndPreview', () => {
1686
1687
  });
1687
1688
  });
1688
1689
 
1690
+ describe('CCS Test Message Sending (notify/ui)', () => {
1691
+ it('dispatches sendCcsTestMessageRequested (not the legacy createMessageMeta/sendTestMessage flow) when ccsSendTransaction is set', async () => {
1692
+ const props = {
1693
+ ...defaultProps,
1694
+ selectedTestEntities: ['user-1'],
1695
+ testGroups: [],
1696
+ ccsSendTransaction: { commDefinitionId: 'cd_123', referenceId: 'ORDER_PLACED' },
1697
+ };
1698
+
1699
+ render(
1700
+ <TestWrapper>
1701
+ <CommonTestAndPreview {...props} />
1702
+ </TestWrapper>
1703
+ );
1704
+
1705
+ lastSendTestMessageProps.handleSendTestMessage();
1706
+
1707
+ expect(mockActions.sendCcsTestMessageRequested).toHaveBeenCalledWith(
1708
+ expect.objectContaining({
1709
+ commDefinitionId: 'cd_123',
1710
+ isTest: true,
1711
+ recipient: expect.objectContaining({
1712
+ identifiers: expect.any(Array),
1713
+ }),
1714
+ }),
1715
+ expect.any(Function),
1716
+ );
1717
+ expect(mockActions.createMessageMetaRequested).not.toHaveBeenCalled();
1718
+ expect(mockActions.sendTestMessageRequested).not.toHaveBeenCalled();
1719
+ });
1720
+
1721
+ it('falls back to referenceId when commDefinitionId is absent', async () => {
1722
+ const props = {
1723
+ ...defaultProps,
1724
+ selectedTestEntities: ['user-1'],
1725
+ testGroups: [],
1726
+ ccsSendTransaction: { referenceId: 'ORDER_PLACED' },
1727
+ };
1728
+
1729
+ render(
1730
+ <TestWrapper>
1731
+ <CommonTestAndPreview {...props} />
1732
+ </TestWrapper>
1733
+ );
1734
+
1735
+ lastSendTestMessageProps.handleSendTestMessage();
1736
+
1737
+ expect(mockActions.sendCcsTestMessageRequested).toHaveBeenCalledWith(
1738
+ expect.objectContaining({ referenceId: 'ORDER_PLACED' }),
1739
+ expect.any(Function),
1740
+ );
1741
+ });
1742
+
1743
+ it('shows a success notification when the callback receives true', async () => {
1744
+ const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
1745
+ mockActions.sendCcsTestMessageRequested.mockImplementation((payload, cb) => cb(true));
1746
+ const props = {
1747
+ ...defaultProps,
1748
+ selectedTestEntities: ['user-1'],
1749
+ testGroups: [],
1750
+ ccsSendTransaction: { commDefinitionId: 'cd_123' },
1751
+ };
1752
+
1753
+ render(
1754
+ <TestWrapper>
1755
+ <CommonTestAndPreview {...props} />
1756
+ </TestWrapper>
1757
+ );
1758
+
1759
+ lastSendTestMessageProps.handleSendTestMessage();
1760
+
1761
+ await waitFor(() => {
1762
+ expect(CapNotification.success).toHaveBeenCalled();
1763
+ });
1764
+ });
1765
+
1766
+ it('shows an error notification when the callback receives false', async () => {
1767
+ const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
1768
+ mockActions.sendCcsTestMessageRequested.mockImplementation((payload, cb) => cb(false));
1769
+ const props = {
1770
+ ...defaultProps,
1771
+ selectedTestEntities: ['user-1'],
1772
+ testGroups: [],
1773
+ ccsSendTransaction: { commDefinitionId: 'cd_123' },
1774
+ };
1775
+
1776
+ render(
1777
+ <TestWrapper>
1778
+ <CommonTestAndPreview {...props} />
1779
+ </TestWrapper>
1780
+ );
1781
+
1782
+ lastSendTestMessageProps.handleSendTestMessage();
1783
+
1784
+ await waitFor(() => {
1785
+ expect(CapNotification.error).toHaveBeenCalled();
1786
+ });
1787
+ });
1788
+ });
1789
+
1689
1790
  describe('Content Extraction', () => {
1690
1791
  it('should extract EMAIL content from formData', async () => {
1691
1792
  const props = {
@@ -19,6 +19,9 @@ import {
19
19
  SEND_TEST_MESSAGE_REQUESTED,
20
20
  SEND_TEST_MESSAGE_SUCCESS,
21
21
  SEND_TEST_MESSAGE_FAILURE,
22
+ SEND_CCS_TEST_MESSAGE_REQUESTED,
23
+ SEND_CCS_TEST_MESSAGE_SUCCESS,
24
+ SEND_CCS_TEST_MESSAGE_FAILURE,
22
25
  CLEAR_CUSTOMER_SEARCH_STATE,
23
26
  CLEAR_SEARCH_RESULTS,
24
27
  GET_TEST_CUSTOMERS_REQUESTED,
@@ -69,6 +72,8 @@ describe('previewAndTestReducer', () => {
69
72
  isSendingTestMessage: false,
70
73
  sendTestMessageError: null,
71
74
  testMessageResponse: null,
75
+ isSendingCcsTestMessage: false,
76
+ sendCcsTestMessageError: null,
72
77
  tags: {
73
78
  loading: false,
74
79
  error: null,
@@ -533,6 +538,42 @@ describe('previewAndTestReducer', () => {
533
538
  });
534
539
  });
535
540
 
541
+ describe('SEND_CCS_TEST_MESSAGE_REQUESTED', () => {
542
+ it('should set the sending flag and clear errors', () => {
543
+ const action = { type: SEND_CCS_TEST_MESSAGE_REQUESTED };
544
+ const result = previewAndTestReducer(initialState, action);
545
+
546
+ expect(result.get('isSendingCcsTestMessage')).toBe(true);
547
+ expect(result.get('sendCcsTestMessageError')).toBeNull();
548
+ });
549
+ });
550
+
551
+ describe('SEND_CCS_TEST_MESSAGE_SUCCESS', () => {
552
+ it('should clear the sending flag and any error', () => {
553
+ const stateWhileSending = initialState
554
+ .set('isSendingCcsTestMessage', true)
555
+ .set('sendCcsTestMessageError', 'previous error');
556
+ const action = { type: SEND_CCS_TEST_MESSAGE_SUCCESS };
557
+ const result = previewAndTestReducer(stateWhileSending, action);
558
+
559
+ expect(result.get('isSendingCcsTestMessage')).toBe(false);
560
+ expect(result.get('sendCcsTestMessageError')).toBeNull();
561
+ });
562
+ });
563
+
564
+ describe('SEND_CCS_TEST_MESSAGE_FAILURE', () => {
565
+ it('should clear the sending flag and set the error', () => {
566
+ const action = {
567
+ type: SEND_CCS_TEST_MESSAGE_FAILURE,
568
+ payload: { error: 'NO_LIVE_VERSION' },
569
+ };
570
+ const result = previewAndTestReducer(initialState, action);
571
+
572
+ expect(result.get('isSendingCcsTestMessage')).toBe(false);
573
+ expect(result.get('sendCcsTestMessageError')).toBe('NO_LIVE_VERSION');
574
+ });
575
+ });
576
+
536
577
  describe('CLEAR_SEARCH_RESULTS', () => {
537
578
  it('should clear search results and reset flags', () => {
538
579
  const stateWithResults = initialState
@@ -12,6 +12,7 @@ import {
12
12
  extractTagsSaga,
13
13
  updatePreviewSaga,
14
14
  sendTestMessageSaga,
15
+ sendCcsTestMessageSaga,
15
16
  getBulkCustomerDetails,
16
17
  fetchTestCustomersSaga,
17
18
  fetchTestGroupsSaga,
@@ -45,6 +46,8 @@ import {
45
46
  UPDATE_PREVIEW_FAILURE,
46
47
  SEND_TEST_MESSAGE_SUCCESS,
47
48
  SEND_TEST_MESSAGE_FAILURE,
49
+ SEND_CCS_TEST_MESSAGE_SUCCESS,
50
+ SEND_CCS_TEST_MESSAGE_FAILURE,
48
51
  GET_TEST_CUSTOMERS_SUCCESS,
49
52
  GET_TEST_CUSTOMERS_FAILURE,
50
53
  GET_TEST_GROUPS_SUCCESS,
@@ -747,6 +750,87 @@ describe('CommonTestAndPreview Sagas', () => {
747
750
  });
748
751
  });
749
752
 
753
+ describe('sendCcsTestMessageSaga', () => {
754
+ it('should send the CCS test message successfully', () => {
755
+ const callback = jest.fn();
756
+ const action = {
757
+ payload: { commDefinitionId: 'cd_123', recipient: { identifiers: [] } },
758
+ callback,
759
+ };
760
+ const response = { response: { success: true, data: {} } };
761
+
762
+ const generator = sendCcsTestMessageSaga(action);
763
+
764
+ expect(generator.next().value).toEqual(
765
+ call(Api.sendTransactionalComm, action.payload)
766
+ );
767
+
768
+ expect(generator.next(response).value).toEqual(
769
+ put({ type: SEND_CCS_TEST_MESSAGE_SUCCESS })
770
+ );
771
+
772
+ generator.next();
773
+ expect(callback).toHaveBeenCalledWith(true);
774
+ expect(generator.next().done).toBe(true);
775
+ });
776
+
777
+ it('should handle a CCS envelope failure (success: false)', () => {
778
+ const callback = jest.fn();
779
+ const action = {
780
+ payload: { commDefinitionId: 'cd_123', recipient: { identifiers: [] } },
781
+ callback,
782
+ };
783
+ const response = {
784
+ response: { success: false, errors: [{ message: 'NO_LIVE_VERSION' }] },
785
+ };
786
+
787
+ const generator = sendCcsTestMessageSaga(action);
788
+
789
+ generator.next();
790
+ expect(generator.next(response).value).toEqual(
791
+ put({ type: SEND_CCS_TEST_MESSAGE_FAILURE, payload: { error: 'NO_LIVE_VERSION' } })
792
+ );
793
+
794
+ generator.next();
795
+ expect(callback).toHaveBeenCalledWith(false);
796
+ });
797
+
798
+ it('falls back to a default error message when the envelope carries none', () => {
799
+ const callback = jest.fn();
800
+ const action = {
801
+ payload: { commDefinitionId: 'cd_123', recipient: { identifiers: [] } },
802
+ callback,
803
+ };
804
+ const response = { response: { success: false, errors: [] } };
805
+
806
+ const generator = sendCcsTestMessageSaga(action);
807
+
808
+ generator.next();
809
+ expect(generator.next(response).value).toEqual(
810
+ put({ type: SEND_CCS_TEST_MESSAGE_FAILURE, payload: { error: 'Failed to send test message' } })
811
+ );
812
+ });
813
+
814
+ it('should handle network error', () => {
815
+ const callback = jest.fn();
816
+ const action = {
817
+ payload: { commDefinitionId: 'cd_123', recipient: { identifiers: [] } },
818
+ callback,
819
+ };
820
+ const error = new Error('Network error');
821
+
822
+ const generator = sendCcsTestMessageSaga(action);
823
+
824
+ generator.next();
825
+ expect(generator.throw(error).value).toEqual(
826
+ put({ type: SEND_CCS_TEST_MESSAGE_FAILURE, payload: { error: 'Network error' } })
827
+ );
828
+
829
+ generator.next();
830
+ expect(callback).toHaveBeenCalledWith(false);
831
+ });
832
+ });
833
+
750
834
  describe('fetchTestCustomersSaga', () => {
751
835
  it('should fetch test customers successfully', () => {
752
836
  const response = {
@@ -28,6 +28,7 @@ import {
28
28
  makeSelectPrefilledValues,
29
29
  makeSelectTestMessageResponse,
30
30
  makeSelectIsSendingTestMessage,
31
+ makeSelectIsSendingCcsTestMessage,
31
32
  makeSelectUpdatePreviewError,
32
33
  makeSelectUpdatePreviewErrors,
33
34
  makeSelectFetchPrefilledValuesError,
@@ -78,6 +79,8 @@ describe('CommonTestAndPreview Selectors', () => {
78
79
  isSendingTestEmail: false,
79
80
  sendTestMessageError: null,
80
81
  testMessageResponse: { messageId: '123', status: 'sent' },
82
+ isSendingCcsTestMessage: false,
83
+ sendCcsTestMessageError: null,
81
84
  tags: {
82
85
  loading: false,
83
86
  error: null,
@@ -470,6 +473,15 @@ describe('CommonTestAndPreview Selectors', () => {
470
473
  });
471
474
  });
472
475
 
476
+ describe('makeSelectIsSendingCcsTestMessage', () => {
477
+ it('should select isSendingCcsTestMessage flag', () => {
478
+ const selector = makeSelectIsSendingCcsTestMessage();
479
+ const result = selector(mockState);
480
+
481
+ expect(result).toBe(false);
482
+ });
483
+ });
484
+
473
485
  describe('makeSelectUpdatePreviewError', () => {
474
486
  it('should select updatePreviewError from state', () => {
475
487
  const selector = makeSelectUpdatePreviewError();
@@ -36,6 +36,7 @@ import {
36
36
  makeSelectMessageMetaConfigId,
37
37
  makeSelectPrefilledValues,
38
38
  makeSelectIsSendingTestMessage,
39
+ makeSelectIsSendingCcsTestMessage,
39
40
  makeSelectUpdatePreviewError,
40
41
  makeSelectUpdatePreviewErrors,
41
42
  makeSelectFetchPrefilledValuesError,
@@ -103,6 +104,7 @@ TestAndPreviewSlidebox.propTypes = {
103
104
  messageMetaConfigId: PropTypes.string,
104
105
  prefilledValues: PropTypes.object,
105
106
  isSendingTestMessage: PropTypes.bool.isRequired,
107
+ isSendingCcsTestMessage: PropTypes.bool.isRequired,
106
108
  intl: PropTypes.object.isRequired,
107
109
  senderDetailsByChannel: PropTypes.object,
108
110
  wecrmAccounts: PropTypes.array,
@@ -151,6 +153,7 @@ const mapStateToProps = createStructuredSelector({
151
153
  fetchPrefilledValuesError: makeSelectFetchPrefilledValuesError(),
152
154
  fetchPrefilledValuesErrors: makeSelectFetchPrefilledValuesErrors(),
153
155
  isSendingTestMessage: makeSelectIsSendingTestMessage(),
156
+ isSendingCcsTestMessage: makeSelectIsSendingCcsTestMessage(),
154
157
  senderDetailsByChannel: makeSelectSenderDetailsByChannel(),
155
158
  wecrmAccounts: makeSelectWeCrmAccounts(),
156
159
  isLoadingSenderDetails: makeSelectIsLoadingSenderDetails(),