@capillarytech/creatives-library 8.0.241 → 8.0.242-alpha.0
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/package.json +1 -1
- package/sagas/__tests__/assetPolling.test.js +607 -0
- package/sagas/assetPolling.js +156 -0
- package/services/api.js +16 -0
- package/services/tests/api.test.js +124 -0
- package/translations/en.json +1 -0
- package/utils/assetStatusConstants.js +12 -0
- package/utils/asyncAssetUpload.js +161 -0
- package/utils/tests/asyncAssetUpload.test.js +292 -0
- package/utils/transformerUtils.js +42 -0
- package/v2Components/CapImageUpload/constants.js +2 -0
- package/v2Components/CapImageUpload/index.js +54 -14
- package/v2Components/CapImageUpload/index.scss +4 -1
- package/v2Components/CapImageUpload/messages.js +4 -0
- package/v2Components/CapImageUrlUpload/constants.js +19 -0
- package/v2Components/CapImageUrlUpload/index.js +455 -0
- package/v2Components/CapImageUrlUpload/index.scss +35 -0
- package/v2Components/CapImageUrlUpload/messages.js +47 -0
- package/v2Containers/App/constants.js +5 -0
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +1 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +57 -2
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -0
- package/v2Containers/CreativesContainer/constants.js +2 -0
- package/v2Containers/CreativesContainer/index.js +152 -0
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +25 -0
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +18 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +46 -0
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +4 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +8 -0
- package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
- package/v2Containers/Templates/_templates.scss +203 -0
- package/v2Containers/Templates/actions.js +2 -1
- package/v2Containers/Templates/constants.js +1 -0
- package/v2Containers/Templates/index.js +273 -30
- package/v2Containers/Templates/messages.js +24 -0
- package/v2Containers/Templates/reducer.js +2 -0
- package/v2Containers/Templates/tests/index.test.js +10 -0
- package/v2Containers/TemplatesV2/index.js +3 -2
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/WebPush/Create/components/ButtonForm.js +175 -0
- package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
- package/v2Containers/WebPush/Create/components/ButtonList.js +144 -0
- package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +80 -0
- package/v2Containers/WebPush/Create/index.js +1755 -0
- package/v2Containers/WebPush/Create/index.scss +123 -0
- package/v2Containers/WebPush/Create/messages.js +199 -0
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +241 -0
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +290 -0
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +81 -0
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +240 -0
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +23 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +144 -0
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +44 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +110 -0
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +72 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +55 -0
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +70 -0
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +512 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +77 -0
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +527 -0
- package/v2Containers/WebPush/Create/preview/constants.js +162 -0
- package/v2Containers/WebPush/Create/preview/notification-container.scss +104 -0
- package/v2Containers/WebPush/Create/preview/preview.scss +409 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +300 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +303 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +188 -0
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +106 -0
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +75 -0
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +174 -0
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +909 -0
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1077 -0
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +943 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +128 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +121 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +127 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.js +116 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
- package/v2Containers/WebPush/actions.js +60 -0
- package/v2Containers/WebPush/constants.js +108 -0
- package/v2Containers/WebPush/index.js +2 -0
- package/v2Containers/WebPush/reducer.js +104 -0
- package/v2Containers/WebPush/sagas.js +119 -0
- package/v2Containers/WebPush/selectors.js +65 -0
- package/v2Containers/WebPush/tests/reducer.test.js +863 -0
- package/v2Containers/WebPush/tests/sagas.test.js +566 -0
- package/v2Containers/WebPush/tests/selectors.test.js +960 -0
- package/v2Containers/Whatsapp/constants.js +9 -0
- package/v2Containers/Whatsapp/reducer.js +34 -5
- package/v2Containers/Whatsapp/sagas.js +61 -10
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +132 -0
- package/v2Containers/Whatsapp/tests/reducer.test.js +188 -0
- package/v2Containers/Whatsapp/tests/saga.test.js +420 -7
|
@@ -5,6 +5,11 @@ import {
|
|
|
5
5
|
URL_META_TAGS_SUCCESS,
|
|
6
6
|
URL_META_TAGS_FAILURE,
|
|
7
7
|
URL_META_TAGS_RESET,
|
|
8
|
+
UPLOAD_WHATSAPP_ASSET_PROCESSING,
|
|
9
|
+
UPLOAD_WHATSAPP_ASSET_COMPLETED,
|
|
10
|
+
UPLOAD_WHATSAPP_ASSET_FAILED,
|
|
11
|
+
UPLOAD_WHATSAPP_ASSET_TIMEOUT,
|
|
12
|
+
CLEAR_WHATSAPP_ASSET,
|
|
8
13
|
} from "../constants";
|
|
9
14
|
import { mockData } from "./mockData";
|
|
10
15
|
|
|
@@ -60,4 +65,187 @@ describe("whatsapp reducer", () => {
|
|
|
60
65
|
.set("metaTagsDetails", {});
|
|
61
66
|
expect(whatsappReducer(state, action)).toEqual(expectedResult);
|
|
62
67
|
});
|
|
68
|
+
|
|
69
|
+
describe("Async upload processing state management", () => {
|
|
70
|
+
const mockAsset = {
|
|
71
|
+
_id: "asset-123",
|
|
72
|
+
type: "IMAGE",
|
|
73
|
+
url: "https://example.com/image.jpg",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
it.concurrent("Reducer : UPLOAD_WHATSAPP_ASSET_PROCESSING", () => {
|
|
77
|
+
const state = fromJS({
|
|
78
|
+
uploadedAssetData: {},
|
|
79
|
+
assetProcessing: {},
|
|
80
|
+
uploadAssetSuccess: false,
|
|
81
|
+
assetUploading: false,
|
|
82
|
+
});
|
|
83
|
+
const action = {
|
|
84
|
+
type: UPLOAD_WHATSAPP_ASSET_PROCESSING,
|
|
85
|
+
payload: {
|
|
86
|
+
assetId: "asset-123",
|
|
87
|
+
asset: mockAsset,
|
|
88
|
+
processingStatus: "processing",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
const result = whatsappReducer(state, action);
|
|
92
|
+
|
|
93
|
+
expect(result.get("uploadAssetSuccess")).toBe(false);
|
|
94
|
+
expect(result.get("assetUploading")).toBe(true);
|
|
95
|
+
expect(result.getIn(["assetProcessing", "asset-123", "status"])).toBe("processing");
|
|
96
|
+
expect(result.getIn(["assetProcessing", "asset-123", "asset"])).toEqual(fromJS(mockAsset));
|
|
97
|
+
expect(result.getIn(["assetProcessing", "asset-123", "startTime"])).toBeDefined();
|
|
98
|
+
expect(result.getIn(["assetProcessing", "asset-123", "error"])).toBe(null);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it.concurrent("Reducer : UPLOAD_WHATSAPP_ASSET_COMPLETED without templateType", () => {
|
|
102
|
+
const state = fromJS({
|
|
103
|
+
uploadedAssetData: {},
|
|
104
|
+
assetProcessing: {
|
|
105
|
+
"asset-123": {
|
|
106
|
+
status: "processing",
|
|
107
|
+
asset: mockAsset,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
uploadAssetSuccess: false,
|
|
111
|
+
assetUploading: true,
|
|
112
|
+
});
|
|
113
|
+
const action = {
|
|
114
|
+
type: UPLOAD_WHATSAPP_ASSET_COMPLETED,
|
|
115
|
+
payload: {
|
|
116
|
+
assetId: "asset-123",
|
|
117
|
+
asset: mockAsset,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const result = whatsappReducer(state, action);
|
|
121
|
+
|
|
122
|
+
expect(result.get("uploadAssetSuccess")).toBe(true);
|
|
123
|
+
expect(result.get("assetUploading")).toBe(false);
|
|
124
|
+
expect(result.get("uploadedAssetData")).toEqual(fromJS(mockAsset));
|
|
125
|
+
expect(result.getIn(["assetProcessing", "asset-123", "status"])).toBe("completed");
|
|
126
|
+
expect(result.getIn(["assetProcessing", "asset-123", "asset"])).toEqual(fromJS(mockAsset));
|
|
127
|
+
expect(result.getIn(["assetProcessing", "asset-123", "error"])).toBe(null);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it.concurrent("Reducer : UPLOAD_WHATSAPP_ASSET_COMPLETED with templateType", () => {
|
|
131
|
+
const state = fromJS({
|
|
132
|
+
uploadedAssetData: {},
|
|
133
|
+
uploadedAssetData2: {},
|
|
134
|
+
assetProcessing: {
|
|
135
|
+
"asset-123": {
|
|
136
|
+
status: "processing",
|
|
137
|
+
asset: mockAsset,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
uploadAssetSuccess: false,
|
|
141
|
+
assetUploading: true,
|
|
142
|
+
});
|
|
143
|
+
const action = {
|
|
144
|
+
type: UPLOAD_WHATSAPP_ASSET_COMPLETED,
|
|
145
|
+
payload: {
|
|
146
|
+
assetId: "asset-123",
|
|
147
|
+
asset: mockAsset,
|
|
148
|
+
},
|
|
149
|
+
templateType: 2,
|
|
150
|
+
};
|
|
151
|
+
const result = whatsappReducer(state, action);
|
|
152
|
+
|
|
153
|
+
expect(result.get("uploadAssetSuccess")).toBe(true);
|
|
154
|
+
expect(result.get("assetUploading")).toBe(false);
|
|
155
|
+
expect(result.get("uploadedAssetData2")).toEqual(fromJS(mockAsset));
|
|
156
|
+
expect(result.getIn(["assetProcessing", "asset-123", "status"])).toBe("completed");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it.concurrent("Reducer : UPLOAD_WHATSAPP_ASSET_FAILED", () => {
|
|
160
|
+
const state = fromJS({
|
|
161
|
+
assetProcessing: {
|
|
162
|
+
"asset-123": {
|
|
163
|
+
status: "processing",
|
|
164
|
+
asset: mockAsset,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
uploadAssetSuccess: false,
|
|
168
|
+
assetUploading: true,
|
|
169
|
+
});
|
|
170
|
+
const action = {
|
|
171
|
+
type: UPLOAD_WHATSAPP_ASSET_FAILED,
|
|
172
|
+
payload: {
|
|
173
|
+
assetId: "asset-123",
|
|
174
|
+
error: "Processing failed",
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
const result = whatsappReducer(state, action);
|
|
178
|
+
|
|
179
|
+
expect(result.get("uploadAssetSuccess")).toBe(false);
|
|
180
|
+
expect(result.get("assetUploading")).toBe(false);
|
|
181
|
+
expect(result.getIn(["assetProcessing", "asset-123", "status"])).toBe("failed");
|
|
182
|
+
expect(result.getIn(["assetProcessing", "asset-123", "error"])).toBe("Processing failed");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it.concurrent("Reducer : UPLOAD_WHATSAPP_ASSET_TIMEOUT", () => {
|
|
186
|
+
const state = fromJS({
|
|
187
|
+
assetProcessing: {
|
|
188
|
+
"asset-123": {
|
|
189
|
+
status: "processing",
|
|
190
|
+
asset: mockAsset,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
uploadAssetSuccess: false,
|
|
194
|
+
assetUploading: true,
|
|
195
|
+
});
|
|
196
|
+
const action = {
|
|
197
|
+
type: UPLOAD_WHATSAPP_ASSET_TIMEOUT,
|
|
198
|
+
payload: {
|
|
199
|
+
assetId: "asset-123",
|
|
200
|
+
message: "Asset processing is taking longer than expected",
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
const result = whatsappReducer(state, action);
|
|
204
|
+
|
|
205
|
+
expect(result.get("uploadAssetSuccess")).toBe(false);
|
|
206
|
+
expect(result.get("assetUploading")).toBe(false);
|
|
207
|
+
expect(result.getIn(["assetProcessing", "asset-123", "status"])).toBe("timeout");
|
|
208
|
+
expect(result.getIn(["assetProcessing", "asset-123", "error"])).toBe("Asset processing is taking longer than expected");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it.concurrent("Reducer : CLEAR_WHATSAPP_ASSET without templateType", () => {
|
|
212
|
+
const state = fromJS({
|
|
213
|
+
uploadedAssetData: mockAsset,
|
|
214
|
+
assetProcessing: {
|
|
215
|
+
"asset-123": {
|
|
216
|
+
status: "completed",
|
|
217
|
+
asset: mockAsset,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
const action = {
|
|
222
|
+
type: CLEAR_WHATSAPP_ASSET,
|
|
223
|
+
};
|
|
224
|
+
const result = whatsappReducer(state, action);
|
|
225
|
+
|
|
226
|
+
expect(result.has("uploadedAssetData")).toBe(false);
|
|
227
|
+
expect(result.get("assetProcessing")).toEqual(fromJS({}));
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it.concurrent("Reducer : CLEAR_WHATSAPP_ASSET with templateType", () => {
|
|
231
|
+
const state = fromJS({
|
|
232
|
+
uploadedAssetData: {},
|
|
233
|
+
uploadedAssetData2: mockAsset,
|
|
234
|
+
assetProcessing: {
|
|
235
|
+
"asset-123": {
|
|
236
|
+
status: "completed",
|
|
237
|
+
asset: mockAsset,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
const action = {
|
|
242
|
+
type: CLEAR_WHATSAPP_ASSET,
|
|
243
|
+
templateType: 2,
|
|
244
|
+
};
|
|
245
|
+
const result = whatsappReducer(state, action);
|
|
246
|
+
|
|
247
|
+
expect(result.has("uploadedAssetData2")).toBe(false);
|
|
248
|
+
expect(result.get("assetProcessing")).toEqual(fromJS({}));
|
|
249
|
+
});
|
|
250
|
+
});
|
|
63
251
|
});
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { expectSaga, testSaga } from "redux-saga-test-plan";
|
|
2
2
|
import * as matchers from "redux-saga-test-plan/matchers";
|
|
3
|
-
import { takeLatest } from "redux-saga/effects";
|
|
4
|
-
import { getMetaTagsDetails, watchGetMetaTagsDetails,v2WhatsappSagas, sendForApprovalCreate } from "../sagas";
|
|
3
|
+
import { takeLatest, call } from "redux-saga/effects";
|
|
4
|
+
import { getMetaTagsDetails, watchGetMetaTagsDetails, v2WhatsappSagas, sendForApprovalCreate, uploadWhatsappAsset } from "../sagas";
|
|
5
5
|
import {
|
|
6
6
|
URL_META_TAGS_REQUEST,
|
|
7
7
|
URL_META_TAGS_SUCCESS,
|
|
8
8
|
URL_META_TAGS_FAILURE,
|
|
9
9
|
TEMPLATE_CREATE_SUCCESS,
|
|
10
10
|
TEMPLATE_CREATE_FAILURE,
|
|
11
|
+
UPLOAD_WHATSAPP_ASSET_REQUEST,
|
|
12
|
+
UPLOAD_WHATSAPP_ASSET_SUCCESS,
|
|
13
|
+
UPLOAD_WHATSAPP_ASSET_FAILURE,
|
|
14
|
+
UPLOAD_WHATSAPP_ASSET_PROCESSING,
|
|
15
|
+
UPLOAD_WHATSAPP_ASSET_FAILED,
|
|
11
16
|
} from "../constants";
|
|
12
17
|
import * as Api from "../../../services/api";
|
|
18
|
+
import { pollAssetStatus } from "../../../sagas/assetPolling";
|
|
19
|
+
import { createPollingConfig } from "../../../utils/asyncAssetUpload";
|
|
13
20
|
import { mockData } from "./mockData";
|
|
14
21
|
|
|
15
22
|
describe("v2WhatsappSagas Combined", () => {
|
|
@@ -30,13 +37,13 @@ describe("Whatsapp saga", () => {
|
|
|
30
37
|
matchers.call.fn(Api.getMetaTags),
|
|
31
38
|
{
|
|
32
39
|
success: true,
|
|
33
|
-
|
|
40
|
+
response: [],
|
|
34
41
|
},
|
|
35
42
|
],
|
|
36
43
|
])
|
|
37
44
|
.put({
|
|
38
45
|
type: URL_META_TAGS_SUCCESS,
|
|
39
|
-
|
|
46
|
+
data: [],
|
|
40
47
|
})
|
|
41
48
|
.run();
|
|
42
49
|
});
|
|
@@ -107,13 +114,16 @@ describe("Whatsapp saga", () => {
|
|
|
107
114
|
matchers.call.fn(Api.createWhatsappTemplate),
|
|
108
115
|
{
|
|
109
116
|
success: true,
|
|
110
|
-
|
|
117
|
+
response: "Test data",
|
|
118
|
+
status: { code: 200 },
|
|
111
119
|
},
|
|
112
120
|
],
|
|
113
121
|
])
|
|
114
122
|
.put({
|
|
115
123
|
type: TEMPLATE_CREATE_SUCCESS,
|
|
116
|
-
|
|
124
|
+
data: "Test data",
|
|
125
|
+
statusCode: 200,
|
|
126
|
+
errorMsg: undefined,
|
|
117
127
|
})
|
|
118
128
|
.run();
|
|
119
129
|
});
|
|
@@ -131,6 +141,7 @@ describe("Whatsapp saga", () => {
|
|
|
131
141
|
.put({
|
|
132
142
|
type: TEMPLATE_CREATE_FAILURE,
|
|
133
143
|
error: "(#192) Param components[1]['buttons'][0]['phone_number'] is not a valid phone number.",
|
|
144
|
+
errorMsg: "(#192) Param components[1]['buttons'][0]['phone_number'] is not a valid phone number.",
|
|
134
145
|
})
|
|
135
146
|
.run();
|
|
136
147
|
});
|
|
@@ -147,7 +158,18 @@ describe("Whatsapp saga", () => {
|
|
|
147
158
|
])
|
|
148
159
|
.put({
|
|
149
160
|
type: TEMPLATE_CREATE_FAILURE,
|
|
150
|
-
error:
|
|
161
|
+
error: {
|
|
162
|
+
name: 'StatusCodeError',
|
|
163
|
+
statusCode: 500,
|
|
164
|
+
message: '500 - Invalid params',
|
|
165
|
+
error: { errorCode: '1004', errorMessage: 'Invalid params' }
|
|
166
|
+
},
|
|
167
|
+
errorMsg: {
|
|
168
|
+
name: 'StatusCodeError',
|
|
169
|
+
statusCode: 500,
|
|
170
|
+
message: '500 - Invalid params',
|
|
171
|
+
error: { errorCode: '1004', errorMessage: 'Invalid params' }
|
|
172
|
+
},
|
|
151
173
|
})
|
|
152
174
|
.run();
|
|
153
175
|
});
|
|
@@ -172,6 +194,7 @@ describe("Whatsapp saga", () => {
|
|
|
172
194
|
.put({
|
|
173
195
|
type: TEMPLATE_CREATE_FAILURE,
|
|
174
196
|
error: 'error',
|
|
197
|
+
errorMsg: 'error',
|
|
175
198
|
})
|
|
176
199
|
.run();
|
|
177
200
|
});
|
|
@@ -195,6 +218,7 @@ describe("Whatsapp saga", () => {
|
|
|
195
218
|
.put({
|
|
196
219
|
type: TEMPLATE_CREATE_FAILURE,
|
|
197
220
|
error: 500,
|
|
221
|
+
errorMsg: 500,
|
|
198
222
|
})
|
|
199
223
|
.run();
|
|
200
224
|
});
|
|
@@ -203,6 +227,395 @@ describe("Whatsapp saga", () => {
|
|
|
203
227
|
testSaga(sendForApprovalCreate, { callBack }).next().throw(error).next().isDone();
|
|
204
228
|
});
|
|
205
229
|
});
|
|
230
|
+
|
|
231
|
+
describe("uploadWhatsappAsset saga", () => {
|
|
232
|
+
const mockAsset = {
|
|
233
|
+
_id: "asset-123",
|
|
234
|
+
type: "IMAGE",
|
|
235
|
+
url: "https://example.com/image.jpg",
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const mockParams = {
|
|
239
|
+
file: new File(["test"], "test.jpg", { type: "image/jpeg" }),
|
|
240
|
+
assetType: "image",
|
|
241
|
+
fileParams: {},
|
|
242
|
+
templateType: 0,
|
|
243
|
+
whatsappParams: {},
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
it("should handle async upload flow (202 status code)", () => {
|
|
247
|
+
const mockResponse = {
|
|
248
|
+
status: { code: 202 },
|
|
249
|
+
response: {
|
|
250
|
+
assetId: "asset-123",
|
|
251
|
+
asset: mockAsset,
|
|
252
|
+
processingStatus: "processing",
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
257
|
+
.provide([
|
|
258
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
259
|
+
[
|
|
260
|
+
matchers.call.fn(pollAssetStatus),
|
|
261
|
+
undefined,
|
|
262
|
+
],
|
|
263
|
+
])
|
|
264
|
+
.put({
|
|
265
|
+
type: UPLOAD_WHATSAPP_ASSET_PROCESSING,
|
|
266
|
+
payload: {
|
|
267
|
+
assetId: "asset-123",
|
|
268
|
+
asset: mockAsset,
|
|
269
|
+
processingStatus: "processing",
|
|
270
|
+
},
|
|
271
|
+
})
|
|
272
|
+
.call.fn(Api.uploadFile)
|
|
273
|
+
.call.fn(pollAssetStatus)
|
|
274
|
+
.run();
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("should handle async upload flow with processingStatus in response", () => {
|
|
278
|
+
const mockResponse = {
|
|
279
|
+
status: { code: 200 },
|
|
280
|
+
response: {
|
|
281
|
+
assetId: "asset-123",
|
|
282
|
+
asset: mockAsset,
|
|
283
|
+
processingStatus: "processing",
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
288
|
+
.provide([
|
|
289
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
290
|
+
[matchers.call.fn(pollAssetStatus), undefined],
|
|
291
|
+
])
|
|
292
|
+
.put({
|
|
293
|
+
type: UPLOAD_WHATSAPP_ASSET_PROCESSING,
|
|
294
|
+
payload: {
|
|
295
|
+
assetId: "asset-123",
|
|
296
|
+
asset: mockAsset,
|
|
297
|
+
processingStatus: "processing",
|
|
298
|
+
},
|
|
299
|
+
})
|
|
300
|
+
.call.fn(Api.uploadFile)
|
|
301
|
+
.call.fn(pollAssetStatus)
|
|
302
|
+
.run();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("should handle sync upload flow (201 status code)", () => {
|
|
306
|
+
const mockResponse = {
|
|
307
|
+
status: { code: 201 },
|
|
308
|
+
response: {
|
|
309
|
+
asset: mockAsset,
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
314
|
+
.provide([
|
|
315
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
316
|
+
])
|
|
317
|
+
.put({
|
|
318
|
+
type: UPLOAD_WHATSAPP_ASSET_SUCCESS,
|
|
319
|
+
data: mockAsset,
|
|
320
|
+
statusCode: 201,
|
|
321
|
+
templateType: 0,
|
|
322
|
+
})
|
|
323
|
+
.not.call(pollAssetStatus)
|
|
324
|
+
.run();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it("should handle sync upload flow (200 status code)", () => {
|
|
328
|
+
const mockResponse = {
|
|
329
|
+
status: { code: 200 },
|
|
330
|
+
response: {
|
|
331
|
+
asset: mockAsset,
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
336
|
+
.provide([
|
|
337
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
338
|
+
])
|
|
339
|
+
.put({
|
|
340
|
+
type: UPLOAD_WHATSAPP_ASSET_SUCCESS,
|
|
341
|
+
data: mockAsset,
|
|
342
|
+
statusCode: 200,
|
|
343
|
+
templateType: 0,
|
|
344
|
+
})
|
|
345
|
+
.not.call(pollAssetStatus)
|
|
346
|
+
.run();
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("should extract assetId from asset._id when assetId is not present", () => {
|
|
350
|
+
const mockResponse = {
|
|
351
|
+
status: { code: 202 },
|
|
352
|
+
response: {
|
|
353
|
+
asset: { ...mockAsset, _id: "asset-456" },
|
|
354
|
+
processingStatus: "processing",
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
359
|
+
.provide([
|
|
360
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
361
|
+
[matchers.call.fn(pollAssetStatus), undefined],
|
|
362
|
+
])
|
|
363
|
+
.put({
|
|
364
|
+
type: UPLOAD_WHATSAPP_ASSET_PROCESSING,
|
|
365
|
+
payload: {
|
|
366
|
+
assetId: "asset-456",
|
|
367
|
+
asset: { ...mockAsset, _id: "asset-456" },
|
|
368
|
+
processingStatus: "processing",
|
|
369
|
+
},
|
|
370
|
+
})
|
|
371
|
+
.call.fn(Api.uploadFile)
|
|
372
|
+
.call.fn(pollAssetStatus)
|
|
373
|
+
.run()
|
|
374
|
+
.then((result) => {
|
|
375
|
+
// Verify the polling config has the correct assetId
|
|
376
|
+
// Find the pollAssetStatus call by checking function name
|
|
377
|
+
const allEffects = result.allEffects || [];
|
|
378
|
+
const pollCall = allEffects.find(effect =>
|
|
379
|
+
effect && effect.CALL && effect.CALL.fn && effect.CALL.fn.name === 'pollAssetStatus'
|
|
380
|
+
);
|
|
381
|
+
expect(pollCall).toBeDefined();
|
|
382
|
+
expect(pollCall.CALL.args[0]).toMatchObject({
|
|
383
|
+
assetId: "asset-456",
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it("should use assetType from params for polling", () => {
|
|
389
|
+
const videoParams = {
|
|
390
|
+
...mockParams,
|
|
391
|
+
assetType: "video",
|
|
392
|
+
};
|
|
393
|
+
const mockResponse = {
|
|
394
|
+
status: { code: 202 },
|
|
395
|
+
response: {
|
|
396
|
+
assetId: "asset-123",
|
|
397
|
+
asset: { ...mockAsset, type: "VIDEO" },
|
|
398
|
+
processingStatus: "processing",
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
return expectSaga(uploadWhatsappAsset, videoParams)
|
|
403
|
+
.provide([
|
|
404
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
405
|
+
[matchers.call.fn(pollAssetStatus), undefined],
|
|
406
|
+
])
|
|
407
|
+
.call.fn(Api.uploadFile)
|
|
408
|
+
.call.fn(pollAssetStatus)
|
|
409
|
+
.run()
|
|
410
|
+
.then((result) => {
|
|
411
|
+
const allEffects = result.allEffects || [];
|
|
412
|
+
const pollCall = allEffects.find(effect =>
|
|
413
|
+
effect && effect.CALL && effect.CALL.fn && effect.CALL.fn.name === 'pollAssetStatus'
|
|
414
|
+
);
|
|
415
|
+
expect(pollCall).toBeDefined();
|
|
416
|
+
expect(pollCall.CALL.args[0]).toMatchObject({
|
|
417
|
+
type: "video",
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it("should fallback to asset.type from response when assetType not in params", () => {
|
|
423
|
+
const paramsWithoutAssetType = {
|
|
424
|
+
...mockParams,
|
|
425
|
+
assetType: undefined,
|
|
426
|
+
};
|
|
427
|
+
const mockResponse = {
|
|
428
|
+
status: { code: 202 },
|
|
429
|
+
response: {
|
|
430
|
+
assetId: "asset-123",
|
|
431
|
+
asset: { ...mockAsset, type: "VIDEO" },
|
|
432
|
+
processingStatus: "processing",
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
return expectSaga(uploadWhatsappAsset, paramsWithoutAssetType)
|
|
437
|
+
.provide([
|
|
438
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
439
|
+
[matchers.call.fn(pollAssetStatus), undefined],
|
|
440
|
+
])
|
|
441
|
+
.call.fn(Api.uploadFile)
|
|
442
|
+
.call.fn(pollAssetStatus)
|
|
443
|
+
.run()
|
|
444
|
+
.then((result) => {
|
|
445
|
+
const allEffects = result.allEffects || [];
|
|
446
|
+
const pollCall = allEffects.find(effect =>
|
|
447
|
+
effect && effect.CALL && effect.CALL.fn && effect.CALL.fn.name === 'pollAssetStatus'
|
|
448
|
+
);
|
|
449
|
+
expect(pollCall).toBeDefined();
|
|
450
|
+
expect(pollCall.CALL.args[0]).toMatchObject({
|
|
451
|
+
type: "video",
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it("should default to 'image' when assetType is not available", () => {
|
|
457
|
+
const paramsWithoutAssetType = {
|
|
458
|
+
...mockParams,
|
|
459
|
+
assetType: undefined,
|
|
460
|
+
};
|
|
461
|
+
const mockResponse = {
|
|
462
|
+
status: { code: 202 },
|
|
463
|
+
response: {
|
|
464
|
+
assetId: "asset-123",
|
|
465
|
+
asset: { ...mockAsset, type: undefined },
|
|
466
|
+
processingStatus: "processing",
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
return expectSaga(uploadWhatsappAsset, paramsWithoutAssetType)
|
|
471
|
+
.provide([
|
|
472
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
473
|
+
[matchers.call.fn(pollAssetStatus), undefined],
|
|
474
|
+
])
|
|
475
|
+
.call.fn(Api.uploadFile)
|
|
476
|
+
.call.fn(pollAssetStatus)
|
|
477
|
+
.run()
|
|
478
|
+
.then((result) => {
|
|
479
|
+
const allEffects = result.allEffects || [];
|
|
480
|
+
const pollCall = allEffects.find(effect =>
|
|
481
|
+
effect && effect.CALL && effect.CALL.fn && effect.CALL.fn.name === 'pollAssetStatus'
|
|
482
|
+
);
|
|
483
|
+
expect(pollCall).toBeDefined();
|
|
484
|
+
expect(pollCall.CALL.args[0]).toMatchObject({
|
|
485
|
+
type: "image",
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
it("should dispatch FAILED action if assetId is missing", () => {
|
|
491
|
+
const mockResponse = {
|
|
492
|
+
status: { code: 202 },
|
|
493
|
+
response: {
|
|
494
|
+
processingStatus: "processing",
|
|
495
|
+
// No assetId or asset._id
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
500
|
+
.provide([
|
|
501
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
502
|
+
])
|
|
503
|
+
.put({
|
|
504
|
+
type: UPLOAD_WHATSAPP_ASSET_FAILED,
|
|
505
|
+
payload: {
|
|
506
|
+
assetId: undefined,
|
|
507
|
+
error: 'Asset upload initiated but no asset ID was returned from the server. Unable to track processing status.',
|
|
508
|
+
},
|
|
509
|
+
templateType: 0,
|
|
510
|
+
})
|
|
511
|
+
.not.put({ type: UPLOAD_WHATSAPP_ASSET_PROCESSING })
|
|
512
|
+
.not.call(pollAssetStatus)
|
|
513
|
+
.run();
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it("should handle error during upload", () => {
|
|
517
|
+
const uploadError = new Error("Upload failed");
|
|
518
|
+
|
|
519
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
520
|
+
.provide([
|
|
521
|
+
[
|
|
522
|
+
matchers.call.fn(Api.uploadFile),
|
|
523
|
+
Promise.reject(uploadError),
|
|
524
|
+
],
|
|
525
|
+
])
|
|
526
|
+
.put({
|
|
527
|
+
type: UPLOAD_WHATSAPP_ASSET_FAILURE,
|
|
528
|
+
error: uploadError,
|
|
529
|
+
})
|
|
530
|
+
.run();
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it("should pass templateType to polling config", () => {
|
|
534
|
+
const paramsWithTemplateType = {
|
|
535
|
+
...mockParams,
|
|
536
|
+
templateType: 2,
|
|
537
|
+
};
|
|
538
|
+
const mockResponse = {
|
|
539
|
+
status: { code: 202 },
|
|
540
|
+
response: {
|
|
541
|
+
assetId: "asset-123",
|
|
542
|
+
asset: mockAsset,
|
|
543
|
+
processingStatus: "processing",
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
return expectSaga(uploadWhatsappAsset, paramsWithTemplateType)
|
|
548
|
+
.provide([
|
|
549
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
550
|
+
[matchers.call.fn(pollAssetStatus), undefined],
|
|
551
|
+
])
|
|
552
|
+
.call.fn(Api.uploadFile)
|
|
553
|
+
.call.fn(pollAssetStatus)
|
|
554
|
+
.run()
|
|
555
|
+
.then((result) => {
|
|
556
|
+
// Verify that the polling config includes templateType
|
|
557
|
+
const allEffects = result.allEffects || [];
|
|
558
|
+
const pollCall = allEffects.find(effect =>
|
|
559
|
+
effect && effect.CALL && effect.CALL.fn && effect.CALL.fn.name === 'pollAssetStatus'
|
|
560
|
+
);
|
|
561
|
+
expect(pollCall).toBeDefined();
|
|
562
|
+
const pollingConfig = pollCall.CALL.args[0];
|
|
563
|
+
expect(pollingConfig).toMatchObject({
|
|
564
|
+
onCompleted: expect.any(Function),
|
|
565
|
+
});
|
|
566
|
+
const completedAction = pollingConfig.onCompleted({ assetId: "asset-123", asset: mockAsset });
|
|
567
|
+
expect(completedAction.templateType).toBe(2);
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it("should handle statusCode from result.statusCode", () => {
|
|
572
|
+
const mockResponse = {
|
|
573
|
+
statusCode: 202,
|
|
574
|
+
response: {
|
|
575
|
+
assetId: "asset-123",
|
|
576
|
+
asset: mockAsset,
|
|
577
|
+
processingStatus: "processing",
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
582
|
+
.provide([
|
|
583
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
584
|
+
[matchers.call.fn(pollAssetStatus), undefined],
|
|
585
|
+
])
|
|
586
|
+
.put({
|
|
587
|
+
type: UPLOAD_WHATSAPP_ASSET_PROCESSING,
|
|
588
|
+
payload: {
|
|
589
|
+
assetId: "asset-123",
|
|
590
|
+
asset: mockAsset,
|
|
591
|
+
processingStatus: "processing",
|
|
592
|
+
},
|
|
593
|
+
})
|
|
594
|
+
.call.fn(Api.uploadFile)
|
|
595
|
+
.call.fn(pollAssetStatus)
|
|
596
|
+
.run();
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it("should handle empty response gracefully", () => {
|
|
600
|
+
const mockResponse = {
|
|
601
|
+
status: { code: 200 },
|
|
602
|
+
response: {},
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
return expectSaga(uploadWhatsappAsset, mockParams)
|
|
606
|
+
.provide([
|
|
607
|
+
[matchers.call.fn(Api.uploadFile), mockResponse],
|
|
608
|
+
])
|
|
609
|
+
.put({
|
|
610
|
+
type: UPLOAD_WHATSAPP_ASSET_SUCCESS,
|
|
611
|
+
data: undefined,
|
|
612
|
+
statusCode: 200,
|
|
613
|
+
templateType: 0,
|
|
614
|
+
})
|
|
615
|
+
.run();
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
|
|
206
619
|
});
|
|
207
620
|
|
|
208
621
|
|