@capillarytech/creatives-library 8.0.242-alpha.0 → 8.0.242-alpha.10
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/sagas/__tests__/assetPolling.test.js +74 -3
- package/sagas/assetPolling.js +8 -1
- package/services/api.js +10 -5
- package/services/tests/api.test.js +18 -0
- package/translations/en.json +0 -1
- package/utils/common.js +5 -0
- package/utils/commonUtils.js +14 -1
- package/utils/tests/commonUtil.test.js +224 -0
- package/utils/transformTemplateConfig.js +0 -10
- package/utils/transformerUtils.js +0 -42
- package/v2Components/CapDeviceContent/index.js +61 -56
- package/v2Components/CapImageUpload/constants.js +0 -2
- package/v2Components/CapImageUpload/index.js +14 -54
- package/v2Components/CapImageUpload/index.scss +1 -4
- package/v2Components/CapImageUpload/messages.js +0 -4
- 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/index.js +412 -72
- package/v2Components/ErrorInfoNote/messages.js +22 -0
- package/v2Components/ErrorInfoNote/style.scss +279 -2
- package/v2Components/HtmlEditor/HTMLEditor.js +220 -91
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1132 -133
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +17 -12
- package/v2Components/HtmlEditor/_htmlEditor.scss +107 -45
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +13 -101
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +148 -139
- 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 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- 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 +3 -6
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +10 -11
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +70 -72
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +49 -31
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +254 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +362 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
- package/v2Components/HtmlEditor/constants.js +29 -20
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +95 -85
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +99 -101
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
- package/v2Components/HtmlEditor/utils/validationAdapter.js +34 -41
- package/v2Components/MobilePushPreviewV2/index.js +32 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +44 -24
- package/v2Components/TemplatePreview/index.js +47 -32
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +31 -25
- package/v2Containers/App/constants.js +0 -5
- package/v2Containers/BeeEditor/index.js +82 -80
- package/v2Containers/BeePopupEditor/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +193 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +0 -1
- package/v2Containers/CreativesContainer/SlideBoxContent.js +148 -120
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +9 -3
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
- package/v2Containers/CreativesContainer/constants.js +1 -2
- package/v2Containers/CreativesContainer/index.js +173 -193
- package/v2Containers/CreativesContainer/messages.js +4 -4
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +36 -0
- package/v2Containers/Email/actions.js +7 -0
- package/v2Containers/Email/constants.js +5 -1
- package/v2Containers/Email/index.js +13 -0
- package/v2Containers/Email/messages.js +32 -0
- package/v2Containers/Email/reducer.js +12 -1
- package/v2Containers/Email/sagas.js +41 -6
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1046 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +193 -7
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +436 -67
- package/v2Containers/EmailWrapper/index.js +99 -23
- package/v2Containers/EmailWrapper/messages.js +61 -1
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +111 -77
- 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 +801 -357
- 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 +162 -0
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +9 -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 -3
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -2
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -25
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -18
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -46
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +0 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -8
- package/v2Containers/TagList/index.js +67 -1
- package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
- package/v2Containers/Templates/_templates.scss +56 -200
- package/v2Containers/Templates/actions.js +1 -2
- package/v2Containers/Templates/constants.js +0 -1
- package/v2Containers/Templates/index.js +124 -277
- package/v2Containers/Templates/messages.js +4 -24
- package/v2Containers/Templates/reducer.js +0 -2
- package/v2Containers/Templates/tests/index.test.js +0 -10
- package/v2Containers/TemplatesV2/index.js +2 -3
- package/v2Containers/TemplatesV2/messages.js +0 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +35 -132
- package/v2Components/CapImageUrlUpload/constants.js +0 -19
- package/v2Components/CapImageUrlUpload/index.js +0 -455
- package/v2Components/CapImageUrlUpload/index.scss +0 -35
- package/v2Components/CapImageUrlUpload/messages.js +0 -47
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
- package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -175
- package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
- package/v2Containers/WebPush/Create/components/ButtonList.js +0 -144
- package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -633
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -80
- package/v2Containers/WebPush/Create/index.js +0 -1755
- package/v2Containers/WebPush/Create/index.scss +0 -123
- package/v2Containers/WebPush/Create/messages.js +0 -199
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -241
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -290
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -81
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -240
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -23
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -144
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
- 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 +0 -106
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -44
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -110
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -72
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -55
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -70
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -512
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -77
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -527
- package/v2Containers/WebPush/Create/preview/constants.js +0 -162
- package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -104
- package/v2Containers/WebPush/Create/preview/preview.scss +0 -409
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -300
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -303
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -188
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -106
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -75
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -174
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1077
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -943
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -128
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -121
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -127
- package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -116
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
- package/v2Containers/WebPush/actions.js +0 -60
- package/v2Containers/WebPush/constants.js +0 -108
- package/v2Containers/WebPush/index.js +0 -2
- package/v2Containers/WebPush/reducer.js +0 -104
- package/v2Containers/WebPush/sagas.js +0 -119
- package/v2Containers/WebPush/selectors.js +0 -65
- package/v2Containers/WebPush/tests/reducer.test.js +0 -863
- package/v2Containers/WebPush/tests/sagas.test.js +0 -566
- package/v2Containers/WebPush/tests/selectors.test.js +0 -960
|
@@ -76,7 +76,7 @@ describe('useInAppContent', () => {
|
|
|
76
76
|
|
|
77
77
|
it('initializes with custom content for Android', () => {
|
|
78
78
|
const customContent = {
|
|
79
|
-
[DEVICE_TYPES.ANDROID]: '<p>Custom Android</p>'
|
|
79
|
+
[DEVICE_TYPES.ANDROID]: '<p>Custom Android</p>',
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
render(<TestComponent initialContent={customContent} />);
|
|
@@ -86,7 +86,7 @@ describe('useInAppContent', () => {
|
|
|
86
86
|
|
|
87
87
|
it('initializes with custom content for iOS', () => {
|
|
88
88
|
const customContent = {
|
|
89
|
-
[DEVICE_TYPES.IOS]: '<p>Custom iOS</p>'
|
|
89
|
+
[DEVICE_TYPES.IOS]: '<p>Custom iOS</p>',
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
render(<TestComponent initialContent={customContent} />);
|
|
@@ -97,7 +97,7 @@ describe('useInAppContent', () => {
|
|
|
97
97
|
it('initializes with custom content for both devices', () => {
|
|
98
98
|
const customContent = {
|
|
99
99
|
[DEVICE_TYPES.ANDROID]: '<p>Android</p>',
|
|
100
|
-
[DEVICE_TYPES.IOS]: '<p>iOS</p>'
|
|
100
|
+
[DEVICE_TYPES.IOS]: '<p>iOS</p>',
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
render(<TestComponent initialContent={customContent} />);
|
|
@@ -112,10 +112,10 @@ describe('useInAppContent', () => {
|
|
|
112
112
|
expect(screen.getByTestId('active-device')).toHaveTextContent(DEVICE_TYPES.ANDROID);
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it('has content by default', () => {
|
|
115
|
+
it('has no content by default (empty strings)', () => {
|
|
116
116
|
render(<TestComponent />);
|
|
117
117
|
|
|
118
|
-
expect(screen.getByTestId('has-content')).toHaveTextContent('
|
|
118
|
+
expect(screen.getByTestId('has-content')).toHaveTextContent('false');
|
|
119
119
|
});
|
|
120
120
|
});
|
|
121
121
|
|
|
@@ -152,7 +152,7 @@ describe('useInAppContent', () => {
|
|
|
152
152
|
it('updates current content when switching devices', () => {
|
|
153
153
|
const customContent = {
|
|
154
154
|
[DEVICE_TYPES.ANDROID]: '<p>Android Content</p>',
|
|
155
|
-
[DEVICE_TYPES.IOS]: '<p>iOS Content</p>'
|
|
155
|
+
[DEVICE_TYPES.IOS]: '<p>iOS Content</p>',
|
|
156
156
|
};
|
|
157
157
|
|
|
158
158
|
render(<TestComponent initialContent={customContent} />);
|
|
@@ -220,7 +220,7 @@ describe('useInAppContent', () => {
|
|
|
220
220
|
it('updates only current device when sync is disabled', () => {
|
|
221
221
|
const customContent = {
|
|
222
222
|
[DEVICE_TYPES.ANDROID]: '<p>Android</p>',
|
|
223
|
-
[DEVICE_TYPES.IOS]: '<p>iOS</p>'
|
|
223
|
+
[DEVICE_TYPES.IOS]: '<p>iOS</p>',
|
|
224
224
|
};
|
|
225
225
|
|
|
226
226
|
let inAppState;
|
|
@@ -254,7 +254,7 @@ describe('useInAppContent', () => {
|
|
|
254
254
|
expect(mockOnChange).toHaveBeenCalled();
|
|
255
255
|
expect(mockOnChange).toHaveBeenCalledWith(
|
|
256
256
|
expect.objectContaining({
|
|
257
|
-
[DEVICE_TYPES.ANDROID]: '<p>New</p>'
|
|
257
|
+
[DEVICE_TYPES.ANDROID]: '<p>New</p>',
|
|
258
258
|
}),
|
|
259
259
|
DEVICE_TYPES.ANDROID
|
|
260
260
|
);
|
|
@@ -294,7 +294,7 @@ describe('useInAppContent', () => {
|
|
|
294
294
|
it('syncs content to both devices when sync is enabled', () => {
|
|
295
295
|
const customContent = {
|
|
296
296
|
[DEVICE_TYPES.ANDROID]: '<p>Android</p>',
|
|
297
|
-
[DEVICE_TYPES.IOS]: '<p>iOS</p>'
|
|
297
|
+
[DEVICE_TYPES.IOS]: '<p>iOS</p>',
|
|
298
298
|
};
|
|
299
299
|
|
|
300
300
|
render(<TestComponent initialContent={customContent} />);
|
|
@@ -457,7 +457,7 @@ describe('useInAppContent', () => {
|
|
|
457
457
|
describe('Content Queries', () => {
|
|
458
458
|
it('reports hasContent as true for non-empty content', () => {
|
|
459
459
|
const customContent = {
|
|
460
|
-
[DEVICE_TYPES.ANDROID]: '<p>Content</p>'
|
|
460
|
+
[DEVICE_TYPES.ANDROID]: '<p>Content</p>',
|
|
461
461
|
};
|
|
462
462
|
|
|
463
463
|
render(<TestComponent initialContent={customContent} />);
|
|
@@ -468,7 +468,7 @@ describe('useInAppContent', () => {
|
|
|
468
468
|
it('reports hasContent as false for empty content', () => {
|
|
469
469
|
const customContent = {
|
|
470
470
|
[DEVICE_TYPES.ANDROID]: '',
|
|
471
|
-
[DEVICE_TYPES.IOS]: ''
|
|
471
|
+
[DEVICE_TYPES.IOS]: '',
|
|
472
472
|
};
|
|
473
473
|
|
|
474
474
|
let inAppState;
|
|
@@ -487,7 +487,7 @@ describe('useInAppContent', () => {
|
|
|
487
487
|
|
|
488
488
|
it('calculates content size correctly', () => {
|
|
489
489
|
const customContent = {
|
|
490
|
-
[DEVICE_TYPES.ANDROID]: '12345'
|
|
490
|
+
[DEVICE_TYPES.ANDROID]: '12345',
|
|
491
491
|
};
|
|
492
492
|
|
|
493
493
|
render(<TestComponent initialContent={customContent} />);
|
|
@@ -498,7 +498,7 @@ describe('useInAppContent', () => {
|
|
|
498
498
|
it('returns 0 size for empty content', () => {
|
|
499
499
|
const customContent = {
|
|
500
500
|
[DEVICE_TYPES.ANDROID]: '',
|
|
501
|
-
[DEVICE_TYPES.IOS]: ''
|
|
501
|
+
[DEVICE_TYPES.IOS]: '',
|
|
502
502
|
};
|
|
503
503
|
|
|
504
504
|
let inAppState;
|
|
@@ -518,7 +518,7 @@ describe('useInAppContent', () => {
|
|
|
518
518
|
it('getDeviceContent returns content for specific device', () => {
|
|
519
519
|
const customContent = {
|
|
520
520
|
[DEVICE_TYPES.ANDROID]: '<p>Android</p>',
|
|
521
|
-
[DEVICE_TYPES.IOS]: '<p>iOS</p>'
|
|
521
|
+
[DEVICE_TYPES.IOS]: '<p>iOS</p>',
|
|
522
522
|
};
|
|
523
523
|
|
|
524
524
|
let inAppState;
|
|
@@ -655,7 +655,7 @@ describe('useInAppContent', () => {
|
|
|
655
655
|
it('handles very large content', () => {
|
|
656
656
|
const largeContent = 'a'.repeat(100000);
|
|
657
657
|
const customContent = {
|
|
658
|
-
[DEVICE_TYPES.ANDROID]: largeContent
|
|
658
|
+
[DEVICE_TYPES.ANDROID]: largeContent,
|
|
659
659
|
};
|
|
660
660
|
|
|
661
661
|
let inAppState;
|
|
@@ -698,7 +698,7 @@ describe('useInAppContent', () => {
|
|
|
698
698
|
it('switches device and updates content', () => {
|
|
699
699
|
const customContent = {
|
|
700
700
|
[DEVICE_TYPES.ANDROID]: '<p>Android</p>',
|
|
701
|
-
[DEVICE_TYPES.IOS]: '<p>iOS</p>'
|
|
701
|
+
[DEVICE_TYPES.IOS]: '<p>iOS</p>',
|
|
702
702
|
};
|
|
703
703
|
|
|
704
704
|
let inAppState;
|
|
@@ -781,5 +781,362 @@ describe('useInAppContent', () => {
|
|
|
781
781
|
expect(mockOnSave).toHaveBeenCalledTimes(1);
|
|
782
782
|
});
|
|
783
783
|
});
|
|
784
|
+
|
|
785
|
+
describe('setDeviceContent Coverage', () => {
|
|
786
|
+
it('sets content for specific device when sync is disabled', () => {
|
|
787
|
+
let inAppState;
|
|
788
|
+
render(<TestComponent onStateChange={(state) => { inAppState = state; }} />);
|
|
789
|
+
|
|
790
|
+
act(() => {
|
|
791
|
+
inAppState.setDeviceContent(DEVICE_TYPES.ANDROID, '<p>Android Only</p>');
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('<p>Android Only</p>');
|
|
795
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('');
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
it('sets content for both devices when sync is enabled', () => {
|
|
799
|
+
let inAppState;
|
|
800
|
+
render(<TestComponent onStateChange={(state) => { inAppState = state; }} />);
|
|
801
|
+
|
|
802
|
+
// Enable sync first
|
|
803
|
+
act(() => {
|
|
804
|
+
inAppState.toggleContentSync(true);
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// Then set content
|
|
808
|
+
act(() => {
|
|
809
|
+
inAppState.setDeviceContent(DEVICE_TYPES.ANDROID, '<p>Synced Content</p>');
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('<p>Synced Content</p>');
|
|
813
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('<p>Synced Content</p>');
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
it('warns when setting content for invalid device', () => {
|
|
817
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
818
|
+
let inAppState;
|
|
819
|
+
render(<TestComponent onStateChange={(state) => { inAppState = state; }} />);
|
|
820
|
+
|
|
821
|
+
act(() => {
|
|
822
|
+
inAppState.setDeviceContent('InvalidDevice', '<p>Content</p>');
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
826
|
+
expect.stringContaining('Invalid device type')
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
consoleSpy.mockRestore();
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
it('warns when setting non-string content', () => {
|
|
833
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
834
|
+
let inAppState;
|
|
835
|
+
render(<TestComponent onStateChange={(state) => { inAppState = state; }} />);
|
|
836
|
+
|
|
837
|
+
act(() => {
|
|
838
|
+
inAppState.setDeviceContent(DEVICE_TYPES.ANDROID, 123);
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
842
|
+
expect.stringContaining('content must be a string')
|
|
843
|
+
);
|
|
844
|
+
|
|
845
|
+
consoleSpy.mockRestore();
|
|
846
|
+
});
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
describe('Edge Cases Coverage', () => {
|
|
850
|
+
it('handles updateContent with non-string input', () => {
|
|
851
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
852
|
+
let inAppState;
|
|
853
|
+
render(<TestComponent onStateChange={(state) => { inAppState = state; }} />);
|
|
854
|
+
|
|
855
|
+
act(() => {
|
|
856
|
+
inAppState.updateContent(123);
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
860
|
+
expect.stringContaining('newContent must be a string')
|
|
861
|
+
);
|
|
862
|
+
|
|
863
|
+
consoleSpy.mockRestore();
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
it('handles switchDevice with invalid device type', () => {
|
|
867
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
868
|
+
let inAppState;
|
|
869
|
+
render(<TestComponent onStateChange={(state) => { inAppState = state; }} />);
|
|
870
|
+
|
|
871
|
+
act(() => {
|
|
872
|
+
inAppState.switchDevice('InvalidDevice');
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
876
|
+
expect.stringContaining('Invalid device type')
|
|
877
|
+
);
|
|
878
|
+
|
|
879
|
+
consoleSpy.mockRestore();
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
it('handles auto-save with content length below minimum', () => {
|
|
883
|
+
const onSave = jest.fn();
|
|
884
|
+
let inAppState;
|
|
885
|
+
render(
|
|
886
|
+
<TestComponent
|
|
887
|
+
options={{ autoSave: true, autoSaveInterval: 100, onSave }}
|
|
888
|
+
onStateChange={(state) => { inAppState = state; }}
|
|
889
|
+
/>
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
act(() => {
|
|
893
|
+
inAppState.updateContent(''); // Empty content
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
act(() => {
|
|
897
|
+
jest.advanceTimersByTime(200);
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// onSave should not be called for empty content
|
|
901
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
it('handles auto-save interval below minimum', () => {
|
|
905
|
+
const onSave = jest.fn();
|
|
906
|
+
let inAppState;
|
|
907
|
+
render(
|
|
908
|
+
<TestComponent
|
|
909
|
+
options={{ autoSave: true, autoSaveInterval: 500, onSave }} // Below 1000ms minimum
|
|
910
|
+
onStateChange={(state) => { inAppState = state; }}
|
|
911
|
+
/>
|
|
912
|
+
);
|
|
913
|
+
|
|
914
|
+
act(() => {
|
|
915
|
+
inAppState.updateContent('<p>Content</p>');
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
act(() => {
|
|
919
|
+
jest.advanceTimersByTime(1000);
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
// onSave should not be called when interval is below minimum
|
|
923
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
924
|
+
});
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
describe('setDeviceContent State Updates (L95-L109)', () => {
|
|
928
|
+
it('updates Android content when newAndroidContent differs from current', () => {
|
|
929
|
+
// With the fix, initialContent effect only runs on first load or when transitioning from empty to content
|
|
930
|
+
// After initial load, changing initialContent won't update content (prevents overriding user edits)
|
|
931
|
+
const initialContent = {
|
|
932
|
+
[DEVICE_TYPES.ANDROID]: '', // Start with empty
|
|
933
|
+
[DEVICE_TYPES.IOS]: '',
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
const { rerender } = render(
|
|
937
|
+
<TestComponent initialContent={initialContent} />
|
|
938
|
+
);
|
|
939
|
+
|
|
940
|
+
// Initially empty
|
|
941
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('');
|
|
942
|
+
|
|
943
|
+
// Transition from empty to meaningful content - this SHOULD update
|
|
944
|
+
const updatedContent = {
|
|
945
|
+
[DEVICE_TYPES.ANDROID]: 'updated android',
|
|
946
|
+
[DEVICE_TYPES.IOS]: '',
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
rerender(<TestComponent initialContent={updatedContent} />);
|
|
950
|
+
|
|
951
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('updated android');
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
it('updates iOS content when newIosContent differs from current', () => {
|
|
955
|
+
// With the fix, initialContent effect only runs on first load or when transitioning from empty to content
|
|
956
|
+
const initialContent = {
|
|
957
|
+
[DEVICE_TYPES.ANDROID]: '',
|
|
958
|
+
[DEVICE_TYPES.IOS]: '', // Start with empty
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
const { rerender } = render(
|
|
962
|
+
<TestComponent initialContent={initialContent} />
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('');
|
|
966
|
+
|
|
967
|
+
// Transition from empty to meaningful content - this SHOULD update
|
|
968
|
+
const updatedContent = {
|
|
969
|
+
[DEVICE_TYPES.ANDROID]: '',
|
|
970
|
+
[DEVICE_TYPES.IOS]: 'updated ios',
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
rerender(<TestComponent initialContent={updatedContent} />);
|
|
974
|
+
|
|
975
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('updated ios');
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
it('updates both Android and iOS content when both differ', () => {
|
|
979
|
+
// With the fix, initialContent effect only runs on first load or when transitioning from empty to content
|
|
980
|
+
const initialContent = {
|
|
981
|
+
[DEVICE_TYPES.ANDROID]: '',
|
|
982
|
+
[DEVICE_TYPES.IOS]: '',
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
const { rerender } = render(
|
|
986
|
+
<TestComponent initialContent={initialContent} />
|
|
987
|
+
);
|
|
988
|
+
|
|
989
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('');
|
|
990
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('');
|
|
991
|
+
|
|
992
|
+
// Transition from empty to meaningful content - this SHOULD update
|
|
993
|
+
const updatedContent = {
|
|
994
|
+
[DEVICE_TYPES.ANDROID]: 'updated android',
|
|
995
|
+
[DEVICE_TYPES.IOS]: 'updated ios',
|
|
996
|
+
};
|
|
997
|
+
|
|
998
|
+
rerender(<TestComponent initialContent={updatedContent} />);
|
|
999
|
+
|
|
1000
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('updated android');
|
|
1001
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('updated ios');
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
it('does not update when content is the same', () => {
|
|
1005
|
+
const initialContent = {
|
|
1006
|
+
[DEVICE_TYPES.ANDROID]: 'same android',
|
|
1007
|
+
[DEVICE_TYPES.IOS]: 'same ios',
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
const { rerender } = render(
|
|
1011
|
+
<TestComponent initialContent={initialContent} />
|
|
1012
|
+
);
|
|
1013
|
+
|
|
1014
|
+
const sameContent = {
|
|
1015
|
+
[DEVICE_TYPES.ANDROID]: 'same android',
|
|
1016
|
+
[DEVICE_TYPES.IOS]: 'same ios',
|
|
1017
|
+
};
|
|
1018
|
+
|
|
1019
|
+
rerender(<TestComponent initialContent={sameContent} />);
|
|
1020
|
+
|
|
1021
|
+
// Content should remain the same
|
|
1022
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('same android');
|
|
1023
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('same ios');
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
it('handles undefined newAndroidContent gracefully', () => {
|
|
1027
|
+
// With the fix, after initial load, rerendering with different initialContent won't update
|
|
1028
|
+
// This test now verifies that content persists even when initialContent changes
|
|
1029
|
+
const initialContent = {
|
|
1030
|
+
[DEVICE_TYPES.ANDROID]: 'initial android',
|
|
1031
|
+
[DEVICE_TYPES.IOS]: 'initial ios',
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
const { rerender } = render(
|
|
1035
|
+
<TestComponent initialContent={initialContent} />
|
|
1036
|
+
);
|
|
1037
|
+
|
|
1038
|
+
const updatedContent = {
|
|
1039
|
+
[DEVICE_TYPES.IOS]: 'updated ios', // Android is undefined
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
rerender(<TestComponent initialContent={updatedContent} />);
|
|
1043
|
+
|
|
1044
|
+
// With the fix, content should NOT change after initial load (prevents overriding user edits)
|
|
1045
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('initial android');
|
|
1046
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('initial ios');
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
it('handles undefined newIosContent gracefully', () => {
|
|
1050
|
+
// With the fix, after initial load, rerendering with different initialContent won't update
|
|
1051
|
+
const initialContent = {
|
|
1052
|
+
[DEVICE_TYPES.ANDROID]: 'initial android',
|
|
1053
|
+
[DEVICE_TYPES.IOS]: 'initial ios',
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
const { rerender } = render(
|
|
1057
|
+
<TestComponent initialContent={initialContent} />
|
|
1058
|
+
);
|
|
1059
|
+
|
|
1060
|
+
const updatedContent = {
|
|
1061
|
+
[DEVICE_TYPES.ANDROID]: 'updated android', // iOS is undefined
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1064
|
+
rerender(<TestComponent initialContent={updatedContent} />);
|
|
1065
|
+
|
|
1066
|
+
// With the fix, content should NOT change after initial load (prevents overriding user edits)
|
|
1067
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('initial android');
|
|
1068
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('initial ios');
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
it('returns updated content object when changes are made', () => {
|
|
1072
|
+
// Test that the transition from empty to content works correctly
|
|
1073
|
+
const initialContent = {
|
|
1074
|
+
[DEVICE_TYPES.ANDROID]: '',
|
|
1075
|
+
[DEVICE_TYPES.IOS]: '',
|
|
1076
|
+
};
|
|
1077
|
+
|
|
1078
|
+
const { rerender } = render(
|
|
1079
|
+
<TestComponent initialContent={initialContent} />
|
|
1080
|
+
);
|
|
1081
|
+
|
|
1082
|
+
// Transition from empty to content - this SHOULD update
|
|
1083
|
+
const updatedContent = {
|
|
1084
|
+
[DEVICE_TYPES.ANDROID]: 'updated',
|
|
1085
|
+
[DEVICE_TYPES.IOS]: 'updated',
|
|
1086
|
+
};
|
|
1087
|
+
|
|
1088
|
+
rerender(<TestComponent initialContent={updatedContent} />);
|
|
1089
|
+
|
|
1090
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('updated');
|
|
1091
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('updated');
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
it('returns previous content object when no changes', () => {
|
|
1095
|
+
const initialContent = {
|
|
1096
|
+
[DEVICE_TYPES.ANDROID]: 'same',
|
|
1097
|
+
[DEVICE_TYPES.IOS]: 'same',
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1100
|
+
let firstRender = true;
|
|
1101
|
+
let previousState;
|
|
1102
|
+
|
|
1103
|
+
const TestObserver = ({ initialContent, onStateChange }) => {
|
|
1104
|
+
const inAppState = useInAppContent(initialContent);
|
|
1105
|
+
|
|
1106
|
+
React.useEffect(() => {
|
|
1107
|
+
if (firstRender) {
|
|
1108
|
+
previousState = inAppState.deviceContent;
|
|
1109
|
+
firstRender = false;
|
|
1110
|
+
} else {
|
|
1111
|
+
// Check if object reference is the same
|
|
1112
|
+
onStateChange?.(inAppState, previousState);
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
return (
|
|
1117
|
+
<div>
|
|
1118
|
+
<div data-testid="android-content">{inAppState.deviceContent[DEVICE_TYPES.ANDROID]}</div>
|
|
1119
|
+
<div data-testid="ios-content">{inAppState.deviceContent[DEVICE_TYPES.IOS]}</div>
|
|
1120
|
+
</div>
|
|
1121
|
+
);
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
const onStateChange = jest.fn();
|
|
1125
|
+
const { rerender } = render(
|
|
1126
|
+
<TestObserver initialContent={initialContent} onStateChange={onStateChange} />
|
|
1127
|
+
);
|
|
1128
|
+
|
|
1129
|
+
const sameContent = {
|
|
1130
|
+
[DEVICE_TYPES.ANDROID]: 'same',
|
|
1131
|
+
[DEVICE_TYPES.IOS]: 'same',
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1134
|
+
rerender(<TestObserver initialContent={sameContent} onStateChange={onStateChange} />);
|
|
1135
|
+
|
|
1136
|
+
// Content should be the same
|
|
1137
|
+
expect(screen.getByTestId('android-content')).toHaveTextContent('same');
|
|
1138
|
+
expect(screen.getByTestId('ios-content')).toHaveTextContent('same');
|
|
1139
|
+
});
|
|
1140
|
+
});
|
|
784
1141
|
});
|
|
785
1142
|
|
|
@@ -69,7 +69,10 @@ export const useEditorContent = (
|
|
|
69
69
|
} = options;
|
|
70
70
|
|
|
71
71
|
// Unified content state
|
|
72
|
-
|
|
72
|
+
// Use DEFAULT_CONTENT only if initialContent is null or undefined (not empty string)
|
|
73
|
+
// This allows explicitly passing empty string for empty content
|
|
74
|
+
const initialContentValue = initialContent == null ? DEFAULT_CONTENT : initialContent;
|
|
75
|
+
const [content, setContent] = useState(initialContentValue);
|
|
73
76
|
const [isDirty, setIsDirty] = useState(false);
|
|
74
77
|
const [lastSaved, setLastSaved] = useState(null);
|
|
75
78
|
const [isAutoSaveEnabled, setIsAutoSaveEnabled] = useState(autoSave);
|
|
@@ -79,7 +82,7 @@ export const useEditorContent = (
|
|
|
79
82
|
const validationDebounceRef = useRef(null);
|
|
80
83
|
const autoSaveRef = useRef(null);
|
|
81
84
|
const validationCallbackRef = useRef(null);
|
|
82
|
-
const lastContentRef = useRef(
|
|
85
|
+
const lastContentRef = useRef(initialContentValue);
|
|
83
86
|
|
|
84
87
|
// Smart debouncing hooks
|
|
85
88
|
const debouncedOnChange = useSmartDebounce(onChange || (() => {}), PERFORMANCE.PREVIEW_UPDATE_DEBOUNCE);
|