@capillarytech/creatives-library 8.0.126 → 8.0.127-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/containers/App/constants.js +1 -0
- package/index.html +3 -1
- package/package.json +1 -1
- package/services/api.js +4 -4
- package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
- package/tests/integration/TemplateCreation/api-response.js +5 -0
- package/tests/integration/TemplateCreation/msw-handler.js +42 -63
- package/utils/common.js +7 -0
- package/utils/commonUtils.js +2 -6
- package/utils/createPayload.js +272 -0
- package/utils/tests/createPayload.test.js +761 -0
- package/v2Components/CapImageUpload/index.js +59 -46
- package/v2Components/CapInAppCTA/index.js +1 -0
- package/v2Components/CapMpushCTA/constants.js +25 -0
- package/v2Components/CapMpushCTA/index.js +332 -0
- package/v2Components/CapMpushCTA/index.scss +95 -0
- package/v2Components/CapMpushCTA/messages.js +89 -0
- package/v2Components/CapTagList/index.js +177 -120
- package/v2Components/CapVideoUpload/constants.js +3 -0
- package/v2Components/CapVideoUpload/index.js +167 -110
- package/v2Components/CapVideoUpload/messages.js +16 -0
- package/v2Components/Carousel/index.js +15 -13
- package/v2Components/CustomerSearchSection/index.js +12 -7
- package/v2Components/ErrorInfoNote/style.scss +1 -0
- package/v2Components/MobilePushPreviewV2/index.js +37 -5
- package/v2Components/TemplatePreview/_templatePreview.scss +114 -72
- package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +29 -0
- package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
- package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +26 -0
- package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
- package/v2Components/TemplatePreview/index.js +178 -50
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +169 -0
- package/v2Components/TestAndPreviewSlidebox/LeftPanelContent.js +95 -0
- package/v2Components/TestAndPreviewSlidebox/PreviewSection.js +69 -0
- package/v2Components/TestAndPreviewSlidebox/SendTestMessage.js +68 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +67 -246
- package/v2Components/TestAndPreviewSlidebox/tests/CustomValuesEditor.test.js +425 -0
- package/v2Components/TestAndPreviewSlidebox/tests/LeftPanelContent.test.js +400 -0
- package/v2Components/TestAndPreviewSlidebox/tests/SendTestMessage.test.js +448 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +9 -9
- package/v2Containers/CreativesContainer/index.js +191 -136
- package/v2Containers/Email/index.js +15 -2
- package/v2Containers/InApp/constants.js +1 -0
- package/v2Containers/InApp/index.js +13 -13
- package/v2Containers/MobilePush/Create/index.js +1 -0
- package/v2Containers/MobilePush/commonMethods.js +7 -14
- package/v2Containers/MobilePushNew/actions.js +116 -0
- package/v2Containers/MobilePushNew/components/CtaButtons.js +170 -0
- package/v2Containers/MobilePushNew/components/MediaUploaders.js +754 -0
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +279 -0
- package/v2Containers/MobilePushNew/components/index.js +5 -0
- package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +779 -0
- package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +2114 -0
- package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +343 -0
- package/v2Containers/MobilePushNew/constants.js +115 -0
- package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1299 -0
- package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1223 -0
- package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +246 -0
- package/v2Containers/MobilePushNew/hooks/useUpload.js +726 -0
- package/v2Containers/MobilePushNew/index.js +2280 -0
- package/v2Containers/MobilePushNew/index.scss +308 -0
- package/v2Containers/MobilePushNew/messages.js +226 -0
- package/v2Containers/MobilePushNew/reducer.js +160 -0
- package/v2Containers/MobilePushNew/sagas.js +198 -0
- package/v2Containers/MobilePushNew/selectors.js +55 -0
- package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
- package/v2Containers/MobilePushNew/tests/sagas.test.js +863 -0
- package/v2Containers/MobilePushNew/tests/selectors.test.js +425 -0
- package/v2Containers/MobilePushNew/tests/utils.test.js +322 -0
- package/v2Containers/MobilePushNew/utils.js +33 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +5 -5
- package/v2Containers/TagList/index.js +56 -10
- package/v2Containers/Templates/_templates.scss +101 -1
- package/v2Containers/Templates/index.js +147 -35
- package/v2Containers/Templates/messages.js +8 -0
- package/v2Containers/Templates/sagas.js +2 -0
- package/v2Containers/Whatsapp/constants.js +1 -0
|
@@ -0,0 +1,863 @@
|
|
|
1
|
+
import { expectSaga } from 'redux-saga-test-plan';
|
|
2
|
+
import { throwError } from 'redux-saga-test-plan/providers';
|
|
3
|
+
import * as matchers from 'redux-saga-test-plan/matchers';
|
|
4
|
+
import { takeLatest } from 'redux-saga/effects';
|
|
5
|
+
|
|
6
|
+
import * as Api from '../../../services/api';
|
|
7
|
+
import * as types from '../constants';
|
|
8
|
+
import {
|
|
9
|
+
createTemplate,
|
|
10
|
+
uploadAsset,
|
|
11
|
+
editTemplate,
|
|
12
|
+
getTemplateDetails,
|
|
13
|
+
getIosCtas,
|
|
14
|
+
getMobilepushTemplatesList,
|
|
15
|
+
fetchWeCrmAccounts,
|
|
16
|
+
watchCreateTemplate,
|
|
17
|
+
v2MobilePushSagas,
|
|
18
|
+
watchUploadAsset,
|
|
19
|
+
watchEditTemplate,
|
|
20
|
+
watchGetTemplateDetails,
|
|
21
|
+
watchGetIosCtas,
|
|
22
|
+
} from '../sagas';
|
|
23
|
+
|
|
24
|
+
describe('MobilePushNew Sagas', () => {
|
|
25
|
+
describe('createTemplate Saga', () => {
|
|
26
|
+
const template = {
|
|
27
|
+
name: 'Test Template',
|
|
28
|
+
content: 'Test content',
|
|
29
|
+
};
|
|
30
|
+
const callback = jest.fn();
|
|
31
|
+
const action = { template, callback };
|
|
32
|
+
|
|
33
|
+
it('should handle successful template creation', () => {
|
|
34
|
+
const mockResponse = {
|
|
35
|
+
response: { id: '123', name: 'Test Template' },
|
|
36
|
+
status: { code: 200 },
|
|
37
|
+
message: 'Template created successfully',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return expectSaga(createTemplate, action)
|
|
41
|
+
.provide([
|
|
42
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
43
|
+
])
|
|
44
|
+
.call(Api.createMobilePushTemplate, template)
|
|
45
|
+
.call(callback, mockResponse.response)
|
|
46
|
+
.put({
|
|
47
|
+
type: types.CREATE_TEMPLATE_SUCCESS,
|
|
48
|
+
data: mockResponse.response,
|
|
49
|
+
statusCode: 200,
|
|
50
|
+
errorMsg: 'Template created successfully',
|
|
51
|
+
})
|
|
52
|
+
.run();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should handle template creation with error message but successful status', () => {
|
|
56
|
+
const mockResponse = {
|
|
57
|
+
response: { id: '123', name: 'Test Template' },
|
|
58
|
+
status: { code: 200 },
|
|
59
|
+
message: 'Warning: Template created with warnings',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return expectSaga(createTemplate, action)
|
|
63
|
+
.provide([
|
|
64
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
65
|
+
])
|
|
66
|
+
.call(Api.createMobilePushTemplate, template)
|
|
67
|
+
.call(callback, mockResponse.response)
|
|
68
|
+
.put({
|
|
69
|
+
type: types.CREATE_TEMPLATE_SUCCESS,
|
|
70
|
+
data: mockResponse.response,
|
|
71
|
+
statusCode: 200,
|
|
72
|
+
errorMsg: 'Warning: Template created with warnings',
|
|
73
|
+
})
|
|
74
|
+
.run();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should handle template creation failure with error status code', () => {
|
|
78
|
+
const mockResponse = {
|
|
79
|
+
response: null,
|
|
80
|
+
status: { code: 400 },
|
|
81
|
+
message: 'Bad Request',
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return expectSaga(createTemplate, action)
|
|
85
|
+
.provide([
|
|
86
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
87
|
+
])
|
|
88
|
+
.call(Api.createMobilePushTemplate, template)
|
|
89
|
+
.put({
|
|
90
|
+
type: types.CREATE_TEMPLATE_FAILURE,
|
|
91
|
+
error: 'Bad Request',
|
|
92
|
+
errorMsg: 'Bad Request',
|
|
93
|
+
})
|
|
94
|
+
.run();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should handle template creation without callback', () => {
|
|
98
|
+
const actionWithoutCallback = { template, callback: null };
|
|
99
|
+
const mockResponse = {
|
|
100
|
+
response: { id: '123', name: 'Test Template' },
|
|
101
|
+
status: { code: 200 },
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return expectSaga(createTemplate, actionWithoutCallback)
|
|
105
|
+
.provide([
|
|
106
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
107
|
+
])
|
|
108
|
+
.call(Api.createMobilePushTemplate, template)
|
|
109
|
+
.not.call(callback, mockResponse.response)
|
|
110
|
+
.put({
|
|
111
|
+
type: types.CREATE_TEMPLATE_SUCCESS,
|
|
112
|
+
data: mockResponse.response,
|
|
113
|
+
statusCode: 200,
|
|
114
|
+
errorMsg: undefined,
|
|
115
|
+
})
|
|
116
|
+
.run();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should handle API call failure', () => {
|
|
120
|
+
const error = new Error('Network error');
|
|
121
|
+
|
|
122
|
+
return expectSaga(createTemplate, action)
|
|
123
|
+
.provide([
|
|
124
|
+
[matchers.call.fn(Api.createMobilePushTemplate), throwError(error)],
|
|
125
|
+
])
|
|
126
|
+
.call(Api.createMobilePushTemplate, template)
|
|
127
|
+
.put({
|
|
128
|
+
type: types.CREATE_TEMPLATE_FAILURE,
|
|
129
|
+
error,
|
|
130
|
+
errorMsg: undefined,
|
|
131
|
+
})
|
|
132
|
+
.run();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should handle response without status code', () => {
|
|
136
|
+
const mockResponse = {
|
|
137
|
+
response: { id: '123', name: 'Test Template' },
|
|
138
|
+
status: null,
|
|
139
|
+
message: 'Success',
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return expectSaga(createTemplate, action)
|
|
143
|
+
.provide([
|
|
144
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
145
|
+
])
|
|
146
|
+
.call(Api.createMobilePushTemplate, template)
|
|
147
|
+
.put({
|
|
148
|
+
type: types.CREATE_TEMPLATE_SUCCESS,
|
|
149
|
+
data: mockResponse.response,
|
|
150
|
+
statusCode: '',
|
|
151
|
+
errorMsg: 'Success',
|
|
152
|
+
})
|
|
153
|
+
.run();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('uploadAsset Saga', () => {
|
|
158
|
+
const action = {
|
|
159
|
+
file: new File(['test'], 'test.jpg'),
|
|
160
|
+
assetType: 'image',
|
|
161
|
+
fileParams: { width: 100, height: 100 },
|
|
162
|
+
index: 0,
|
|
163
|
+
mobilePushParams: { platform: 'android' },
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
it('should handle successful asset upload', () => {
|
|
167
|
+
const mockResponse = {
|
|
168
|
+
response: {
|
|
169
|
+
asset: { id: 'asset123', url: 'https://example.com/asset.jpg' },
|
|
170
|
+
},
|
|
171
|
+
status: { code: 200 },
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const expectedUploadParams = {
|
|
175
|
+
file: action.file,
|
|
176
|
+
assetType: action.assetType,
|
|
177
|
+
fileParams: action.fileParams,
|
|
178
|
+
platform: 'android',
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
return expectSaga(uploadAsset, action)
|
|
182
|
+
.provide([
|
|
183
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
184
|
+
])
|
|
185
|
+
.call(Api.uploadFile, expectedUploadParams)
|
|
186
|
+
.put({
|
|
187
|
+
type: types.UPLOAD_ASSET_SUCCESS,
|
|
188
|
+
data: mockResponse.response.asset,
|
|
189
|
+
statusCode: 200,
|
|
190
|
+
index: 0,
|
|
191
|
+
})
|
|
192
|
+
.run();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should handle asset upload without mobilePushParams', () => {
|
|
196
|
+
const actionWithoutMobileParams = {
|
|
197
|
+
file: new File(['test'], 'test.jpg'),
|
|
198
|
+
assetType: 'image',
|
|
199
|
+
fileParams: { width: 100, height: 100 },
|
|
200
|
+
index: 1,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const mockResponse = {
|
|
204
|
+
response: {
|
|
205
|
+
asset: { id: 'asset123', url: 'https://example.com/asset.jpg' },
|
|
206
|
+
},
|
|
207
|
+
status: { code: 200 },
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const expectedUploadParams = {
|
|
211
|
+
file: actionWithoutMobileParams.file,
|
|
212
|
+
assetType: actionWithoutMobileParams.assetType,
|
|
213
|
+
fileParams: actionWithoutMobileParams.fileParams,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
return expectSaga(uploadAsset, actionWithoutMobileParams)
|
|
217
|
+
.provide([
|
|
218
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
219
|
+
])
|
|
220
|
+
.call(Api.uploadFile, expectedUploadParams)
|
|
221
|
+
.put({
|
|
222
|
+
type: types.UPLOAD_ASSET_SUCCESS,
|
|
223
|
+
data: mockResponse.response.asset,
|
|
224
|
+
statusCode: 200,
|
|
225
|
+
index: 1,
|
|
226
|
+
})
|
|
227
|
+
.run();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should handle asset upload failure', () => {
|
|
231
|
+
const error = new Error('Upload failed');
|
|
232
|
+
|
|
233
|
+
return expectSaga(uploadAsset, action)
|
|
234
|
+
.provide([
|
|
235
|
+
[matchers.call.fn(Api.uploadFile), throwError(error)],
|
|
236
|
+
])
|
|
237
|
+
.put({
|
|
238
|
+
type: types.UPLOAD_ASSET_FAILURE,
|
|
239
|
+
error,
|
|
240
|
+
})
|
|
241
|
+
.run();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should handle response without status code', () => {
|
|
245
|
+
const mockResponse = {
|
|
246
|
+
response: {
|
|
247
|
+
asset: { id: 'asset123', url: 'https://example.com/asset.jpg' },
|
|
248
|
+
},
|
|
249
|
+
status: null,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
return expectSaga(uploadAsset, action)
|
|
253
|
+
.provide([
|
|
254
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
255
|
+
])
|
|
256
|
+
.put({
|
|
257
|
+
type: types.UPLOAD_ASSET_SUCCESS,
|
|
258
|
+
data: mockResponse.response.asset,
|
|
259
|
+
statusCode: '',
|
|
260
|
+
index: 0,
|
|
261
|
+
})
|
|
262
|
+
.run();
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe('editTemplate Saga', () => {
|
|
267
|
+
const template = {
|
|
268
|
+
_id: 'template123',
|
|
269
|
+
name: 'Updated Template',
|
|
270
|
+
content: 'Updated content',
|
|
271
|
+
};
|
|
272
|
+
const callback = jest.fn();
|
|
273
|
+
const action = { template, callback };
|
|
274
|
+
|
|
275
|
+
it('should handle successful template edit', () => {
|
|
276
|
+
const mockResponse = {
|
|
277
|
+
response: {
|
|
278
|
+
_id: 'template123',
|
|
279
|
+
name: 'Updated Template',
|
|
280
|
+
templateId: { _id: 'template123' },
|
|
281
|
+
},
|
|
282
|
+
status: { code: 200 },
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const expectedResponseData = {
|
|
286
|
+
...mockResponse.response,
|
|
287
|
+
templateId: 'template123',
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
return expectSaga(editTemplate, action)
|
|
291
|
+
.provide([
|
|
292
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
293
|
+
])
|
|
294
|
+
.call(Api.createMobilePushTemplate, template)
|
|
295
|
+
.put({
|
|
296
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
297
|
+
data: expectedResponseData,
|
|
298
|
+
statusCode: 200,
|
|
299
|
+
errorMsg: undefined,
|
|
300
|
+
})
|
|
301
|
+
.call(callback, expectedResponseData)
|
|
302
|
+
.run();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should handle template edit with nested templateId structure', () => {
|
|
306
|
+
const mockResponse = {
|
|
307
|
+
response: {
|
|
308
|
+
_id: 'template123',
|
|
309
|
+
name: 'Updated Template',
|
|
310
|
+
templateId: { _id: 'nested-template-id' },
|
|
311
|
+
},
|
|
312
|
+
status: { code: 200 },
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const expectedResponseData = {
|
|
316
|
+
...mockResponse.response,
|
|
317
|
+
templateId: 'nested-template-id',
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
return expectSaga(editTemplate, action)
|
|
321
|
+
.provide([
|
|
322
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
323
|
+
])
|
|
324
|
+
.call(Api.createMobilePushTemplate, template)
|
|
325
|
+
.put({
|
|
326
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
327
|
+
data: expectedResponseData,
|
|
328
|
+
statusCode: 200,
|
|
329
|
+
errorMsg: undefined,
|
|
330
|
+
})
|
|
331
|
+
.call(callback, expectedResponseData)
|
|
332
|
+
.run();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should handle template edit without callback', () => {
|
|
336
|
+
const actionWithoutCallback = { template, callback: null };
|
|
337
|
+
const mockResponse = {
|
|
338
|
+
response: { _id: 'template123', name: 'Updated Template' },
|
|
339
|
+
status: { code: 200 },
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const expectedResponseData = {
|
|
343
|
+
...mockResponse.response,
|
|
344
|
+
templateId: 'template123',
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
return expectSaga(editTemplate, actionWithoutCallback)
|
|
348
|
+
.provide([
|
|
349
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
350
|
+
])
|
|
351
|
+
.call(Api.createMobilePushTemplate, template)
|
|
352
|
+
.put({
|
|
353
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
354
|
+
data: expectedResponseData,
|
|
355
|
+
statusCode: 200,
|
|
356
|
+
errorMsg: undefined,
|
|
357
|
+
})
|
|
358
|
+
.not.call(callback, expectedResponseData)
|
|
359
|
+
.run();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('should handle template edit failure with error status code', () => {
|
|
363
|
+
const mockResponse = {
|
|
364
|
+
response: null,
|
|
365
|
+
status: { code: 400 },
|
|
366
|
+
message: 'Bad Request',
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
return expectSaga(editTemplate, action)
|
|
370
|
+
.provide([
|
|
371
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
372
|
+
])
|
|
373
|
+
.call(Api.createMobilePushTemplate, template)
|
|
374
|
+
.put({
|
|
375
|
+
type: types.EDIT_TEMPLATE_FAILURE,
|
|
376
|
+
error: 'Bad Request',
|
|
377
|
+
errorMsg: 'Bad Request',
|
|
378
|
+
})
|
|
379
|
+
.run();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('should handle template edit failure with 500 error', () => {
|
|
383
|
+
const mockResponse = {
|
|
384
|
+
response: null,
|
|
385
|
+
status: { code: 500 },
|
|
386
|
+
message: 'Internal Server Error',
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
return expectSaga(editTemplate, action)
|
|
390
|
+
.provide([
|
|
391
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
392
|
+
])
|
|
393
|
+
.call(Api.createMobilePushTemplate, template)
|
|
394
|
+
.put({
|
|
395
|
+
type: types.EDIT_TEMPLATE_FAILURE,
|
|
396
|
+
error: 'Internal Server Error',
|
|
397
|
+
errorMsg: 'Internal Server Error',
|
|
398
|
+
})
|
|
399
|
+
.run();
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('should handle API call failure', () => {
|
|
403
|
+
const error = new Error('Network error');
|
|
404
|
+
|
|
405
|
+
return expectSaga(editTemplate, action)
|
|
406
|
+
.provide([
|
|
407
|
+
[matchers.call.fn(Api.createMobilePushTemplate), throwError(error)],
|
|
408
|
+
])
|
|
409
|
+
.call(Api.createMobilePushTemplate, template)
|
|
410
|
+
.put({
|
|
411
|
+
type: types.EDIT_TEMPLATE_FAILURE,
|
|
412
|
+
error,
|
|
413
|
+
errorMsg: undefined,
|
|
414
|
+
})
|
|
415
|
+
.run();
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('should fallback to template._id when no templateId in response', () => {
|
|
419
|
+
const mockResponse = {
|
|
420
|
+
response: {
|
|
421
|
+
name: 'Updated Template',
|
|
422
|
+
// No _id or templateId in response
|
|
423
|
+
},
|
|
424
|
+
status: { code: 200 },
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
const expectedResponseData = {
|
|
428
|
+
...mockResponse.response,
|
|
429
|
+
templateId: 'template123', // Falls back to template._id
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
return expectSaga(editTemplate, action)
|
|
433
|
+
.provide([
|
|
434
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
435
|
+
])
|
|
436
|
+
.call(Api.createMobilePushTemplate, template)
|
|
437
|
+
.put({
|
|
438
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
439
|
+
data: expectedResponseData,
|
|
440
|
+
statusCode: 200,
|
|
441
|
+
errorMsg: undefined,
|
|
442
|
+
})
|
|
443
|
+
.call(callback, expectedResponseData)
|
|
444
|
+
.run();
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// Additional test cases for complete coverage of lines 72 and 86
|
|
448
|
+
|
|
449
|
+
it('should use HTTP Error fallback when message is null (Line 72)', () => {
|
|
450
|
+
const mockResponse = {
|
|
451
|
+
response: null,
|
|
452
|
+
status: { code: 400 },
|
|
453
|
+
message: null, // This should trigger the fallback
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
return expectSaga(editTemplate, action)
|
|
457
|
+
.provide([
|
|
458
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
459
|
+
])
|
|
460
|
+
.call(Api.createMobilePushTemplate, template)
|
|
461
|
+
.put({
|
|
462
|
+
type: types.EDIT_TEMPLATE_FAILURE,
|
|
463
|
+
error: 'HTTP Error 400',
|
|
464
|
+
errorMsg: 'HTTP Error 400',
|
|
465
|
+
})
|
|
466
|
+
.run();
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('should use HTTP Error fallback when message is undefined (Line 72)', () => {
|
|
470
|
+
const mockResponse = {
|
|
471
|
+
response: null,
|
|
472
|
+
status: { code: 404 },
|
|
473
|
+
message: undefined, // This should trigger the fallback
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
return expectSaga(editTemplate, action)
|
|
477
|
+
.provide([
|
|
478
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
479
|
+
])
|
|
480
|
+
.call(Api.createMobilePushTemplate, template)
|
|
481
|
+
.put({
|
|
482
|
+
type: types.EDIT_TEMPLATE_FAILURE,
|
|
483
|
+
error: 'HTTP Error 404',
|
|
484
|
+
errorMsg: 'HTTP Error 404',
|
|
485
|
+
})
|
|
486
|
+
.run();
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('should use HTTP Error fallback when message is empty string (Line 72)', () => {
|
|
490
|
+
const mockResponse = {
|
|
491
|
+
response: null,
|
|
492
|
+
status: { code: 422 },
|
|
493
|
+
message: '', // This should trigger the fallback
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
return expectSaga(editTemplate, action)
|
|
497
|
+
.provide([
|
|
498
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
499
|
+
])
|
|
500
|
+
.call(Api.createMobilePushTemplate, template)
|
|
501
|
+
.put({
|
|
502
|
+
type: types.EDIT_TEMPLATE_FAILURE,
|
|
503
|
+
error: 'HTTP Error 422',
|
|
504
|
+
errorMsg: 'HTTP Error 422',
|
|
505
|
+
})
|
|
506
|
+
.run();
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it('should use HTTP Error fallback when message is false (Line 72)', () => {
|
|
510
|
+
const mockResponse = {
|
|
511
|
+
response: null,
|
|
512
|
+
status: { code: 403 },
|
|
513
|
+
message: false, // This should trigger the fallback
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
return expectSaga(editTemplate, action)
|
|
517
|
+
.provide([
|
|
518
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
519
|
+
])
|
|
520
|
+
.call(Api.createMobilePushTemplate, template)
|
|
521
|
+
.put({
|
|
522
|
+
type: types.EDIT_TEMPLATE_FAILURE,
|
|
523
|
+
error: 'HTTP Error 403',
|
|
524
|
+
errorMsg: 'HTTP Error 403',
|
|
525
|
+
})
|
|
526
|
+
.run();
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
it('should handle success with status having null code (Line 86)', () => {
|
|
530
|
+
const mockResponse = {
|
|
531
|
+
response: {
|
|
532
|
+
_id: 'template123',
|
|
533
|
+
name: 'Updated Template',
|
|
534
|
+
},
|
|
535
|
+
status: { code: null }, // code property is null
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
const expectedResponseData = {
|
|
539
|
+
...mockResponse.response,
|
|
540
|
+
templateId: 'template123',
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
return expectSaga(editTemplate, action)
|
|
544
|
+
.provide([
|
|
545
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
546
|
+
])
|
|
547
|
+
.call(Api.createMobilePushTemplate, template)
|
|
548
|
+
.put({
|
|
549
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
550
|
+
data: expectedResponseData,
|
|
551
|
+
statusCode: null, // code is null
|
|
552
|
+
errorMsg: undefined,
|
|
553
|
+
})
|
|
554
|
+
.call(callback, expectedResponseData)
|
|
555
|
+
.run();
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it('should handle success with empty status object (Line 86)', () => {
|
|
559
|
+
const mockResponse = {
|
|
560
|
+
response: {
|
|
561
|
+
_id: 'template123',
|
|
562
|
+
name: 'Updated Template',
|
|
563
|
+
},
|
|
564
|
+
status: {}, // Empty object - status.code will be undefined
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
const expectedResponseData = {
|
|
568
|
+
...mockResponse.response,
|
|
569
|
+
templateId: 'template123',
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
return expectSaga(editTemplate, action)
|
|
573
|
+
.provide([
|
|
574
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
575
|
+
])
|
|
576
|
+
.call(Api.createMobilePushTemplate, template)
|
|
577
|
+
.put({
|
|
578
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
579
|
+
data: expectedResponseData,
|
|
580
|
+
statusCode: undefined, // status.code is undefined
|
|
581
|
+
errorMsg: undefined,
|
|
582
|
+
})
|
|
583
|
+
.call(callback, expectedResponseData)
|
|
584
|
+
.run();
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('should handle success with status having undefined code (Line 86)', () => {
|
|
588
|
+
const mockResponse = {
|
|
589
|
+
response: {
|
|
590
|
+
_id: 'template123',
|
|
591
|
+
name: 'Updated Template',
|
|
592
|
+
},
|
|
593
|
+
status: { code: undefined }, // code property is explicitly undefined
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
const expectedResponseData = {
|
|
597
|
+
...mockResponse.response,
|
|
598
|
+
templateId: 'template123',
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
return expectSaga(editTemplate, action)
|
|
602
|
+
.provide([
|
|
603
|
+
[matchers.call.fn(Api.createMobilePushTemplate), mockResponse],
|
|
604
|
+
])
|
|
605
|
+
.call(Api.createMobilePushTemplate, template)
|
|
606
|
+
.put({
|
|
607
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
608
|
+
data: expectedResponseData,
|
|
609
|
+
statusCode: undefined, // code is undefined
|
|
610
|
+
errorMsg: undefined,
|
|
611
|
+
})
|
|
612
|
+
.call(callback, expectedResponseData)
|
|
613
|
+
.run();
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
describe('getTemplateDetails Saga', () => {
|
|
618
|
+
const templateId = 'template123';
|
|
619
|
+
|
|
620
|
+
it('should handle successful template details fetch', () => {
|
|
621
|
+
const mockResponse = {
|
|
622
|
+
response: {
|
|
623
|
+
id: 'template123',
|
|
624
|
+
name: 'Template Details',
|
|
625
|
+
content: 'Template content',
|
|
626
|
+
},
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
return expectSaga(getTemplateDetails, templateId)
|
|
630
|
+
.provide([
|
|
631
|
+
[matchers.call.fn(Api.getTemplateDetails), mockResponse],
|
|
632
|
+
])
|
|
633
|
+
.call(Api.getTemplateDetails, templateId)
|
|
634
|
+
.put({
|
|
635
|
+
type: types.GET_TEMPLATE_DETAILS_SUCCESS,
|
|
636
|
+
data: mockResponse.response,
|
|
637
|
+
})
|
|
638
|
+
.run();
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
it('should handle template details fetch failure', () => {
|
|
642
|
+
const error = new Error('Template not found');
|
|
643
|
+
|
|
644
|
+
return expectSaga(getTemplateDetails, templateId)
|
|
645
|
+
.provide([
|
|
646
|
+
[matchers.call.fn(Api.getTemplateDetails), throwError(error)],
|
|
647
|
+
])
|
|
648
|
+
.call(Api.getTemplateDetails, templateId)
|
|
649
|
+
.put({
|
|
650
|
+
type: types.GET_TEMPLATE_DETAILS_FAILURE,
|
|
651
|
+
error,
|
|
652
|
+
})
|
|
653
|
+
.run();
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
describe('getIosCtas Saga', () => {
|
|
658
|
+
const licenseCode = 'LICENSE123';
|
|
659
|
+
|
|
660
|
+
it('should handle successful iOS CTAs fetch', () => {
|
|
661
|
+
const mockResponse = {
|
|
662
|
+
response: {
|
|
663
|
+
metaEntities: {
|
|
664
|
+
data: [
|
|
665
|
+
{ id: 1, name: 'CTA 1' },
|
|
666
|
+
{ id: 2, name: 'CTA 2' },
|
|
667
|
+
],
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
status: { code: 200 },
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
return expectSaga(getIosCtas, licenseCode)
|
|
674
|
+
.provide([
|
|
675
|
+
[matchers.call.fn(Api.getIosCtas), mockResponse],
|
|
676
|
+
])
|
|
677
|
+
.call(Api.getIosCtas, licenseCode)
|
|
678
|
+
.put({
|
|
679
|
+
type: types.GET_IOS_CTAS_SUCCESS,
|
|
680
|
+
data: mockResponse.response.metaEntities.data,
|
|
681
|
+
statusCode: 200,
|
|
682
|
+
})
|
|
683
|
+
.run();
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
it('should handle iOS CTAs fetch failure', () => {
|
|
687
|
+
const error = new Error('Failed to fetch iOS CTAs');
|
|
688
|
+
|
|
689
|
+
return expectSaga(getIosCtas, licenseCode)
|
|
690
|
+
.provide([
|
|
691
|
+
[matchers.call.fn(Api.getIosCtas), throwError(error)],
|
|
692
|
+
])
|
|
693
|
+
.call(Api.getIosCtas, licenseCode)
|
|
694
|
+
.put({
|
|
695
|
+
type: types.GET_IOS_CTAS_FAILURE,
|
|
696
|
+
error,
|
|
697
|
+
})
|
|
698
|
+
.run();
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
it('should handle response without status code', () => {
|
|
702
|
+
const mockResponse = {
|
|
703
|
+
response: {
|
|
704
|
+
metaEntities: {
|
|
705
|
+
data: [{ id: 1, name: 'CTA 1' }],
|
|
706
|
+
},
|
|
707
|
+
},
|
|
708
|
+
status: null,
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
return expectSaga(getIosCtas, licenseCode)
|
|
712
|
+
.provide([
|
|
713
|
+
[matchers.call.fn(Api.getIosCtas), mockResponse],
|
|
714
|
+
])
|
|
715
|
+
.call(Api.getIosCtas, licenseCode)
|
|
716
|
+
.put({
|
|
717
|
+
type: types.GET_IOS_CTAS_SUCCESS,
|
|
718
|
+
data: mockResponse.response.metaEntities.data,
|
|
719
|
+
statusCode: '',
|
|
720
|
+
})
|
|
721
|
+
.run();
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
describe('getMobilepushTemplatesList Saga', () => {
|
|
726
|
+
const params = {
|
|
727
|
+
channel: 'mobilepush',
|
|
728
|
+
queryParams: {
|
|
729
|
+
page: 1,
|
|
730
|
+
limit: 10,
|
|
731
|
+
},
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
it('should handle successful templates list fetch', () => {
|
|
735
|
+
const mockResponse = {
|
|
736
|
+
response: {
|
|
737
|
+
templates: [
|
|
738
|
+
{ id: 1, name: 'Template 1' },
|
|
739
|
+
{ id: 2, name: 'Template 2' },
|
|
740
|
+
],
|
|
741
|
+
mapped: {
|
|
742
|
+
1: { id: 1, mapped: true },
|
|
743
|
+
2: { id: 2, mapped: true },
|
|
744
|
+
},
|
|
745
|
+
},
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
return expectSaga(getMobilepushTemplatesList, params)
|
|
749
|
+
.provide([
|
|
750
|
+
[matchers.call.fn(Api.getAllTemplates), mockResponse],
|
|
751
|
+
])
|
|
752
|
+
.call(Api.getAllTemplates, {
|
|
753
|
+
channel: params.channel,
|
|
754
|
+
queryParams: params.queryParams,
|
|
755
|
+
})
|
|
756
|
+
.put({
|
|
757
|
+
type: types.GET_MOBILEPUSH_TEMPLATES_LIST_SUCCESS,
|
|
758
|
+
data: mockResponse.response.templates,
|
|
759
|
+
templateData: mockResponse.response.mapped,
|
|
760
|
+
})
|
|
761
|
+
.run();
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
it('should handle templates list fetch failure', () => {
|
|
765
|
+
const error = new Error('Failed to fetch templates');
|
|
766
|
+
|
|
767
|
+
return expectSaga(getMobilepushTemplatesList, params)
|
|
768
|
+
.provide([
|
|
769
|
+
[matchers.call.fn(Api.getAllTemplates), throwError(error)],
|
|
770
|
+
])
|
|
771
|
+
.call(Api.getAllTemplates, {
|
|
772
|
+
channel: params.channel,
|
|
773
|
+
queryParams: params.queryParams,
|
|
774
|
+
})
|
|
775
|
+
.put({
|
|
776
|
+
type: types.GET_MOBILEPUSH_TEMPLATES_LIST_FAILURE,
|
|
777
|
+
error,
|
|
778
|
+
})
|
|
779
|
+
.run();
|
|
780
|
+
});
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
describe('fetchWeCrmAccounts Saga', () => {
|
|
784
|
+
const action = { source: 'WeChat' };
|
|
785
|
+
|
|
786
|
+
it('should handle successful WeChat CRM accounts fetch', () => {
|
|
787
|
+
const mockResponse = {
|
|
788
|
+
response: [
|
|
789
|
+
{ id: 1, name: 'Account 1' },
|
|
790
|
+
{ id: 2, name: 'Account 2' },
|
|
791
|
+
],
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
return expectSaga(fetchWeCrmAccounts, action)
|
|
795
|
+
.provide([
|
|
796
|
+
[matchers.call.fn(Api.fetchWeCrmAccounts), mockResponse],
|
|
797
|
+
])
|
|
798
|
+
.call(Api.fetchWeCrmAccounts, action.source)
|
|
799
|
+
.put({
|
|
800
|
+
type: types.GET_WECRM_ACCOUNTS_SUCCESS,
|
|
801
|
+
data: mockResponse.response,
|
|
802
|
+
})
|
|
803
|
+
.run();
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
it('should handle WeChat CRM accounts fetch failure', () => {
|
|
807
|
+
const error = new Error('Failed to fetch WeChat accounts');
|
|
808
|
+
|
|
809
|
+
return expectSaga(fetchWeCrmAccounts, action)
|
|
810
|
+
.provide([
|
|
811
|
+
[matchers.call.fn(Api.fetchWeCrmAccounts), throwError(error)],
|
|
812
|
+
])
|
|
813
|
+
.call(Api.fetchWeCrmAccounts, action.source)
|
|
814
|
+
.put({
|
|
815
|
+
type: types.GET_WECRM_ACCOUNTS_FAILURE,
|
|
816
|
+
data: error,
|
|
817
|
+
})
|
|
818
|
+
.run();
|
|
819
|
+
});
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
describe('Watcher Sagas', () => {
|
|
823
|
+
it('should watch for CREATE_TEMPLATE_REQUEST actions', () => {
|
|
824
|
+
const generator = watchCreateTemplate();
|
|
825
|
+
expect(generator.next().value).toEqual(
|
|
826
|
+
takeLatest(types.CREATE_TEMPLATE_REQUEST, createTemplate)
|
|
827
|
+
);
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
it('should watch for EDIT_TEMPLATE_REQUEST actions', () => {
|
|
831
|
+
const generator = watchEditTemplate();
|
|
832
|
+
expect(generator.next().value).toEqual(
|
|
833
|
+
takeLatest(types.EDIT_TEMPLATE_REQUEST, editTemplate)
|
|
834
|
+
);
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
it('should watch for UPLOAD_ASSET_REQUEST actions', () => {
|
|
838
|
+
const generator = watchUploadAsset();
|
|
839
|
+
expect(generator.next().value).toEqual(
|
|
840
|
+
takeLatest(types.UPLOAD_ASSET_REQUEST, uploadAsset)
|
|
841
|
+
);
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
it('should watch for GET_TEMPLATE_DETAILS_REQUEST actions', () => {
|
|
845
|
+
const generator = watchGetTemplateDetails();
|
|
846
|
+
expect(generator.next().value).toEqual(
|
|
847
|
+
takeLatest(types.GET_TEMPLATE_DETAILS_REQUEST, getTemplateDetails)
|
|
848
|
+
);
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
it('should watch for GET_IOS_CTAS actions', () => {
|
|
852
|
+
const generator = watchGetIosCtas();
|
|
853
|
+
expect(generator.next().value).toEqual(
|
|
854
|
+
takeLatest(types.GET_IOS_CTAS, getIosCtas)
|
|
855
|
+
);
|
|
856
|
+
});
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
describe('Combined Sagas', () => {
|
|
860
|
+
it('should initialize all v2MobilePushSagas without error', () => expectSaga(v2MobilePushSagas)
|
|
861
|
+
.run({ timeout: 1000 }));
|
|
862
|
+
});
|
|
863
|
+
});
|