@capillarytech/creatives-library 8.0.271 → 8.0.273
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/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +2 -1
- package/initialReducer.js +2 -0
- package/package.json +1 -1
- package/services/api.js +10 -0
- package/services/tests/api.test.js +34 -0
- package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +17 -35
- package/tests/integration/TemplateCreation/api-response.js +31 -1
- package/tests/integration/TemplateCreation/msw-handler.js +2 -0
- package/utils/common.js +5 -0
- package/utils/commonUtils.js +28 -5
- package/utils/imageUrlUpload.js +13 -14
- package/utils/tests/commonUtil.test.js +224 -0
- package/utils/tests/imageUrlUpload.test.js +298 -0
- package/utils/transformTemplateConfig.js +0 -10
- package/v2Components/CapDeviceContent/index.js +61 -56
- package/v2Components/CapTagList/index.js +6 -1
- package/v2Components/CapTagListWithInput/index.js +5 -1
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
- package/v2Components/ErrorInfoNote/constants.js +1 -0
- package/v2Components/ErrorInfoNote/index.js +402 -72
- package/v2Components/ErrorInfoNote/messages.js +32 -6
- package/v2Components/ErrorInfoNote/style.scss +278 -6
- package/v2Components/FormBuilder/tests/index.test.js +13 -4
- package/v2Components/HtmlEditor/HTMLEditor.js +418 -99
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +870 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1882 -133
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
- package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
- package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +23 -102
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +148 -140
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +9 -1
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +31 -6
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +22 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +7 -10
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +22 -43
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +18 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +36 -31
- package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +46 -34
- package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +6 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +52 -46
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +277 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +295 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
- package/v2Components/HtmlEditor/constants.js +45 -20
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +351 -16
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
- package/v2Components/HtmlEditor/hooks/useValidation.js +213 -56
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +102 -94
- package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +214 -45
- package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +134 -0
- package/v2Components/HtmlEditor/utils/contentSanitizer.js +40 -41
- package/v2Components/HtmlEditor/utils/htmlValidator.js +71 -72
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +158 -124
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
- package/v2Components/HtmlEditor/utils/validationAdapter.js +66 -41
- package/v2Components/HtmlEditor/utils/validationConstants.js +38 -0
- package/v2Components/MobilePushPreviewV2/constants.js +6 -0
- package/v2Components/MobilePushPreviewV2/index.js +33 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +55 -24
- package/v2Components/TemplatePreview/index.js +47 -32
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +1 -0
- package/v2Containers/BeeEditor/index.js +172 -90
- package/v2Containers/BeePopupEditor/_beePopupEditor.scss +14 -0
- package/v2Containers/BeePopupEditor/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +194 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -51
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +156 -13
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -1
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +251 -47
- package/v2Containers/CreativesContainer/messages.js +8 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +11 -2
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +103 -0
- package/v2Containers/Email/actions.js +7 -0
- package/v2Containers/Email/constants.js +5 -1
- package/v2Containers/Email/index.js +234 -29
- package/v2Containers/Email/messages.js +32 -0
- package/v2Containers/Email/reducer.js +12 -1
- package/v2Containers/Email/sagas.js +61 -7
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
- package/v2Containers/Email/tests/reducer.test.js +46 -0
- package/v2Containers/Email/tests/sagas.test.js +320 -29
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1246 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +212 -21
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +2614 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +520 -0
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +627 -79
- package/v2Containers/EmailWrapper/index.js +103 -23
- package/v2Containers/EmailWrapper/messages.js +65 -1
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +955 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +596 -82
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
- package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
- package/v2Containers/InApp/actions.js +7 -0
- package/v2Containers/InApp/constants.js +20 -4
- package/v2Containers/InApp/index.js +802 -360
- package/v2Containers/InApp/index.scss +4 -3
- package/v2Containers/InApp/messages.js +7 -3
- package/v2Containers/InApp/reducer.js +21 -3
- package/v2Containers/InApp/sagas.js +29 -9
- package/v2Containers/InApp/selectors.js +25 -5
- package/v2Containers/InApp/tests/index.test.js +154 -50
- package/v2Containers/InApp/tests/reducer.test.js +34 -0
- package/v2Containers/InApp/tests/sagas.test.js +61 -9
- package/v2Containers/InApp/tests/selectors.test.js +612 -0
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +151 -0
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +23 -0
- package/v2Containers/InAppWrapper/constants.js +16 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
- package/v2Containers/InAppWrapper/index.js +148 -0
- package/v2Containers/InAppWrapper/messages.js +49 -0
- package/v2Containers/InappAdvance/index.js +1099 -0
- package/v2Containers/InappAdvance/index.scss +10 -0
- package/v2Containers/InappAdvance/tests/index.test.js +448 -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 +2 -0
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
- package/v2Containers/MobilePush/Create/index.js +1 -1
- package/v2Containers/MobilePush/Edit/index.js +10 -6
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
- package/v2Containers/TagList/index.js +62 -19
- package/v2Containers/Templates/_templates.scss +60 -1
- package/v2Containers/Templates/index.js +89 -4
- package/v2Containers/Templates/messages.js +4 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +4 -2
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +0 -152
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import useEmailWrapper from '../hooks/useEmailWrapper';
|
|
3
|
-
import { EmailWrapperMockData } from '../mockdata/mockdata';
|
|
4
1
|
import _, { isEmpty, find } from 'lodash';
|
|
5
2
|
import { renderHook, waitFor, act as reactAct } from '@testing-library/react';
|
|
3
|
+
import useEmailWrapper from '../hooks/useEmailWrapper';
|
|
4
|
+
import { EmailWrapperMockData } from '../mockdata/mockdata';
|
|
6
5
|
import { EMAIL_CREATE_MODES, STEPS } from '../constants';
|
|
7
|
-
import { GA } from '@capillarytech/cap-ui-utils';
|
|
8
6
|
import { gtmPush } from '../../../utils/gtmTrackers';
|
|
9
7
|
|
|
10
8
|
// Mock dependencies
|
|
11
9
|
jest.mock('lodash', () => ({
|
|
12
10
|
...jest.requireActual('lodash'),
|
|
13
|
-
isEmpty: jest.fn().mockImplementation(val => {
|
|
11
|
+
isEmpty: jest.fn().mockImplementation((val) => {
|
|
14
12
|
if (val === null || val === undefined) return true;
|
|
15
13
|
if (typeof val === 'object') return Object.keys(val).length === 0;
|
|
16
14
|
if (typeof val === 'string') return val.trim().length === 0;
|
|
@@ -31,6 +29,10 @@ jest.mock('../../../utils/gtmTrackers', () => ({
|
|
|
31
29
|
gtmPush: jest.fn(),
|
|
32
30
|
}));
|
|
33
31
|
|
|
32
|
+
jest.mock('../../../utils/common', () => ({
|
|
33
|
+
hasSupportCKEditor: jest.fn(() => true), // Default to legacy flow
|
|
34
|
+
}));
|
|
35
|
+
|
|
34
36
|
const mockStopTimer = jest.fn();
|
|
35
37
|
|
|
36
38
|
jest.mock('@capillarytech/cap-ui-utils', () => ({
|
|
@@ -39,8 +41,8 @@ jest.mock('@capillarytech/cap-ui-utils', () => ({
|
|
|
39
41
|
timeTracker: {
|
|
40
42
|
startTimer: jest.fn(),
|
|
41
43
|
stopTimer: jest.fn(),
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
+
},
|
|
45
|
+
},
|
|
44
46
|
}));
|
|
45
47
|
|
|
46
48
|
describe('useEmailWrapper', () => {
|
|
@@ -54,12 +56,12 @@ describe('useEmailWrapper', () => {
|
|
|
54
56
|
gtmPush.mockClear();
|
|
55
57
|
mockStopTimer.mockClear();
|
|
56
58
|
|
|
57
|
-
isEmpty.mockImplementation(val => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
isEmpty.mockImplementation((val) => {
|
|
60
|
+
if (val === null || val === undefined) return true;
|
|
61
|
+
if (typeof val === 'object') return Object.keys(val).length === 0;
|
|
62
|
+
if (typeof val === 'string') return val.trim().length === 0;
|
|
63
|
+
return !val;
|
|
64
|
+
});
|
|
63
65
|
|
|
64
66
|
mockProps = {
|
|
65
67
|
...EmailWrapperMockData,
|
|
@@ -149,13 +151,11 @@ describe('useEmailWrapper', () => {
|
|
|
149
151
|
result.current.onChange({ target: { value: EMAIL_CREATE_MODES.UPLOAD } });
|
|
150
152
|
});
|
|
151
153
|
|
|
152
|
-
|
|
154
|
+
// onEmailModeChange is called with (mappedValue, value) - both are UPLOAD in this case
|
|
155
|
+
expect(mockProps.onEmailModeChange).toHaveBeenCalledWith(EMAIL_CREATE_MODES.UPLOAD, EMAIL_CREATE_MODES.UPLOAD);
|
|
153
156
|
});
|
|
154
157
|
|
|
155
158
|
it('handles zip file upload correctly and calls success callbacks', () => {
|
|
156
|
-
const successCallback = mockProps.showNextStep;
|
|
157
|
-
const errorCallback = jest.fn();
|
|
158
|
-
|
|
159
159
|
mockProps.templatesActions.handleZipUpload.mockImplementation((file, onSuccess, onError) => {
|
|
160
160
|
onSuccess();
|
|
161
161
|
});
|
|
@@ -168,7 +168,7 @@ describe('useEmailWrapper', () => {
|
|
|
168
168
|
const mockFile = {
|
|
169
169
|
name: 'test.zip',
|
|
170
170
|
size: 1024 * 1024,
|
|
171
|
-
originFileObj: new Blob(['test data'], { type: 'application/zip' })
|
|
171
|
+
originFileObj: new Blob(['test data'], { type: 'application/zip' }),
|
|
172
172
|
};
|
|
173
173
|
|
|
174
174
|
reactAct(() => {
|
|
@@ -181,9 +181,9 @@ describe('useEmailWrapper', () => {
|
|
|
181
181
|
expect.any(Function)
|
|
182
182
|
);
|
|
183
183
|
|
|
184
|
-
// expect(mockStopTimer).toHaveBeenCalled();
|
|
185
184
|
expect(gtmPush).toHaveBeenCalled();
|
|
186
|
-
|
|
185
|
+
// User must enter template name and click Continue in footer; no auto-advance after upload
|
|
186
|
+
expect(mockProps.showNextStep).not.toHaveBeenCalled();
|
|
187
187
|
expect(mockCapNotificationError).not.toHaveBeenCalled();
|
|
188
188
|
expect(result.current.modeContent).toEqual({ file: mockFile });
|
|
189
189
|
});
|
|
@@ -201,7 +201,7 @@ describe('useEmailWrapper', () => {
|
|
|
201
201
|
const mockFile = {
|
|
202
202
|
name: 'test.zip',
|
|
203
203
|
size: 1024 * 1024,
|
|
204
|
-
originFileObj: new Blob(['test data'], { type: 'application/zip' })
|
|
204
|
+
originFileObj: new Blob(['test data'], { type: 'application/zip' }),
|
|
205
205
|
};
|
|
206
206
|
|
|
207
207
|
reactAct(() => {
|
|
@@ -218,13 +218,13 @@ describe('useEmailWrapper', () => {
|
|
|
218
218
|
const mockFile = {
|
|
219
219
|
name: 'test.html',
|
|
220
220
|
size: 1024,
|
|
221
|
-
originFileObj: new Blob([mockHtmlContent], { type: 'text/html' })
|
|
221
|
+
originFileObj: new Blob([mockHtmlContent], { type: 'text/html' }),
|
|
222
222
|
};
|
|
223
223
|
|
|
224
224
|
const mockReader = {
|
|
225
225
|
onload: null,
|
|
226
226
|
onerror: null,
|
|
227
|
-
readAsText: jest.fn(function() {
|
|
227
|
+
readAsText: jest.fn(function () {
|
|
228
228
|
this.result = mockHtmlContent;
|
|
229
229
|
if (this.onload) {
|
|
230
230
|
this.onload();
|
|
@@ -257,13 +257,13 @@ describe('useEmailWrapper', () => {
|
|
|
257
257
|
it('shows error for invalid file type during upload', () => {
|
|
258
258
|
const { result } = renderHook(() => useEmailWrapper({
|
|
259
259
|
...mockProps,
|
|
260
|
-
isUploading: false
|
|
260
|
+
isUploading: false,
|
|
261
261
|
}));
|
|
262
262
|
|
|
263
263
|
const mockFile = {
|
|
264
264
|
name: 'test.txt',
|
|
265
265
|
size: 1024,
|
|
266
|
-
originFileObj: new Blob(['test data'], { type: 'text/plain' })
|
|
266
|
+
originFileObj: new Blob(['test data'], { type: 'text/plain' }),
|
|
267
267
|
};
|
|
268
268
|
|
|
269
269
|
reactAct(() => {
|
|
@@ -280,13 +280,13 @@ describe('useEmailWrapper', () => {
|
|
|
280
280
|
it('shows error for oversized file during upload', () => {
|
|
281
281
|
const { result } = renderHook(() => useEmailWrapper({
|
|
282
282
|
...mockProps,
|
|
283
|
-
isUploading: false
|
|
283
|
+
isUploading: false,
|
|
284
284
|
}));
|
|
285
285
|
|
|
286
286
|
const mockFile = {
|
|
287
287
|
name: 'large_file.zip',
|
|
288
288
|
size: 6 * 1024 * 1024,
|
|
289
|
-
originFileObj: new Blob(['large data'], { type: 'application/zip' })
|
|
289
|
+
originFileObj: new Blob(['large data'], { type: 'application/zip' }),
|
|
290
290
|
};
|
|
291
291
|
|
|
292
292
|
reactAct(() => {
|
|
@@ -294,7 +294,7 @@ describe('useEmailWrapper', () => {
|
|
|
294
294
|
});
|
|
295
295
|
|
|
296
296
|
expect(mockCapNotificationError).toHaveBeenCalledWith(expect.objectContaining({
|
|
297
|
-
|
|
297
|
+
key: "email-upload-error",
|
|
298
298
|
}));
|
|
299
299
|
expect(mockProps.templatesActions.handleZipUpload).not.toHaveBeenCalled();
|
|
300
300
|
});
|
|
@@ -302,21 +302,21 @@ describe('useEmailWrapper', () => {
|
|
|
302
302
|
it('shows error if no file or originFileObj is provided for upload', () => {
|
|
303
303
|
const { result } = renderHook(() => useEmailWrapper({
|
|
304
304
|
...mockProps,
|
|
305
|
-
isUploading: false
|
|
305
|
+
isUploading: false,
|
|
306
306
|
}));
|
|
307
307
|
|
|
308
308
|
reactAct(() => {
|
|
309
309
|
result.current.useFileUpload({ file: null });
|
|
310
310
|
});
|
|
311
311
|
expect(mockCapNotificationError).toHaveBeenCalledTimes(1);
|
|
312
|
-
expect(mockCapNotificationError).toHaveBeenCalledWith(expect.objectContaining({ key: "email-upload-error"}));
|
|
312
|
+
expect(mockCapNotificationError).toHaveBeenCalledWith(expect.objectContaining({ key: "email-upload-error" }));
|
|
313
313
|
|
|
314
314
|
mockCapNotificationError.mockClear();
|
|
315
315
|
reactAct(() => {
|
|
316
|
-
|
|
316
|
+
result.current.useFileUpload({ file: { name: 'test.zip', size: 100 } });
|
|
317
317
|
});
|
|
318
318
|
expect(mockCapNotificationError).toHaveBeenCalledTimes(1);
|
|
319
|
-
expect(mockCapNotificationError).toHaveBeenCalledWith(expect.objectContaining({ key: "email-upload-error"}));
|
|
319
|
+
expect(mockCapNotificationError).toHaveBeenCalledWith(expect.objectContaining({ key: "email-upload-error" }));
|
|
320
320
|
|
|
321
321
|
expect(mockProps.templatesActions.handleZipUpload).not.toHaveBeenCalled();
|
|
322
322
|
expect(mockProps.templatesActions.handleHtmlUpload).not.toHaveBeenCalled();
|
|
@@ -335,6 +335,10 @@ describe('useEmailWrapper', () => {
|
|
|
335
335
|
});
|
|
336
336
|
|
|
337
337
|
it('calls getDefaultBeeTemplates in useEffect when in EDITOR mode, TEMPLATE_SELECTION step, and no templates', () => {
|
|
338
|
+
// Ensure hasSupportCKEditor returns true for legacy flow
|
|
339
|
+
const { hasSupportCKEditor } = require('../../../utils/common');
|
|
340
|
+
hasSupportCKEditor.mockReturnValue(true);
|
|
341
|
+
|
|
338
342
|
renderHook(() => useEmailWrapper({
|
|
339
343
|
...mockProps,
|
|
340
344
|
step: STEPS.TEMPLATE_SELECTION,
|
|
@@ -367,6 +371,9 @@ describe('useEmailWrapper', () => {
|
|
|
367
371
|
});
|
|
368
372
|
|
|
369
373
|
it('calls setEdmTemplate/setBEETemplate in useEffect when in EDITOR mode and CREATE_TEMPLATE_CONTENT step', async () => {
|
|
374
|
+
// Ensure hasSupportCKEditor returns true for legacy flow
|
|
375
|
+
const { hasSupportCKEditor } = require('../../../utils/common');
|
|
376
|
+
hasSupportCKEditor.mockReturnValue(true);
|
|
370
377
|
// 1. Setup
|
|
371
378
|
const templateId = 'editorTemplate456';
|
|
372
379
|
const mockTemplateData = { _id: templateId, name: 'Selected Editor Template' };
|
|
@@ -397,7 +404,7 @@ describe('useEmailWrapper', () => {
|
|
|
397
404
|
// selectedCreateMode is initially '' from hook's useState
|
|
398
405
|
};
|
|
399
406
|
const { result, rerender } = renderHook((props) => useEmailWrapper(props), {
|
|
400
|
-
|
|
407
|
+
initialProps,
|
|
401
408
|
});
|
|
402
409
|
|
|
403
410
|
// 4. Simulate user selecting a template ID via the exposed callback (useEditor)
|
|
@@ -409,17 +416,21 @@ describe('useEmailWrapper', () => {
|
|
|
409
416
|
expect(result.current.modeContent).toEqual({ id: templateId }); // State updated
|
|
410
417
|
expect(mockProps.showNextStep).toHaveBeenCalledTimes(1); // User action effect
|
|
411
418
|
|
|
419
|
+
// Clear mocks after user action to isolate effect calls
|
|
420
|
+
mockProps.templatesActions.setEdmTemplate.mockClear();
|
|
421
|
+
mockProps.templatesActions.setBEETemplate.mockClear();
|
|
422
|
+
|
|
412
423
|
// 5. Rerender with step changed to CREATE_TEMPLATE_CONTENT
|
|
413
424
|
const createContentProps = {
|
|
414
425
|
...initialProps, // Base props
|
|
415
426
|
step: STEPS.CREATE_TEMPLATE_CONTENT, // *** Change step ***
|
|
416
|
-
SelectedEdmDefaultTemplate: null // *** Ensure this is null ***
|
|
427
|
+
SelectedEdmDefaultTemplate: null, // *** Ensure this is null ***
|
|
417
428
|
// The internal state `modeContent = { id: templateId }` persists
|
|
418
429
|
// The internal state `selectedCreateMode = ''` also persists (not changed yet)
|
|
419
430
|
};
|
|
420
431
|
|
|
421
432
|
// Mock isEmpty just before rerender for the specific check inside the effect
|
|
422
|
-
isEmpty.mockImplementation(val => {
|
|
433
|
+
isEmpty.mockImplementation((val) => {
|
|
423
434
|
// console.log('DEBUG: isEmpty called with', JSON.stringify(val)); // Optional debug
|
|
424
435
|
// Return true ONLY for the 'SelectedEdmDefaultTemplate' check (which is null)
|
|
425
436
|
if (val === null) return true;
|
|
@@ -434,28 +445,48 @@ describe('useEmailWrapper', () => {
|
|
|
434
445
|
|
|
435
446
|
// 6. Wait for effects triggered by the rerender
|
|
436
447
|
await reactAct(async () => {
|
|
437
|
-
//
|
|
438
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
448
|
+
// Allow React to process the rerender and run effects
|
|
449
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
439
450
|
});
|
|
440
451
|
|
|
441
|
-
|
|
442
452
|
// Assert that the template setting actions were called as a result of the effect
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
453
|
+
// Note: The effect may run multiple times in React 18+ StrictMode or due to dependency changes
|
|
454
|
+
// We verify that it was called at least once with the correct data after clearing mocks
|
|
455
|
+
const setEdmTemplateCalls = mockProps.templatesActions.setEdmTemplate.mock.calls;
|
|
456
|
+
const setBEETemplateCalls = mockProps.templatesActions.setBEETemplate.mock.calls;
|
|
457
|
+
|
|
458
|
+
// The effect should call handleEdmDefaultTemplateSelection, which calls both functions
|
|
459
|
+
// We expect at least 1 call each after clearing mocks (the effect call)
|
|
460
|
+
expect(setEdmTemplateCalls.length).toBeGreaterThanOrEqual(1);
|
|
461
|
+
expect(setBEETemplateCalls.length).toBeGreaterThanOrEqual(1);
|
|
462
|
+
|
|
463
|
+
// Verify the first call after clearing was with the correct data
|
|
464
|
+
expect(setEdmTemplateCalls[0]).toEqual([mockTemplateData]);
|
|
465
|
+
expect(setBEETemplateCalls[0]).toEqual([mockTemplateData]);
|
|
466
|
+
|
|
467
|
+
// If there are multiple calls (due to effect running twice), verify all are correct
|
|
468
|
+
if (setEdmTemplateCalls.length > 1) {
|
|
469
|
+
setEdmTemplateCalls.forEach((call) => {
|
|
470
|
+
expect(call).toEqual([mockTemplateData]);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
if (setBEETemplateCalls.length > 1) {
|
|
474
|
+
setBEETemplateCalls.forEach((call) => {
|
|
475
|
+
expect(call).toEqual([mockTemplateData]);
|
|
476
|
+
});
|
|
477
|
+
}
|
|
447
478
|
});
|
|
448
479
|
|
|
449
480
|
it('sets selectedCreateMode in useEffect when in UPLOAD mode and CREATE_TEMPLATE_CONTENT step with EmailLayout', async () => {
|
|
450
481
|
const initialRenderProps = {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
482
|
+
...mockProps,
|
|
483
|
+
step: STEPS.MODE_SELECTION,
|
|
484
|
+
emailCreateMode: EMAIL_CREATE_MODES.UPLOAD,
|
|
485
|
+
EmailLayout: null,
|
|
486
|
+
};
|
|
456
487
|
|
|
457
488
|
const { result, rerender } = renderHook((props) => useEmailWrapper(props), {
|
|
458
|
-
initialProps: initialRenderProps
|
|
489
|
+
initialProps: initialRenderProps,
|
|
459
490
|
});
|
|
460
491
|
|
|
461
492
|
const rerenderProps = {
|
|
@@ -467,11 +498,11 @@ describe('useEmailWrapper', () => {
|
|
|
467
498
|
|
|
468
499
|
// Reset isEmpty to default before setting the specific mock for the effect
|
|
469
500
|
isEmpty.mockImplementation((val) => {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
501
|
+
if (val === null || val === undefined) return true;
|
|
502
|
+
if (typeof val === 'object') return Object.keys(val).length === 0;
|
|
503
|
+
if (typeof val === 'string') return val.trim().length === 0;
|
|
504
|
+
return !val;
|
|
505
|
+
});
|
|
475
506
|
// Mock isEmpty specifically for the EmailLayout check inside the useEffect
|
|
476
507
|
isEmpty.mockImplementationOnce(() => false); // Mock !isEmpty(EmailLayout) to be true
|
|
477
508
|
|
|
@@ -479,16 +510,16 @@ describe('useEmailWrapper', () => {
|
|
|
479
510
|
|
|
480
511
|
// Wait for the effect to run, set selectedCreateMode, and isShowEmailCreate to update
|
|
481
512
|
await waitFor(() => {
|
|
482
|
-
|
|
513
|
+
expect(result.current.isShowEmailCreate).toBe(true);
|
|
483
514
|
});
|
|
484
515
|
|
|
485
516
|
// Restore default isEmpty behavior after the specific mock is used
|
|
486
517
|
isEmpty.mockImplementation((val) => {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
518
|
+
if (val === null || val === undefined) return true;
|
|
519
|
+
if (typeof val === 'object') return Object.keys(val).length === 0;
|
|
520
|
+
if (typeof val === 'string') return val.trim().length === 0;
|
|
521
|
+
return !val;
|
|
522
|
+
});
|
|
492
523
|
isEmpty.mockClear(); // Clear any remaining mock state if needed
|
|
493
524
|
|
|
494
525
|
expect(mockProps.templatesActions.setEdmTemplate).not.toHaveBeenCalled();
|
|
@@ -533,11 +564,11 @@ describe('useEmailWrapper', () => {
|
|
|
533
564
|
|
|
534
565
|
// Reset isEmpty to default before setting the specific mock for the effect
|
|
535
566
|
isEmpty.mockImplementation((val) => {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
567
|
+
if (val === null || val === undefined) return true;
|
|
568
|
+
if (typeof val === 'object') return Object.keys(val).length === 0;
|
|
569
|
+
if (typeof val === 'string') return val.trim().length === 0;
|
|
570
|
+
return !val;
|
|
571
|
+
});
|
|
541
572
|
// Mock isEmpty specifically for the EmailLayout check inside the useEffect
|
|
542
573
|
isEmpty.mockImplementationOnce(() => false); // Mock !isEmpty(EmailLayout) to be true
|
|
543
574
|
|
|
@@ -545,16 +576,16 @@ describe('useEmailWrapper', () => {
|
|
|
545
576
|
|
|
546
577
|
// Wait for the effect to run, set selectedCreateMode, and isShowEmailCreate to update
|
|
547
578
|
await waitFor(() => {
|
|
548
|
-
|
|
579
|
+
expect(result.current.isShowEmailCreate).toBe(true);
|
|
549
580
|
});
|
|
550
581
|
|
|
551
582
|
// Restore default isEmpty behavior after the specific mock is used
|
|
552
583
|
isEmpty.mockImplementation((val) => {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
584
|
+
if (val === null || val === undefined) return true;
|
|
585
|
+
if (typeof val === 'object') return Object.keys(val).length === 0;
|
|
586
|
+
if (typeof val === 'string') return val.trim().length === 0;
|
|
587
|
+
return !val;
|
|
588
|
+
});
|
|
558
589
|
isEmpty.mockClear(); // Clear any remaining mock state if needed
|
|
559
590
|
|
|
560
591
|
// --- Case 3: EDITOR mode selected, Template becomes available -> true (via effect) ---
|
|
@@ -563,11 +594,11 @@ describe('useEmailWrapper', () => {
|
|
|
563
594
|
find.mockReturnValue(mockTemplate); // Ensure find is mocked for this case
|
|
564
595
|
|
|
565
596
|
const editorPropsInitial = {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
597
|
+
...mockProps,
|
|
598
|
+
step: STEPS.TEMPLATE_SELECTION,
|
|
599
|
+
emailCreateMode: EMAIL_CREATE_MODES.EDITOR,
|
|
600
|
+
CmsTemplates: [mockTemplate],
|
|
601
|
+
SelectedEdmDefaultTemplate: null,
|
|
571
602
|
};
|
|
572
603
|
rerender(editorPropsInitial);
|
|
573
604
|
|
|
@@ -579,12 +610,12 @@ describe('useEmailWrapper', () => {
|
|
|
579
610
|
expect(result.current.modeContent).toEqual({ id: templateId });
|
|
580
611
|
|
|
581
612
|
const editorPropsFinal = {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
613
|
+
...mockProps, // Use fresh props base
|
|
614
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT, // Move to the create step
|
|
615
|
+
emailCreateMode: EMAIL_CREATE_MODES.EDITOR,
|
|
616
|
+
CmsTemplates: [mockTemplate],
|
|
617
|
+
SelectedEdmDefaultTemplate: null, // Template not yet selected in props
|
|
618
|
+
// modeContent state ({id: templateId}) should persist internally from the reactAct call
|
|
588
619
|
};
|
|
589
620
|
|
|
590
621
|
// Mock isEmpty specifically for the check within the useEffect triggered by rerender
|
|
@@ -598,4 +629,487 @@ describe('useEmailWrapper', () => {
|
|
|
598
629
|
find.mockClear();
|
|
599
630
|
isEmpty.mockClear();
|
|
600
631
|
});
|
|
601
|
-
|
|
632
|
+
|
|
633
|
+
describe('New Flow (hasSupportCKEditor = false) - Editor Type Determination', () => {
|
|
634
|
+
let newFlowMockProps;
|
|
635
|
+
let mockEmailActions;
|
|
636
|
+
|
|
637
|
+
beforeEach(() => {
|
|
638
|
+
const { hasSupportCKEditor } = require('../../../utils/common');
|
|
639
|
+
hasSupportCKEditor.mockReturnValue(false); // New flow
|
|
640
|
+
|
|
641
|
+
mockEmailActions = {
|
|
642
|
+
getTemplateDetails: jest.fn(),
|
|
643
|
+
getCmsAccounts: jest.fn(),
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
newFlowMockProps = {
|
|
647
|
+
...mockProps,
|
|
648
|
+
emailActions: mockEmailActions,
|
|
649
|
+
Email: {
|
|
650
|
+
templateDetails: null,
|
|
651
|
+
BEETemplate: null,
|
|
652
|
+
getTemplateDetailsInProgress: false,
|
|
653
|
+
isBeeEnabled: true,
|
|
654
|
+
},
|
|
655
|
+
location: {
|
|
656
|
+
pathname: '/email/create',
|
|
657
|
+
query: {},
|
|
658
|
+
},
|
|
659
|
+
params: {},
|
|
660
|
+
templateData: null,
|
|
661
|
+
};
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
describe('Create Flow', () => {
|
|
665
|
+
it('should set HTML editor when HTML_EDITOR mode is selected', async () => {
|
|
666
|
+
const { result } = renderHook((props) => useEmailWrapper(props), {
|
|
667
|
+
initialProps: newFlowMockProps,
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
// Select HTML Editor mode
|
|
671
|
+
reactAct(() => {
|
|
672
|
+
result.current.onChange({ target: { value: EMAIL_CREATE_MODES.HTML_EDITOR } });
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
await waitFor(() => {
|
|
676
|
+
const emailProps = result.current.emailProps;
|
|
677
|
+
expect(emailProps.editor).toBe('HTML');
|
|
678
|
+
expect(emailProps.selectedEditorMode).toBe(EMAIL_CREATE_MODES.HTML_EDITOR);
|
|
679
|
+
});
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
describe('Edit Flow - HTML Editor Template', () => {
|
|
684
|
+
it('should call getTemplateDetails and set HTML editor for HTML template', async () => {
|
|
685
|
+
const templateId = 'html-template-123';
|
|
686
|
+
const htmlTemplateData = {
|
|
687
|
+
_id: templateId,
|
|
688
|
+
name: 'HTML Template',
|
|
689
|
+
versions: {
|
|
690
|
+
base: {
|
|
691
|
+
activeTab: 'en',
|
|
692
|
+
en: {
|
|
693
|
+
is_drag_drop: false,
|
|
694
|
+
html_content: '<html><body>Test</body></html>',
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
const editProps = {
|
|
701
|
+
...newFlowMockProps,
|
|
702
|
+
params: { id: templateId },
|
|
703
|
+
location: {
|
|
704
|
+
pathname: `/email/edit/${templateId}`,
|
|
705
|
+
query: { id: templateId },
|
|
706
|
+
},
|
|
707
|
+
Email: {
|
|
708
|
+
...newFlowMockProps.Email,
|
|
709
|
+
templateDetails: null,
|
|
710
|
+
getTemplateDetailsInProgress: false,
|
|
711
|
+
},
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
const { result, rerender } = renderHook((props) => useEmailWrapper(props), {
|
|
715
|
+
initialProps: editProps,
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// Verify getTemplateDetails is called
|
|
719
|
+
await waitFor(() => {
|
|
720
|
+
expect(mockEmailActions.getTemplateDetails).toHaveBeenCalledWith(templateId, 'email');
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
// Simulate template data loaded
|
|
724
|
+
rerender({
|
|
725
|
+
...editProps,
|
|
726
|
+
Email: {
|
|
727
|
+
...editProps.Email,
|
|
728
|
+
templateDetails: htmlTemplateData,
|
|
729
|
+
getTemplateDetailsInProgress: false,
|
|
730
|
+
},
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
await waitFor(() => {
|
|
734
|
+
const emailProps = result.current.emailProps;
|
|
735
|
+
expect(emailProps.editor).toBe('HTML');
|
|
736
|
+
expect(emailProps.selectedEditorMode).toBe(EMAIL_CREATE_MODES.HTML_EDITOR);
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
it('should detect HTML template from templateData prop (library mode)', async () => {
|
|
741
|
+
const htmlTemplateData = {
|
|
742
|
+
_id: 'html-template-456',
|
|
743
|
+
name: 'HTML Template',
|
|
744
|
+
base: {
|
|
745
|
+
is_drag_drop: false,
|
|
746
|
+
html_content: '<html><body>Test</body></html>',
|
|
747
|
+
},
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
const editProps = {
|
|
751
|
+
...newFlowMockProps,
|
|
752
|
+
templateData: htmlTemplateData,
|
|
753
|
+
location: {
|
|
754
|
+
pathname: '/email/edit',
|
|
755
|
+
query: { type: 'embedded', module: 'library' },
|
|
756
|
+
},
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
const { result } = renderHook((props) => useEmailWrapper(props), {
|
|
760
|
+
initialProps: editProps,
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
await waitFor(() => {
|
|
764
|
+
const emailProps = result.current.emailProps;
|
|
765
|
+
expect(emailProps.editor).toBe('HTML');
|
|
766
|
+
expect(emailProps.selectedEditorMode).toBe(EMAIL_CREATE_MODES.HTML_EDITOR);
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
describe('Edit Flow - BEE Editor Template', () => {
|
|
772
|
+
it('should call getTemplateDetails and set BEE editor for BEE template', async () => {
|
|
773
|
+
const templateId = 'bee-template-123';
|
|
774
|
+
const beeTemplateData = {
|
|
775
|
+
_id: templateId,
|
|
776
|
+
name: 'BEE Template',
|
|
777
|
+
versions: {
|
|
778
|
+
base: {
|
|
779
|
+
activeTab: 'en',
|
|
780
|
+
en: {
|
|
781
|
+
is_drag_drop: true,
|
|
782
|
+
drag_drop_id: 'drag-drop-123',
|
|
783
|
+
},
|
|
784
|
+
},
|
|
785
|
+
},
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
const editProps = {
|
|
789
|
+
...newFlowMockProps,
|
|
790
|
+
params: { id: templateId },
|
|
791
|
+
location: {
|
|
792
|
+
pathname: `/email/edit/${templateId}`,
|
|
793
|
+
query: { id: templateId },
|
|
794
|
+
},
|
|
795
|
+
Email: {
|
|
796
|
+
...newFlowMockProps.Email,
|
|
797
|
+
templateDetails: null,
|
|
798
|
+
getTemplateDetailsInProgress: false,
|
|
799
|
+
isBeeEnabled: true,
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
const { result, rerender } = renderHook((props) => useEmailWrapper(props), {
|
|
804
|
+
initialProps: editProps,
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// Verify getTemplateDetails is called
|
|
808
|
+
await waitFor(() => {
|
|
809
|
+
expect(mockEmailActions.getTemplateDetails).toHaveBeenCalledWith(templateId, 'email');
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// Simulate template data loaded
|
|
813
|
+
rerender({
|
|
814
|
+
...editProps,
|
|
815
|
+
Email: {
|
|
816
|
+
...editProps.Email,
|
|
817
|
+
templateDetails: beeTemplateData,
|
|
818
|
+
getTemplateDetailsInProgress: false,
|
|
819
|
+
isBeeEnabled: true,
|
|
820
|
+
},
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
await waitFor(() => {
|
|
824
|
+
const emailProps = result.current.emailProps;
|
|
825
|
+
expect(emailProps.editor).toBe('BEE');
|
|
826
|
+
expect(emailProps.selectedEditorMode).toBe(null);
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
it('should detect BEE template from templateData prop with base.is_drag_drop (library mode)', async () => {
|
|
831
|
+
const beeTemplateData = {
|
|
832
|
+
_id: 'bee-template-456',
|
|
833
|
+
name: 'BEE Template',
|
|
834
|
+
base: {
|
|
835
|
+
is_drag_drop: true,
|
|
836
|
+
drag_drop_id: 'drag-drop-456',
|
|
837
|
+
},
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
const editProps = {
|
|
841
|
+
...newFlowMockProps,
|
|
842
|
+
templateData: beeTemplateData,
|
|
843
|
+
location: {
|
|
844
|
+
pathname: '/email/edit',
|
|
845
|
+
query: { type: 'embedded', module: 'library' },
|
|
846
|
+
},
|
|
847
|
+
Email: {
|
|
848
|
+
...newFlowMockProps.Email,
|
|
849
|
+
isBeeEnabled: true,
|
|
850
|
+
},
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
const { result } = renderHook((props) => useEmailWrapper(props), {
|
|
854
|
+
initialProps: editProps,
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
await waitFor(() => {
|
|
858
|
+
const emailProps = result.current.emailProps;
|
|
859
|
+
expect(emailProps.editor).toBe('BEE');
|
|
860
|
+
expect(emailProps.selectedEditorMode).toBe(null);
|
|
861
|
+
});
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
it('should detect BEE template with language-specific is_drag_drop (actual API format)', async () => {
|
|
865
|
+
// This matches the actual API response format shown by the user
|
|
866
|
+
const beeTemplateData = {
|
|
867
|
+
_id: 'bee-template-lang',
|
|
868
|
+
name: 'BEE Template',
|
|
869
|
+
versions: {
|
|
870
|
+
base: {
|
|
871
|
+
activeTab: 'en',
|
|
872
|
+
en: {
|
|
873
|
+
is_drag_drop: true,
|
|
874
|
+
drag_drop_id: '',
|
|
875
|
+
lang_id: 69,
|
|
876
|
+
iso_code: 'en',
|
|
877
|
+
language: 'English',
|
|
878
|
+
},
|
|
879
|
+
},
|
|
880
|
+
},
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
const editProps = {
|
|
884
|
+
...newFlowMockProps,
|
|
885
|
+
templateData: beeTemplateData,
|
|
886
|
+
Email: {
|
|
887
|
+
...newFlowMockProps.Email,
|
|
888
|
+
isBeeEnabled: true,
|
|
889
|
+
},
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
const { result } = renderHook((props) => useEmailWrapper(props), {
|
|
893
|
+
initialProps: editProps,
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
await waitFor(() => {
|
|
897
|
+
const emailProps = result.current.emailProps;
|
|
898
|
+
expect(emailProps.editor).toBe('BEE');
|
|
899
|
+
expect(emailProps.selectedEditorMode).toBe(null);
|
|
900
|
+
});
|
|
901
|
+
});
|
|
902
|
+
|
|
903
|
+
it('should fallback to HTML editor if BEE template but BEE is disabled', async () => {
|
|
904
|
+
const beeTemplateData = {
|
|
905
|
+
_id: 'bee-template-disabled',
|
|
906
|
+
name: 'BEE Template',
|
|
907
|
+
versions: {
|
|
908
|
+
base: {
|
|
909
|
+
activeTab: 'en',
|
|
910
|
+
en: {
|
|
911
|
+
is_drag_drop: true,
|
|
912
|
+
},
|
|
913
|
+
},
|
|
914
|
+
},
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
const editProps = {
|
|
918
|
+
...newFlowMockProps,
|
|
919
|
+
templateData: beeTemplateData,
|
|
920
|
+
Email: {
|
|
921
|
+
...newFlowMockProps.Email,
|
|
922
|
+
isBeeEnabled: false, // BEE disabled
|
|
923
|
+
},
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
const { result } = renderHook((props) => useEmailWrapper(props), {
|
|
927
|
+
initialProps: editProps,
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
await waitFor(() => {
|
|
931
|
+
const emailProps = result.current.emailProps;
|
|
932
|
+
// Should fallback to HTML editor when BEE is disabled
|
|
933
|
+
expect(emailProps.editor).toBe('HTML');
|
|
934
|
+
expect(emailProps.selectedEditorMode).toBe(EMAIL_CREATE_MODES.HTML_EDITOR);
|
|
935
|
+
});
|
|
936
|
+
});
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
describe('Edit Flow - API Call Verification', () => {
|
|
940
|
+
it('should NOT call getTemplateDetails if template data already exists', async () => {
|
|
941
|
+
const templateId = 'existing-template';
|
|
942
|
+
const existingTemplateData = {
|
|
943
|
+
_id: templateId,
|
|
944
|
+
name: 'Existing Template',
|
|
945
|
+
versions: {
|
|
946
|
+
base: {
|
|
947
|
+
activeTab: 'en',
|
|
948
|
+
en: {
|
|
949
|
+
is_drag_drop: false,
|
|
950
|
+
},
|
|
951
|
+
},
|
|
952
|
+
},
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
const editProps = {
|
|
956
|
+
...newFlowMockProps,
|
|
957
|
+
params: { id: templateId },
|
|
958
|
+
Email: {
|
|
959
|
+
...newFlowMockProps.Email,
|
|
960
|
+
templateDetails: existingTemplateData, // Already loaded
|
|
961
|
+
getTemplateDetailsInProgress: false,
|
|
962
|
+
},
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
renderHook((props) => useEmailWrapper(props), {
|
|
966
|
+
initialProps: editProps,
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
// Wait a bit to ensure effect runs
|
|
970
|
+
await waitFor(() => {
|
|
971
|
+
// Should NOT call getTemplateDetails since data already exists
|
|
972
|
+
expect(mockEmailActions.getTemplateDetails).not.toHaveBeenCalled();
|
|
973
|
+
}, { timeout: 1000 });
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
it('should NOT call getTemplateDetails if templateData prop is provided', async () => {
|
|
977
|
+
const templateData = {
|
|
978
|
+
_id: 'prop-template',
|
|
979
|
+
base: {
|
|
980
|
+
is_drag_drop: false,
|
|
981
|
+
},
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
const editProps = {
|
|
985
|
+
...newFlowMockProps,
|
|
986
|
+
params: { id: 'prop-template' },
|
|
987
|
+
templateData, // Provided via prop
|
|
988
|
+
Email: {
|
|
989
|
+
...newFlowMockProps.Email,
|
|
990
|
+
templateDetails: null,
|
|
991
|
+
},
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
renderHook((props) => useEmailWrapper(props), {
|
|
995
|
+
initialProps: editProps,
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
// Wait a bit to ensure effect runs
|
|
999
|
+
await waitFor(() => {
|
|
1000
|
+
// Should NOT call getTemplateDetails since templateData prop is provided
|
|
1001
|
+
expect(mockEmailActions.getTemplateDetails).not.toHaveBeenCalled();
|
|
1002
|
+
}, { timeout: 1000 });
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
it('should NOT call getTemplateDetails if already loading', async () => {
|
|
1006
|
+
const templateId = 'loading-template';
|
|
1007
|
+
|
|
1008
|
+
const editProps = {
|
|
1009
|
+
...newFlowMockProps,
|
|
1010
|
+
params: { id: templateId },
|
|
1011
|
+
Email: {
|
|
1012
|
+
...newFlowMockProps.Email,
|
|
1013
|
+
templateDetails: null,
|
|
1014
|
+
getTemplateDetailsInProgress: true, // Already loading
|
|
1015
|
+
},
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
renderHook((props) => useEmailWrapper(props), {
|
|
1019
|
+
initialProps: editProps,
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
// Wait a bit to ensure effect runs
|
|
1023
|
+
await waitFor(() => {
|
|
1024
|
+
// Should NOT call getTemplateDetails since already loading
|
|
1025
|
+
expect(mockEmailActions.getTemplateDetails).not.toHaveBeenCalled();
|
|
1026
|
+
}, { timeout: 1000 });
|
|
1027
|
+
});
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
describe('getStepFromTemplateStep (tested indirectly through behavior)', () => {
|
|
1032
|
+
it('should handle numeric step 1 (MODE_SELECTION)', () => {
|
|
1033
|
+
const { result } = renderHook(() => useEmailWrapper({
|
|
1034
|
+
...mockProps,
|
|
1035
|
+
step: 1,
|
|
1036
|
+
}));
|
|
1037
|
+
|
|
1038
|
+
// When step is 1 (MODE_SELECTION), isShowEmailCreate should be false
|
|
1039
|
+
// This tests that getStepFromTemplateStep converts 1 to MODE_SELECTION
|
|
1040
|
+
expect(result.current.isShowEmailCreate).toBe(false);
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
it('should handle numeric step 2 (TEMPLATE_SELECTION)', () => {
|
|
1044
|
+
const { result } = renderHook(() => useEmailWrapper({
|
|
1045
|
+
...mockProps,
|
|
1046
|
+
step: 2,
|
|
1047
|
+
emailCreateMode: EMAIL_CREATE_MODES.EDITOR,
|
|
1048
|
+
}));
|
|
1049
|
+
|
|
1050
|
+
// When step is 2 (TEMPLATE_SELECTION), isShowEmailCreate should be false
|
|
1051
|
+
expect(result.current.isShowEmailCreate).toBe(false);
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
it('should handle numeric step 3 (CREATE_TEMPLATE_CONTENT)', () => {
|
|
1055
|
+
const { result } = renderHook(() => useEmailWrapper({
|
|
1056
|
+
...mockProps,
|
|
1057
|
+
step: 3,
|
|
1058
|
+
emailCreateMode: EMAIL_CREATE_MODES.EDITOR,
|
|
1059
|
+
SelectedEdmDefaultTemplate: { id: 'template1' },
|
|
1060
|
+
}));
|
|
1061
|
+
|
|
1062
|
+
// When step is 3 (CREATE_TEMPLATE_CONTENT) and template is selected, isShowEmailCreate should be true
|
|
1063
|
+
expect(result.current.isShowEmailCreate).toBe(true);
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
it('should handle string step value', () => {
|
|
1067
|
+
const { result } = renderHook(() => useEmailWrapper({
|
|
1068
|
+
...mockProps,
|
|
1069
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
1070
|
+
emailCreateMode: EMAIL_CREATE_MODES.EDITOR,
|
|
1071
|
+
SelectedEdmDefaultTemplate: { id: 'template1' },
|
|
1072
|
+
}));
|
|
1073
|
+
|
|
1074
|
+
// String step should work the same way
|
|
1075
|
+
expect(result.current.isShowEmailCreate).toBe(true);
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
it('should default to MODE_SELECTION when step is null or undefined', () => {
|
|
1079
|
+
const { result: result1 } = renderHook(() => useEmailWrapper({
|
|
1080
|
+
...mockProps,
|
|
1081
|
+
step: null,
|
|
1082
|
+
}));
|
|
1083
|
+
|
|
1084
|
+
// Should default to MODE_SELECTION behavior
|
|
1085
|
+
expect(result1.current.isShowEmailCreate).toBe(false);
|
|
1086
|
+
|
|
1087
|
+
const { result: result2 } = renderHook(() => useEmailWrapper({
|
|
1088
|
+
...mockProps,
|
|
1089
|
+
step: undefined,
|
|
1090
|
+
}));
|
|
1091
|
+
|
|
1092
|
+
expect(result2.current.isShowEmailCreate).toBe(false);
|
|
1093
|
+
});
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
describe('Template mode selection logic', () => {
|
|
1097
|
+
it('should set HTML_EDITOR mode when HTML_EDITOR is selected and supportCKEditor is false', () => {
|
|
1098
|
+
const { hasSupportCKEditor } = require('../../../utils/common');
|
|
1099
|
+
hasSupportCKEditor.mockReturnValueOnce(false);
|
|
1100
|
+
|
|
1101
|
+
const { result } = renderHook(() => useEmailWrapper({
|
|
1102
|
+
...mockProps,
|
|
1103
|
+
emailCreateMode: EMAIL_CREATE_MODES.HTML_EDITOR,
|
|
1104
|
+
modeContent: { id: 'mode1' },
|
|
1105
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
1106
|
+
}));
|
|
1107
|
+
|
|
1108
|
+
expect(result.current.emailProps.selectedEditorMode).toBe(EMAIL_CREATE_MODES.HTML_EDITOR);
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
// Note: DRAG_DROP and EDITOR mode selection logic is complex and depends on multiple conditions
|
|
1112
|
+
// These are tested through integration tests and actual component usage
|
|
1113
|
+
// The logic is covered in existing tests that test the full flow
|
|
1114
|
+
});
|
|
1115
|
+
});
|