@capillarytech/creatives-library 8.0.359-alpha.0 → 8.0.359-alpha.1
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 +29 -0
- package/index.html +1 -0
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/cdnTransformation.js +75 -3
- package/utils/commonUtils.js +19 -1
- package/utils/rcsPayloadUtils.js +92 -0
- package/utils/templateVarUtils.js +201 -0
- package/utils/tests/cdnTransformation.test.js +127 -0
- package/utils/tests/rcsPayloadUtils.test.js +226 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +166 -108
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapImageUpload/index.js +2 -2
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +72 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +214 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/PreviewHeader.js +16 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +157 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +14 -132
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +169 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +400 -239
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +202 -10
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +40 -2
- package/v2Components/CommonTestAndPreview/index.js +887 -453
- package/v2Components/CommonTestAndPreview/messages.js +45 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +25 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +308 -284
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +34 -13
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +163 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/ViberPreviewContent.test.js +0 -364
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +522 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +454 -1
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +2 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +327 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
- package/v2Components/FormBuilder/index.js +167 -56
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +956 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +119 -0
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +223 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +37 -22
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -31
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +15 -3
- package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/v2Containers/App/constants.js +3 -0
- package/v2Containers/App/tests/constants.test.js +61 -0
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +17 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
- package/v2Containers/CreativesContainer/constants.js +9 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +79 -0
- package/v2Containers/CreativesContainer/index.js +382 -127
- package/v2Containers/CreativesContainer/index.scss +83 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +79 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +357 -98
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +120 -11
- package/v2Containers/Rcs/index.js +2577 -812
- package/v2Containers/Rcs/index.scss +281 -8
- package/v2Containers/Rcs/messages.js +34 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +225 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +98036 -70145
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/index.test.js +152 -121
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
- package/v2Containers/Rcs/tests/utils.test.js +646 -30
- package/v2Containers/Rcs/utils.js +478 -11
- package/v2Containers/Sms/Create/index.js +106 -40
- package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Create/index.js +9 -4
- package/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +640 -130
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4328 -2375
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +6 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +166 -86
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +203 -145
- package/v2Containers/Templates/sagas.js +62 -13
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1062 -1017
- package/v2Containers/Templates/tests/sagas.test.js +222 -22
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/v2Containers/Templates/tests/webpush.test.js +375 -0
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/v2Containers/TemplatesV2/index.js +86 -23
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/Viber/constants.js +0 -19
- package/v2Containers/Viber/index.js +47 -714
- package/v2Containers/Viber/index.scss +0 -148
- package/v2Containers/Viber/messages.js +0 -116
- package/v2Containers/Viber/tests/index.test.js +0 -80
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/WebPush/Create/index.js +91 -8
- package/v2Containers/WebPush/Create/index.scss +7 -0
- package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +348 -0
- package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +325 -0
- package/v2Containers/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { expectSaga } from 'redux-saga-test-plan';
|
|
2
|
+
import {
|
|
3
|
+
take, call, takeLatest, takeEvery, put,
|
|
4
|
+
} from 'redux-saga/effects';
|
|
2
5
|
import * as matchers from 'redux-saga-test-plan/matchers';
|
|
3
6
|
import { throwError } from 'redux-saga-test-plan/providers';
|
|
4
|
-
import { call, takeLatest, put } from 'redux-saga/effects';
|
|
5
7
|
import * as api from '../../../services/api';
|
|
6
8
|
import * as types from '../constants';
|
|
7
9
|
import * as cdnUtils from '../../../utils/cdnTransformation';
|
|
8
10
|
import {
|
|
9
11
|
getCdnTransformationConfig,
|
|
10
12
|
getAllTemplates,
|
|
13
|
+
getLocalSmsTemplates,
|
|
11
14
|
watchGetCdnTransformationConfig,
|
|
12
15
|
watchGetAllTemplates,
|
|
13
16
|
getSenderDetails,
|
|
14
17
|
fetchWeCrmAccounts,
|
|
15
18
|
sendZippedFile,
|
|
16
19
|
fetchUserList,
|
|
17
|
-
watchGetUserList,
|
|
18
20
|
deleteRcsTemplate,
|
|
19
21
|
watchDeleteRcsTemplate,
|
|
20
22
|
watchForGetTemplateInfoById,
|
|
@@ -39,10 +41,14 @@ import {
|
|
|
39
41
|
watchUnarchiveTemplate,
|
|
40
42
|
watchBulkArchive,
|
|
41
43
|
watchBulkUnarchive,
|
|
44
|
+
watchGetUserList,
|
|
42
45
|
} from '../sagas';
|
|
43
|
-
|
|
44
|
-
import { ZALO_TEMPLATE_INFO_REQUEST } from '../../Zalo/constants';
|
|
46
|
+
|
|
45
47
|
import * as mockData from './mockData';
|
|
48
|
+
import { fetchSmsTemplatesFromQuery } from '../utils/smsTemplatesListApi';
|
|
49
|
+
import { ZALO } from '../../CreativesContainer/constants';
|
|
50
|
+
import { VIET_GUYS, ZALO_TEMPLATE_INFO_REQUEST } from '../../Zalo/constants';
|
|
51
|
+
import { getTemplateInfoById } from '../../Zalo/saga';
|
|
46
52
|
|
|
47
53
|
jest.mock('@capillarytech/cap-ui-library', () => ({
|
|
48
54
|
CapNotification: {
|
|
@@ -54,10 +60,25 @@ jest.mock('@capillarytech/cap-ui-library', () => ({
|
|
|
54
60
|
}));
|
|
55
61
|
|
|
56
62
|
describe('getCdnTransformationConfig saga', () => {
|
|
57
|
-
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
delete window.APP_ENV;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("short-circuits to env config and skips the API call when window.APP_ENV is set", async () => {
|
|
68
|
+
const initSpy = jest.spyOn(cdnUtils, "initCdnConfigFromEnv").mockReturnValue(true);
|
|
69
|
+
const apiSpy = jest.spyOn(api, "getCdnTransformationConfig");
|
|
70
|
+
|
|
71
|
+
await expectSaga(getCdnTransformationConfig).run();
|
|
72
|
+
|
|
73
|
+
expect(initSpy).toHaveBeenCalled();
|
|
74
|
+
expect(apiSpy).not.toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("handle valid response from api", async () => {
|
|
78
|
+
jest.spyOn(cdnUtils, "initCdnConfigFromEnv").mockReturnValue(false);
|
|
58
79
|
const saveCdnConfigsSpy = jest.spyOn(cdnUtils, "saveCdnConfigs");
|
|
59
80
|
|
|
60
|
-
expectSaga(getCdnTransformationConfig)
|
|
81
|
+
await expectSaga(getCdnTransformationConfig)
|
|
61
82
|
.provide([
|
|
62
83
|
[
|
|
63
84
|
call(api.getCdnTransformationConfig),
|
|
@@ -68,13 +89,14 @@ describe('getCdnTransformationConfig saga', () => {
|
|
|
68
89
|
expect(saveCdnConfigsSpy).toHaveBeenCalled();
|
|
69
90
|
});
|
|
70
91
|
|
|
71
|
-
it("handle error response from api", () => {
|
|
92
|
+
it("handle error response from api", async () => {
|
|
93
|
+
jest.spyOn(cdnUtils, "initCdnConfigFromEnv").mockReturnValue(false);
|
|
72
94
|
const removeAllCdnLocalStorageItemsSpy = jest.spyOn(
|
|
73
95
|
cdnUtils,
|
|
74
96
|
"removeAllCdnLocalStorageItems"
|
|
75
97
|
);
|
|
76
98
|
|
|
77
|
-
expectSaga(getCdnTransformationConfig)
|
|
99
|
+
await expectSaga(getCdnTransformationConfig)
|
|
78
100
|
.provide([
|
|
79
101
|
[
|
|
80
102
|
call(api.getCdnTransformationConfig),
|
|
@@ -85,7 +107,8 @@ describe('getCdnTransformationConfig saga', () => {
|
|
|
85
107
|
expect(removeAllCdnLocalStorageItemsSpy).toHaveBeenCalled();
|
|
86
108
|
});
|
|
87
109
|
|
|
88
|
-
it("remove localStorage items when an error is thrown", () => {
|
|
110
|
+
it("remove localStorage items when an error is thrown", async () => {
|
|
111
|
+
jest.spyOn(cdnUtils, "initCdnConfigFromEnv").mockReturnValue(false);
|
|
89
112
|
const saveCdnConfigsSpy = jest.spyOn(cdnUtils, "saveCdnConfigs").mockImplementation(()=>{
|
|
90
113
|
throw new Error()
|
|
91
114
|
});
|
|
@@ -94,7 +117,7 @@ describe('getCdnTransformationConfig saga', () => {
|
|
|
94
117
|
"removeAllCdnLocalStorageItems"
|
|
95
118
|
);
|
|
96
119
|
|
|
97
|
-
expectSaga(getCdnTransformationConfig)
|
|
120
|
+
await expectSaga(getCdnTransformationConfig)
|
|
98
121
|
.provide([
|
|
99
122
|
[
|
|
100
123
|
call(api.getCdnTransformationConfig),
|
|
@@ -150,8 +173,8 @@ describe('templateList saga', () => {
|
|
|
150
173
|
],
|
|
151
174
|
]).put({
|
|
152
175
|
type: types.GET_ALL_TEMPLATES_SUCCESS,
|
|
153
|
-
data: mockData.getAllTemplatesListSuccess,
|
|
154
|
-
weCRMTemplate: mockData.getAllTemplatesListSuccess,
|
|
176
|
+
data: mockData.getAllTemplatesListSuccess.response,
|
|
177
|
+
weCRMTemplate: mockData.getAllTemplatesListSuccess.response?.unMapped,
|
|
155
178
|
isReset: mockData.getAllTemplatesListSuccess?.queryParams?.page === 1,
|
|
156
179
|
})
|
|
157
180
|
.run();
|
|
@@ -167,8 +190,8 @@ describe('templateList saga', () => {
|
|
|
167
190
|
],
|
|
168
191
|
]).put({
|
|
169
192
|
type: types.GET_ALL_TEMPLATES_SUCCESS,
|
|
170
|
-
data: mockData.getAllTemplatesListSuccess,
|
|
171
|
-
weCRMTemplate: mockData.getAllTemplatesListSuccess,
|
|
193
|
+
data: mockData.getAllTemplatesListSuccess.response,
|
|
194
|
+
weCRMTemplate: mockData.getAllTemplatesListSuccess.response?.unMapped,
|
|
172
195
|
isReset: mockData.getAllTemplatesListSuccess?.queryParams?.page === 1,
|
|
173
196
|
})
|
|
174
197
|
.run();
|
|
@@ -187,6 +210,163 @@ describe('templateList saga', () => {
|
|
|
187
210
|
})
|
|
188
211
|
.run();
|
|
189
212
|
});
|
|
213
|
+
|
|
214
|
+
it('SMS channel uses fetchSmsTemplatesFromQuery', () => {
|
|
215
|
+
const smsAction = {
|
|
216
|
+
type: types.GET_ALL_TEMPLATES_REQUEST,
|
|
217
|
+
channel: 'Sms',
|
|
218
|
+
queryParams: { page: 1, perPage: 25, name: '', sortBy: 'Most Recent' },
|
|
219
|
+
intlCopyOf: 'Kopie',
|
|
220
|
+
};
|
|
221
|
+
const fetched = {
|
|
222
|
+
channelTemplates: { templates: [{ name: 'Kopie Foo' }], totalCount: 1 },
|
|
223
|
+
weCRMTemplate: undefined,
|
|
224
|
+
raw: {},
|
|
225
|
+
};
|
|
226
|
+
return expectSaga(getAllTemplates, smsAction)
|
|
227
|
+
.provide([
|
|
228
|
+
[call(fetchSmsTemplatesFromQuery, smsAction.queryParams, smsAction.intlCopyOf), fetched],
|
|
229
|
+
])
|
|
230
|
+
.put({
|
|
231
|
+
type: types.GET_ALL_TEMPLATES_SUCCESS,
|
|
232
|
+
data: fetched.channelTemplates,
|
|
233
|
+
weCRMTemplate: fetched.weCRMTemplate,
|
|
234
|
+
isReset: true,
|
|
235
|
+
})
|
|
236
|
+
.run();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('SMS channel propagates fetchSmsTemplatesFromQuery errors', () => {
|
|
240
|
+
const smsAction = {
|
|
241
|
+
type: types.GET_ALL_TEMPLATES_REQUEST,
|
|
242
|
+
channel: 'SMS',
|
|
243
|
+
queryParams: { page: 2, perPage: 25 },
|
|
244
|
+
intlCopyOf: '',
|
|
245
|
+
};
|
|
246
|
+
const error = new Error('sms list fail');
|
|
247
|
+
return expectSaga(getAllTemplates, smsAction)
|
|
248
|
+
.provide([
|
|
249
|
+
[call(fetchSmsTemplatesFromQuery, smsAction.queryParams, smsAction.intlCopyOf), throwError(error)],
|
|
250
|
+
])
|
|
251
|
+
.put({
|
|
252
|
+
type: types.GET_ALL_TEMPLATES_FAILURE,
|
|
253
|
+
error,
|
|
254
|
+
})
|
|
255
|
+
.run();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('wechat channel merges mapped and richmedia and applies Most Recent sort', () => {
|
|
259
|
+
const wechatApiResponse = {
|
|
260
|
+
response: {
|
|
261
|
+
mapped: [
|
|
262
|
+
{ name: 'B', updatedAt: '2024-01-02T00:00:00Z' },
|
|
263
|
+
{ name: 'A', updatedAt: '2024-01-01T00:00:00Z' },
|
|
264
|
+
],
|
|
265
|
+
richmedia: [{ name: 'C', updatedAt: '2024-01-03T00:00:00Z' }],
|
|
266
|
+
unMapped: [],
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
const action = {
|
|
270
|
+
channel: 'wechat',
|
|
271
|
+
queryParams: { sortBy: 'Most Recent', page: 1 },
|
|
272
|
+
intlCopyOf: '',
|
|
273
|
+
};
|
|
274
|
+
return expectSaga(getAllTemplates, action)
|
|
275
|
+
.provide([[matchers.call.fn(api.getAllTemplates), wechatApiResponse]])
|
|
276
|
+
.put.actionType(types.GET_ALL_TEMPLATES_SUCCESS)
|
|
277
|
+
.run();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('wechat channel applies Alphabetically sort', () => {
|
|
281
|
+
const wechatApiResponse = {
|
|
282
|
+
response: {
|
|
283
|
+
mapped: [{ name: 'Zebra', updatedAt: '2024-01-02T00:00:00Z' }],
|
|
284
|
+
richmedia: [{ name: 'Apple', updatedAt: '2024-01-01T00:00:00Z' }],
|
|
285
|
+
unMapped: [],
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
const action = {
|
|
289
|
+
channel: 'wechat',
|
|
290
|
+
queryParams: { sortBy: 'Alphabetically', page: 1 },
|
|
291
|
+
intlCopyOf: '',
|
|
292
|
+
};
|
|
293
|
+
return expectSaga(getAllTemplates, action)
|
|
294
|
+
.provide([[matchers.call.fn(api.getAllTemplates), wechatApiResponse]])
|
|
295
|
+
.put.actionType(types.GET_ALL_TEMPLATES_SUCCESS)
|
|
296
|
+
.run();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('wechat channel replaces Copy-of prefix when intlCopyOf is set', () => {
|
|
300
|
+
const wechatApiResponse = {
|
|
301
|
+
response: {
|
|
302
|
+
mapped: [{ name: 'Copy of Promo', updatedAt: '2024-01-01T00:00:00Z' }],
|
|
303
|
+
richmedia: [],
|
|
304
|
+
unMapped: [],
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
const action = {
|
|
308
|
+
channel: 'wechat',
|
|
309
|
+
queryParams: { page: 1 },
|
|
310
|
+
intlCopyOf: 'Kopia av ',
|
|
311
|
+
};
|
|
312
|
+
return expectSaga(getAllTemplates, action)
|
|
313
|
+
.provide([[matchers.call.fn(api.getAllTemplates), wechatApiResponse]])
|
|
314
|
+
.put.actionType(types.GET_ALL_TEMPLATES_SUCCESS)
|
|
315
|
+
.run();
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe('getLocalSmsTemplates saga', () => {
|
|
320
|
+
it('invokes onSuccess with fetched data', () => {
|
|
321
|
+
const onSuccess = jest.fn();
|
|
322
|
+
const action = {
|
|
323
|
+
queryParams: { page: 1 },
|
|
324
|
+
intlCopyOf: '',
|
|
325
|
+
onSuccess,
|
|
326
|
+
};
|
|
327
|
+
const fetched = { channelTemplates: { templates: [] }, raw: {} };
|
|
328
|
+
return expectSaga(getLocalSmsTemplates, action)
|
|
329
|
+
.provide([[call(fetchSmsTemplatesFromQuery, action.queryParams, action.intlCopyOf), fetched]])
|
|
330
|
+
.call(onSuccess, fetched)
|
|
331
|
+
.run();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('invokes onFailure when fetch throws', () => {
|
|
335
|
+
const onFailure = jest.fn();
|
|
336
|
+
const error = new Error('local list fail');
|
|
337
|
+
const action = {
|
|
338
|
+
queryParams: { page: 1 },
|
|
339
|
+
intlCopyOf: 'Kopie',
|
|
340
|
+
onFailure,
|
|
341
|
+
};
|
|
342
|
+
return expectSaga(getLocalSmsTemplates, action)
|
|
343
|
+
.provide([
|
|
344
|
+
[call(fetchSmsTemplatesFromQuery, action.queryParams, action.intlCopyOf), throwError(error)],
|
|
345
|
+
])
|
|
346
|
+
.call(onFailure, error)
|
|
347
|
+
.run();
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('does not throw when callbacks are omitted', () => {
|
|
351
|
+
const action = { queryParams: { page: 1 }, intlCopyOf: '' };
|
|
352
|
+
return expectSaga(getLocalSmsTemplates, action)
|
|
353
|
+
.provide([
|
|
354
|
+
[call(fetchSmsTemplatesFromQuery, action.queryParams, action.intlCopyOf), throwError(new Error('x'))],
|
|
355
|
+
])
|
|
356
|
+
.run();
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('does not call onSuccess when it is not a function', () => {
|
|
360
|
+
const action = {
|
|
361
|
+
queryParams: { page: 1 },
|
|
362
|
+
intlCopyOf: '',
|
|
363
|
+
onSuccess: 'not-a-fn',
|
|
364
|
+
};
|
|
365
|
+
const fetched = { channelTemplates: { templates: [] } };
|
|
366
|
+
return expectSaga(getLocalSmsTemplates, action)
|
|
367
|
+
.provide([[call(fetchSmsTemplatesFromQuery, action.queryParams, action.intlCopyOf), fetched]])
|
|
368
|
+
.run();
|
|
369
|
+
});
|
|
190
370
|
});
|
|
191
371
|
|
|
192
372
|
describe('watchForTemplates saga', () => {
|
|
@@ -380,7 +560,7 @@ describe('getSenderDetails Saga', () => {
|
|
|
380
560
|
|
|
381
561
|
describe('fetchWeCrmAccounts Saga', () => {
|
|
382
562
|
const action = { source: 'CRM' };
|
|
383
|
-
|
|
563
|
+
it('handles successful fetching of WeCRM accounts', () => {
|
|
384
564
|
const fakeResponse = {
|
|
385
565
|
response: [{ id: 1, name: 'Account One' }]
|
|
386
566
|
};
|
|
@@ -393,14 +573,11 @@ describe('fetchWeCrmAccounts Saga', () => {
|
|
|
393
573
|
})
|
|
394
574
|
);
|
|
395
575
|
});
|
|
396
|
-
|
|
576
|
+
it('handles error thrown from api', () => {
|
|
397
577
|
const error = new Error('Fetch failed');
|
|
398
|
-
expectSaga(fetchWeCrmAccounts, action
|
|
578
|
+
expectSaga(fetchWeCrmAccounts, action)
|
|
399
579
|
.provide([
|
|
400
|
-
[
|
|
401
|
-
call(api.fetchWeCrmAccounts),
|
|
402
|
-
throwError(error)
|
|
403
|
-
],
|
|
580
|
+
[call(api.fetchWeCrmAccounts, action.source), throwError(error)],
|
|
404
581
|
])
|
|
405
582
|
.put({
|
|
406
583
|
type: types.GET_WECRM_ACCOUNTS_FAILURE,
|
|
@@ -442,6 +619,29 @@ describe('sendZippedFile Saga', () => {
|
|
|
442
619
|
expect(generator.next().value).toEqual(call(api.sendZippedFile, action.selectedFile));
|
|
443
620
|
});
|
|
444
621
|
|
|
622
|
+
it('calls errorHandler with message and returns early when isError is true', () => {
|
|
623
|
+
const errorHandler = jest.fn();
|
|
624
|
+
const successHandler = jest.fn();
|
|
625
|
+
const errorAction = {
|
|
626
|
+
selectedFile: 'upload.zip',
|
|
627
|
+
errorHandler,
|
|
628
|
+
successHandler,
|
|
629
|
+
};
|
|
630
|
+
const fakeErrorResponse = {
|
|
631
|
+
status: { isError: true },
|
|
632
|
+
message: 'Upload failed',
|
|
633
|
+
};
|
|
634
|
+
const generator = sendZippedFile(errorAction);
|
|
635
|
+
expect(generator.next().value).toEqual(call(api.sendZippedFile, errorAction.selectedFile));
|
|
636
|
+
// Advancing with isError response causes the saga to call errorHandler and yield
|
|
637
|
+
const yieldStep = generator.next(fakeErrorResponse);
|
|
638
|
+
expect(errorHandler).toHaveBeenCalledWith('Upload failed');
|
|
639
|
+
expect(yieldStep.done).toBe(false);
|
|
640
|
+
// After resuming from the yield, the return statement completes the generator
|
|
641
|
+
expect(generator.next().done).toBe(true);
|
|
642
|
+
expect(successHandler).not.toHaveBeenCalled();
|
|
643
|
+
});
|
|
644
|
+
|
|
445
645
|
it('handles error thrown from api', () => {
|
|
446
646
|
const error = new Error('Fetch failed');
|
|
447
647
|
expectSaga(sendZippedFile, action)
|
|
@@ -1207,7 +1407,7 @@ describe('v2TemplateSaga', () => {
|
|
|
1207
1407
|
// all() returns an IO object with an ALL key containing the array of effects
|
|
1208
1408
|
expect(step.value).toHaveProperty('@@redux-saga/IO', true);
|
|
1209
1409
|
expect(step.value).toHaveProperty('ALL');
|
|
1210
|
-
expect(step.value.ALL).toHaveLength(
|
|
1410
|
+
expect(step.value.ALL).toHaveLength(15);
|
|
1211
1411
|
expect(step.done).toBe(false);
|
|
1212
1412
|
});
|
|
1213
1413
|
});
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import * as Api from '../../../services/api';
|
|
2
|
+
import { isTraiDLTEnable } from '../../../utils/common';
|
|
3
|
+
|
|
4
|
+
jest.mock('../../../services/api', () => ({
|
|
5
|
+
getAllTemplates: jest.fn(),
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
jest.mock('../../../utils/common', () => ({
|
|
9
|
+
isTraiDLTEnable: jest.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
buildSmsTemplatesListQueryParams,
|
|
14
|
+
fetchSmsTemplatesFromQuery,
|
|
15
|
+
fetchSmsTemplatesListPage,
|
|
16
|
+
SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
17
|
+
} from '../utils/smsTemplatesListApi';
|
|
18
|
+
|
|
19
|
+
describe('smsTemplatesListApi', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('buildSmsTemplatesListQueryParams', () => {
|
|
25
|
+
it('includes traiEnable when TRAI DLT is enabled', () => {
|
|
26
|
+
isTraiDLTEnable.mockReturnValue(true);
|
|
27
|
+
const q = buildSmsTemplatesListQueryParams({
|
|
28
|
+
page: 1,
|
|
29
|
+
perPage: 25,
|
|
30
|
+
name: 'x',
|
|
31
|
+
sortBy: SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
32
|
+
isFullMode: true,
|
|
33
|
+
smsRegister: {},
|
|
34
|
+
});
|
|
35
|
+
expect(q).toEqual({
|
|
36
|
+
page: 1,
|
|
37
|
+
perPage: 25,
|
|
38
|
+
sortBy: SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
39
|
+
name: 'x',
|
|
40
|
+
traiEnable: true,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('omits traiEnable when TRAI DLT is disabled', () => {
|
|
45
|
+
isTraiDLTEnable.mockReturnValue(false);
|
|
46
|
+
const q = buildSmsTemplatesListQueryParams({
|
|
47
|
+
page: 2,
|
|
48
|
+
perPage: 10,
|
|
49
|
+
isFullMode: false,
|
|
50
|
+
smsRegister: null,
|
|
51
|
+
});
|
|
52
|
+
expect(q.traiEnable).toBeUndefined();
|
|
53
|
+
expect(q.name).toBe('');
|
|
54
|
+
expect(q.sortBy).toBe(SMS_TEMPLATES_LIST_SORT_MOST_RECENT);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('fetchSmsTemplatesFromQuery', () => {
|
|
59
|
+
it('returns channelTemplates, weCRMTemplate, and raw; maps intl copy on names', async () => {
|
|
60
|
+
Api.getAllTemplates.mockResolvedValue({
|
|
61
|
+
response: {
|
|
62
|
+
templates: [{ name: 'Copy of A', _id: '1' }],
|
|
63
|
+
unMapped: { u: 1 },
|
|
64
|
+
totalCount: 5,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const out = await fetchSmsTemplatesFromQuery(
|
|
69
|
+
{ page: 1, perPage: 25 },
|
|
70
|
+
'Kopie',
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(Api.getAllTemplates).toHaveBeenCalledWith({
|
|
74
|
+
channel: 'Sms',
|
|
75
|
+
queryParams: { page: 1, perPage: 25 },
|
|
76
|
+
});
|
|
77
|
+
expect(out.weCRMTemplate).toEqual({ u: 1 });
|
|
78
|
+
expect(out.raw.response.templates[0].name).toBe('Copy of A');
|
|
79
|
+
expect(out.channelTemplates.templates[0].name).toBe('Kopie A');
|
|
80
|
+
expect(out.channelTemplates.totalCount).toBe(5);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('skips name mapping when intlCopyOf is empty', async () => {
|
|
84
|
+
Api.getAllTemplates.mockResolvedValue({
|
|
85
|
+
response: {
|
|
86
|
+
templates: [{ name: 'Copy of A' }],
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const out = await fetchSmsTemplatesFromQuery({ page: 1 }, '');
|
|
90
|
+
expect(out.channelTemplates.templates[0].name).toBe('Copy of A');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('handles missing response.templates', async () => {
|
|
94
|
+
Api.getAllTemplates.mockResolvedValue({ response: {} });
|
|
95
|
+
const out = await fetchSmsTemplatesFromQuery({}, '');
|
|
96
|
+
expect(out.channelTemplates.templates).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('uses empty response when raw.response is missing', async () => {
|
|
100
|
+
Api.getAllTemplates.mockResolvedValue({});
|
|
101
|
+
const out = await fetchSmsTemplatesFromQuery({}, '');
|
|
102
|
+
expect(out.channelTemplates.templates).toEqual([]);
|
|
103
|
+
expect(out.weCRMTemplate).toBeUndefined();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('does not map names when intlCopyOf is set but templates list is empty', async () => {
|
|
107
|
+
Api.getAllTemplates.mockResolvedValue({
|
|
108
|
+
response: { templates: [] },
|
|
109
|
+
});
|
|
110
|
+
const out = await fetchSmsTemplatesFromQuery({ page: 1 }, 'X');
|
|
111
|
+
expect(out.channelTemplates.templates).toEqual([]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('uses empty string when template name is missing during intl mapping', async () => {
|
|
115
|
+
Api.getAllTemplates.mockResolvedValue({
|
|
116
|
+
response: {
|
|
117
|
+
templates: [{ _id: 'n', name: undefined }],
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
const out = await fetchSmsTemplatesFromQuery({ page: 1 }, 'Lbl');
|
|
121
|
+
expect(out.channelTemplates.templates[0].name).toBe('');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('fetchSmsTemplatesListPage', () => {
|
|
126
|
+
it('falls back to total when totalCount is absent', async () => {
|
|
127
|
+
isTraiDLTEnable.mockReturnValue(false);
|
|
128
|
+
Api.getAllTemplates.mockResolvedValue({
|
|
129
|
+
response: {
|
|
130
|
+
templates: [{ _id: 'a' }],
|
|
131
|
+
total: 7,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const page = await fetchSmsTemplatesListPage({
|
|
136
|
+
page: 1,
|
|
137
|
+
perPage: 25,
|
|
138
|
+
name: '',
|
|
139
|
+
sortBy: SMS_TEMPLATES_LIST_SORT_MOST_RECENT,
|
|
140
|
+
isFullMode: true,
|
|
141
|
+
smsRegister: {},
|
|
142
|
+
intlCopyOf: '',
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(page.templates).toEqual([{ _id: 'a' }]);
|
|
146
|
+
expect(page.totalCount).toBe(7);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('uses totalCount when set', async () => {
|
|
150
|
+
isTraiDLTEnable.mockReturnValue(false);
|
|
151
|
+
Api.getAllTemplates.mockResolvedValue({
|
|
152
|
+
response: {
|
|
153
|
+
templates: [],
|
|
154
|
+
totalCount: 12,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
const page = await fetchSmsTemplatesListPage({
|
|
158
|
+
page: 1,
|
|
159
|
+
perPage: 25,
|
|
160
|
+
isFullMode: false,
|
|
161
|
+
smsRegister: {},
|
|
162
|
+
});
|
|
163
|
+
expect(page.totalCount).toBe(12);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('normalizes total to 0 when missing counts', async () => {
|
|
167
|
+
isTraiDLTEnable.mockReturnValue(false);
|
|
168
|
+
Api.getAllTemplates.mockResolvedValue({
|
|
169
|
+
response: { templates: [] },
|
|
170
|
+
});
|
|
171
|
+
const page = await fetchSmsTemplatesListPage({
|
|
172
|
+
page: 1,
|
|
173
|
+
perPage: 25,
|
|
174
|
+
isFullMode: false,
|
|
175
|
+
smsRegister: {},
|
|
176
|
+
});
|
|
177
|
+
expect(page.totalCount).toBe(0);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|