@capillarytech/creatives-library 8.0.242-alpha.1 → 8.0.242-alpha.11
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/config/app.js +1 -1
- package/constants/unified.js +2 -2
- package/initialReducer.js +0 -2
- package/package.json +1 -1
- package/services/api.js +5 -10
- package/services/tests/api.test.js +0 -18
- package/translations/en.json +4 -3
- package/utils/common.js +6 -5
- package/utils/commonUtils.js +1 -14
- package/utils/imageUrlUpload.js +141 -0
- package/utils/tests/commonUtil.test.js +0 -224
- package/utils/transformTemplateConfig.js +10 -0
- package/v2Components/CapDeviceContent/index.js +56 -61
- package/v2Components/CapImageUpload/constants.js +2 -0
- package/v2Components/CapImageUpload/index.js +65 -16
- package/v2Components/CapImageUpload/index.scss +4 -1
- package/v2Components/CapImageUpload/messages.js +5 -1
- package/v2Components/CapImageUrlUpload/constants.js +26 -0
- package/v2Components/CapImageUrlUpload/index.js +365 -0
- package/v2Components/CapImageUrlUpload/index.scss +35 -0
- package/v2Components/CapImageUrlUpload/messages.js +47 -0
- package/v2Components/CapTagList/index.js +1 -6
- package/v2Components/CapTagListWithInput/index.js +1 -5
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
- package/v2Components/ErrorInfoNote/index.js +72 -412
- package/v2Components/ErrorInfoNote/messages.js +0 -22
- package/v2Components/ErrorInfoNote/style.scss +2 -279
- package/v2Components/HtmlEditor/HTMLEditor.js +89 -210
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1132
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +12 -17
- package/v2Components/HtmlEditor/_htmlEditor.scss +23 -8
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -13
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +139 -148
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +11 -10
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +62 -87
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
- package/v2Components/HtmlEditor/constants.js +20 -29
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -95
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +101 -99
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
- package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -34
- package/v2Components/MobilePushPreviewV2/index.js +7 -32
- package/v2Components/TemplatePreview/_templatePreview.scss +24 -44
- package/v2Components/TemplatePreview/index.js +32 -47
- package/v2Components/TemplatePreview/messages.js +0 -4
- package/v2Components/TestAndPreviewSlidebox/index.js +25 -31
- package/v2Containers/App/constants.js +5 -0
- package/v2Containers/BeeEditor/index.js +80 -82
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +4 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +118 -148
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -9
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
- package/v2Containers/CreativesContainer/constants.js +2 -1
- package/v2Containers/CreativesContainer/index.js +41 -173
- package/v2Containers/CreativesContainer/messages.js +4 -4
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +210 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +354 -38
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -36
- package/v2Containers/Email/actions.js +0 -7
- package/v2Containers/Email/constants.js +1 -5
- package/v2Containers/Email/index.js +0 -13
- package/v2Containers/Email/messages.js +0 -32
- package/v2Containers/Email/reducer.js +1 -12
- package/v2Containers/Email/sagas.js +6 -41
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +7 -193
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
- package/v2Containers/EmailWrapper/constants.js +0 -2
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +67 -436
- package/v2Containers/EmailWrapper/index.js +23 -99
- package/v2Containers/EmailWrapper/messages.js +1 -61
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +1 -26
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -111
- package/v2Containers/InApp/actions.js +0 -7
- package/v2Containers/InApp/constants.js +4 -20
- package/v2Containers/InApp/index.js +357 -800
- package/v2Containers/InApp/index.scss +3 -4
- package/v2Containers/InApp/messages.js +3 -7
- package/v2Containers/InApp/reducer.js +3 -21
- package/v2Containers/InApp/sagas.js +9 -29
- package/v2Containers/InApp/selectors.js +5 -25
- package/v2Containers/InApp/tests/index.test.js +50 -154
- package/v2Containers/InApp/tests/reducer.test.js +0 -34
- package/v2Containers/InApp/tests/sagas.test.js +9 -61
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +12 -12
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +8 -8
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +100 -77
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +72 -63
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +184 -150
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +16 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +32 -28
- package/v2Containers/TagList/index.js +1 -67
- package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
- package/v2Containers/Templates/_templates.scss +202 -56
- package/v2Containers/Templates/actions.js +2 -1
- package/v2Containers/Templates/constants.js +1 -0
- package/v2Containers/Templates/index.js +278 -128
- package/v2Containers/Templates/messages.js +24 -4
- package/v2Containers/Templates/reducer.js +2 -0
- package/v2Containers/Templates/tests/index.test.js +10 -0
- package/v2Containers/TemplatesV2/index.js +8 -1
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/WebPush/Create/components/BrandIconSection.js +108 -0
- package/v2Containers/WebPush/Create/components/ButtonForm.js +172 -0
- package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
- package/v2Containers/WebPush/Create/components/ButtonList.js +145 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +164 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +463 -0
- package/v2Containers/WebPush/Create/components/FormActions.js +54 -0
- package/v2Containers/WebPush/Create/components/FormActions.test.js +163 -0
- package/v2Containers/WebPush/Create/components/MediaSection.js +142 -0
- package/v2Containers/WebPush/Create/components/MediaSection.test.js +341 -0
- package/v2Containers/WebPush/Create/components/MessageSection.js +103 -0
- package/v2Containers/WebPush/Create/components/MessageSection.test.js +268 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +87 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +210 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.js +54 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +143 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +86 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +16 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +41 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +54 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +37 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +21 -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 +78 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +138 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +406 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +30 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +151 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.js +104 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +538 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +122 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +633 -0
- package/v2Containers/WebPush/Create/index.js +1056 -0
- package/v2Containers/WebPush/Create/index.scss +134 -0
- package/v2Containers/WebPush/Create/messages.js +203 -0
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +228 -0
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +294 -0
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +90 -0
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +305 -0
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +23 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +150 -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/android-arrow-down.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +9 -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/macos-arrow-down-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +9 -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/assets/windows-close-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +47 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +141 -0
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +68 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +61 -0
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +99 -0
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +733 -0
- package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +571 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +81 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +81 -0
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +50 -0
- package/v2Containers/WebPush/Create/preview/constants.js +637 -0
- package/v2Containers/WebPush/Create/preview/notification-container.scss +79 -0
- package/v2Containers/WebPush/Create/preview/preview.scss +351 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +370 -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 +47 -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 +207 -0
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +153 -0
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +101 -0
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +229 -0
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +909 -0
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1081 -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 +131 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +112 -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 +129 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.js +94 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +390 -0
- package/v2Containers/WebPush/Create/utils/previewUtils.js +89 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.js +115 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
- package/v2Containers/WebPush/Create/utils/validation.js +75 -0
- package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
- package/v2Containers/WebPush/actions.js +60 -0
- package/v2Containers/WebPush/constants.js +128 -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 +843 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +528 -431
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -362
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
- package/v2Containers/BeePopupEditor/constants.js +0 -10
- package/v2Containers/BeePopupEditor/index.js +0 -193
- package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1045
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
- package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
- package/v2Containers/InApp/tests/selectors.test.js +0 -612
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -162
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -9
- package/v2Containers/InAppWrapper/constants.js +0 -16
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
- package/v2Containers/InAppWrapper/index.js +0 -148
- package/v2Containers/InAppWrapper/messages.js +0 -49
- package/v2Containers/InappAdvance/index.js +0 -1099
- package/v2Containers/InappAdvance/index.scss +0 -10
- package/v2Containers/InappAdvance/tests/index.test.js +0 -448
|
@@ -5,51 +5,33 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
|
-
import {
|
|
9
|
-
render, screen, fireEvent, act, waitFor,
|
|
10
|
-
} from '@testing-library/react';
|
|
8
|
+
import { render, screen, fireEvent, act, waitFor } from '@testing-library/react';
|
|
11
9
|
import '@testing-library/jest-dom';
|
|
12
10
|
import { IntlProvider } from 'react-intl';
|
|
13
11
|
import HTMLEditor from '../HTMLEditor';
|
|
14
12
|
|
|
15
|
-
// Options to control CodeEditorPane mock behavior
|
|
16
|
-
const mockCodeEditorOptions = {
|
|
17
|
-
includeInsertText: true,
|
|
18
|
-
insertTextThrows: false,
|
|
19
|
-
setRef: true,
|
|
20
|
-
navigateToLineThrows: false,
|
|
21
|
-
includeNavigateToLine: true,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
|
|
25
13
|
// Mock useLayoutEffect to behave like useEffect in tests
|
|
26
14
|
React.useLayoutEffect = React.useEffect;
|
|
27
15
|
|
|
28
16
|
// Mock browser APIs
|
|
29
17
|
global.IntersectionObserver = class IntersectionObserver {
|
|
30
|
-
constructor() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
observe() { }
|
|
35
|
-
|
|
36
|
-
unobserve() { }
|
|
18
|
+
constructor() {}
|
|
19
|
+
disconnect() {}
|
|
20
|
+
observe() {}
|
|
21
|
+
unobserve() {}
|
|
37
22
|
};
|
|
38
23
|
|
|
39
24
|
global.ResizeObserver = class ResizeObserver {
|
|
40
|
-
constructor() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
observe() { }
|
|
45
|
-
|
|
46
|
-
unobserve() { }
|
|
25
|
+
constructor() {}
|
|
26
|
+
disconnect() {}
|
|
27
|
+
observe() {}
|
|
28
|
+
unobserve() {}
|
|
47
29
|
};
|
|
48
30
|
|
|
49
31
|
// Setup window.matchMedia mock
|
|
50
32
|
Object.defineProperty(window, 'matchMedia', {
|
|
51
33
|
writable: true,
|
|
52
|
-
value: jest.fn().mockImplementation(
|
|
34
|
+
value: jest.fn().mockImplementation(query => ({
|
|
53
35
|
matches: false,
|
|
54
36
|
media: query,
|
|
55
37
|
onchange: null,
|
|
@@ -106,97 +88,60 @@ window.getComputedStyle = jest.fn(() => ({
|
|
|
106
88
|
jest.mock('@capillarytech/cap-ui-library/CapNotification', () => ({
|
|
107
89
|
warning: jest.fn(),
|
|
108
90
|
error: jest.fn(),
|
|
109
|
-
success: jest.fn()
|
|
91
|
+
success: jest.fn()
|
|
110
92
|
}));
|
|
111
93
|
|
|
112
94
|
// Mock components
|
|
113
|
-
jest.mock('../components/EditorToolbar', () =>
|
|
114
|
-
return (
|
|
115
|
-
|
|
116
|
-
<
|
|
117
|
-
|
|
95
|
+
jest.mock('../components/EditorToolbar', () => {
|
|
96
|
+
return function MockEditorToolbar(props) {
|
|
97
|
+
return (
|
|
98
|
+
<div data-testid="editor-toolbar">
|
|
99
|
+
<button onClick={props.onToggleFullscreen}>Toggle Fullscreen</button>
|
|
100
|
+
<button onClick={() => props.onLabelInsert && props.onLabelInsert('test-label', 10)}>
|
|
118
101
|
Insert Label
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Insert Label (Null Position)
|
|
122
|
-
</button>
|
|
123
|
-
<button onClick={() => props.onSave && props.onSave()}>
|
|
102
|
+
</button>
|
|
103
|
+
<button onClick={() => props.onSave && props.onSave()}>
|
|
124
104
|
Save
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
105
|
+
</button>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
128
109
|
});
|
|
129
110
|
|
|
130
|
-
jest.mock('../components/DeviceToggle', () =>
|
|
131
|
-
return (
|
|
132
|
-
|
|
133
|
-
<
|
|
111
|
+
jest.mock('../components/DeviceToggle', () => {
|
|
112
|
+
return function MockDeviceToggle(props) {
|
|
113
|
+
return (
|
|
114
|
+
<div data-testid="device-toggle">
|
|
115
|
+
<button onClick={() => props.onDeviceChange && props.onDeviceChange('android')}>
|
|
134
116
|
Android
|
|
135
|
-
|
|
136
|
-
|
|
117
|
+
</button>
|
|
118
|
+
<button onClick={() => props.onDeviceChange && props.onDeviceChange('ios')}>
|
|
137
119
|
iOS
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
141
124
|
});
|
|
142
125
|
|
|
143
|
-
jest.mock('../components/SplitContainer', () =>
|
|
144
|
-
return
|
|
126
|
+
jest.mock('../components/SplitContainer', () => {
|
|
127
|
+
return function MockSplitContainer({ children }) {
|
|
128
|
+
return <div data-testid="split-container">{children}</div>;
|
|
129
|
+
};
|
|
145
130
|
});
|
|
146
131
|
|
|
147
|
-
|
|
148
132
|
jest.mock('../components/CodeEditorPane', () => {
|
|
149
133
|
const React = require('react');
|
|
150
|
-
|
|
151
|
-
return React.forwardRef((props, ref) => {
|
|
134
|
+
return React.forwardRef(function MockCodeEditorPane(props, ref) {
|
|
152
135
|
const [value, setValue] = React.useState('');
|
|
153
|
-
// Get validation from context
|
|
154
|
-
let validation = null;
|
|
155
|
-
try {
|
|
156
|
-
const context = useEditorContext();
|
|
157
|
-
validation = context?.validation;
|
|
158
|
-
} catch (e) {
|
|
159
|
-
// Context not available, use props or null
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
React.useImperativeHandle(ref, () => {
|
|
163
|
-
if (!mockCodeEditorOptions.setRef) {
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const methods = {
|
|
168
|
-
focus: jest.fn(),
|
|
169
|
-
getCursor: jest.fn(() => 0),
|
|
170
|
-
getValue: jest.fn(() => value),
|
|
171
|
-
setValue: jest.fn((newValue) => setValue(newValue)),
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
if (mockCodeEditorOptions.includeNavigateToLine) {
|
|
175
|
-
methods.navigateToLine = jest.fn(() => {
|
|
176
|
-
if (mockCodeEditorOptions.navigateToLineThrows) {
|
|
177
|
-
throw new Error('Navigation failed');
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (mockCodeEditorOptions.includeInsertText) {
|
|
183
|
-
methods.insertText = jest.fn(() => {
|
|
184
|
-
if (mockCodeEditorOptions.insertTextThrows) {
|
|
185
|
-
throw new Error('Insert failed');
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return methods;
|
|
191
|
-
});
|
|
192
136
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
137
|
+
React.useImperativeHandle(ref, () => ({
|
|
138
|
+
insertText: jest.fn(),
|
|
139
|
+
focus: jest.fn(),
|
|
140
|
+
getCursor: jest.fn(() => 0),
|
|
141
|
+
getValue: jest.fn(() => value),
|
|
142
|
+
setValue: jest.fn((newValue) => setValue(newValue)),
|
|
143
|
+
navigateToLine: jest.fn(),
|
|
144
|
+
}));
|
|
200
145
|
|
|
201
146
|
return (
|
|
202
147
|
<div data-testid="code-editor-pane">
|
|
@@ -210,47 +155,36 @@ jest.mock('../components/CodeEditorPane', () => {
|
|
|
210
155
|
}}
|
|
211
156
|
data-testid="editor-textarea"
|
|
212
157
|
/>
|
|
213
|
-
<button
|
|
214
|
-
onClick={() => props.onContextChange && props.onContextChange('test-context')}
|
|
215
|
-
data-testid="trigger-context-change"
|
|
216
|
-
>
|
|
217
|
-
Trigger Context Change
|
|
218
|
-
</button>
|
|
219
|
-
{validation && (
|
|
220
|
-
<ValidationErrorDisplay
|
|
221
|
-
validation={validation}
|
|
222
|
-
onErrorClick={props.onErrorClick}
|
|
223
|
-
/>
|
|
224
|
-
)}
|
|
225
158
|
</div>
|
|
226
159
|
);
|
|
227
160
|
});
|
|
228
161
|
});
|
|
229
162
|
|
|
230
|
-
jest.mock('../components/PreviewPane', () =>
|
|
231
|
-
return (
|
|
232
|
-
|
|
163
|
+
jest.mock('../components/PreviewPane', () => {
|
|
164
|
+
return function MockPreviewPane(props) {
|
|
165
|
+
return (
|
|
166
|
+
<div data-testid="preview-pane" data-fullscreen={props.isFullscreenMode}>
|
|
233
167
|
Preview Content
|
|
234
|
-
|
|
235
|
-
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
};
|
|
236
171
|
});
|
|
237
172
|
|
|
238
|
-
jest.mock('../components/ValidationErrorDisplay', () =>
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
<div>Validation Errors</div>
|
|
246
|
-
<button onClick={() => onErrorClick && onErrorClick({ line: 5, column: 10 })}>
|
|
173
|
+
jest.mock('../components/ValidationErrorDisplay', () => {
|
|
174
|
+
return function MockValidationErrorDisplay({ validation, onErrorClick }) {
|
|
175
|
+
if (!validation || validation.isClean?.()) return null;
|
|
176
|
+
return (
|
|
177
|
+
<div data-testid="validation-error-display">
|
|
178
|
+
<div>Validation Errors</div>
|
|
179
|
+
<button onClick={() => onErrorClick && onErrorClick({ line: 5, column: 10 })}>
|
|
247
180
|
Error at Line 5
|
|
248
|
-
|
|
249
|
-
|
|
181
|
+
</button>
|
|
182
|
+
<button onClick={() => onErrorClick && onErrorClick({ line: null })}>
|
|
250
183
|
Error without Line
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
184
|
+
</button>
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
254
188
|
});
|
|
255
189
|
|
|
256
190
|
// Mock hooks - Return complete hook objects with all required methods
|
|
@@ -263,8 +197,8 @@ jest.mock('../hooks/useEditorContent', () => ({
|
|
|
263
197
|
isLoading: false,
|
|
264
198
|
isDirty: false,
|
|
265
199
|
hasContent: true,
|
|
266
|
-
getContentSize: jest.fn(() => 20)
|
|
267
|
-
})
|
|
200
|
+
getContentSize: jest.fn(() => 20)
|
|
201
|
+
})
|
|
268
202
|
}));
|
|
269
203
|
|
|
270
204
|
jest.mock('../hooks/useInAppContent', () => ({
|
|
@@ -272,7 +206,7 @@ jest.mock('../hooks/useInAppContent', () => ({
|
|
|
272
206
|
content: '<p>Android content</p>',
|
|
273
207
|
deviceContent: {
|
|
274
208
|
android: '<p>Android content</p>',
|
|
275
|
-
ios: '<p>iOS content</p>'
|
|
209
|
+
ios: '<p>iOS content</p>'
|
|
276
210
|
},
|
|
277
211
|
activeDevice: 'android',
|
|
278
212
|
keepContentSame: false,
|
|
@@ -286,8 +220,8 @@ jest.mock('../hooks/useInAppContent', () => ({
|
|
|
286
220
|
getContentSize: () => 20,
|
|
287
221
|
isLoading: false,
|
|
288
222
|
isDirty: false,
|
|
289
|
-
hasContent: true
|
|
290
|
-
})
|
|
223
|
+
hasContent: true
|
|
224
|
+
})
|
|
291
225
|
}));
|
|
292
226
|
|
|
293
227
|
jest.mock('../hooks/useLayoutState', () => ({
|
|
@@ -319,8 +253,8 @@ jest.mock('../hooks/useLayoutState', () => ({
|
|
|
319
253
|
// Layout constraints
|
|
320
254
|
minPaneSize: 20,
|
|
321
255
|
maxPaneSize: 80,
|
|
322
|
-
gutterSize: 10
|
|
323
|
-
})
|
|
256
|
+
gutterSize: 10
|
|
257
|
+
})
|
|
324
258
|
}));
|
|
325
259
|
|
|
326
260
|
// Mock useValidation - need to use a variable that gets assigned in the factory
|
|
@@ -331,11 +265,11 @@ jest.mock('../hooks/useValidation', () => {
|
|
|
331
265
|
isValidating: false,
|
|
332
266
|
getAllIssues: () => [],
|
|
333
267
|
isClean: () => true,
|
|
334
|
-
summary: { totalErrors: 0, totalWarnings: 0 }
|
|
268
|
+
summary: { totalErrors: 0, totalWarnings: 0 }
|
|
335
269
|
}));
|
|
336
270
|
|
|
337
271
|
return {
|
|
338
|
-
useValidation: (...args) => mockUseValidationImpl(...args)
|
|
272
|
+
useValidation: (...args) => mockUseValidationImpl(...args)
|
|
339
273
|
};
|
|
340
274
|
});
|
|
341
275
|
|
|
@@ -363,7 +297,7 @@ describe('HTMLEditor', () => {
|
|
|
363
297
|
initialContent: '<p>Initial content</p>',
|
|
364
298
|
onChange: jest.fn(),
|
|
365
299
|
onSave: jest.fn(),
|
|
366
|
-
variant: 'email'
|
|
300
|
+
variant: 'email'
|
|
367
301
|
};
|
|
368
302
|
|
|
369
303
|
describe('Loading State', () => {
|
|
@@ -433,7 +367,7 @@ describe('HTMLEditor', () => {
|
|
|
433
367
|
|
|
434
368
|
// Context should reflect fullscreen mode change
|
|
435
369
|
const previewPanes = screen.getAllByTestId('preview-pane');
|
|
436
|
-
expect(previewPanes.some(
|
|
370
|
+
expect(previewPanes.some(pane => pane.getAttribute('data-fullscreen') === 'true')).toBe(true);
|
|
437
371
|
});
|
|
438
372
|
});
|
|
439
373
|
|
|
@@ -539,44 +473,10 @@ describe('HTMLEditor', () => {
|
|
|
539
473
|
expect(screen.getByTestId('device-toggle')).toBeInTheDocument();
|
|
540
474
|
});
|
|
541
475
|
|
|
542
|
-
it('converts string initialContent to device-specific format for inapp variant', () => {
|
|
543
|
-
// This test covers lines 104-109 in HTMLEditor.js
|
|
544
|
-
const mockUseInAppContent = require('../hooks/useInAppContent').useInAppContent;
|
|
545
|
-
const originalUseInAppContent = jest.requireActual('../hooks/useInAppContent').useInAppContent;
|
|
546
|
-
|
|
547
|
-
let capturedInitialContent = null;
|
|
548
|
-
jest.spyOn(require('../hooks/useInAppContent'), 'useInAppContent').mockImplementation((initialContent) => {
|
|
549
|
-
capturedInitialContent = initialContent;
|
|
550
|
-
return originalUseInAppContent(initialContent, {});
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
render(
|
|
554
|
-
<TestWrapper>
|
|
555
|
-
<HTMLEditor
|
|
556
|
-
{...defaultProps}
|
|
557
|
-
variant="inapp"
|
|
558
|
-
initialContent="<p>String content</p>"
|
|
559
|
-
/>
|
|
560
|
-
</TestWrapper>
|
|
561
|
-
);
|
|
562
|
-
|
|
563
|
-
act(() => {
|
|
564
|
-
jest.runAllTimers();
|
|
565
|
-
});
|
|
566
|
-
|
|
567
|
-
// Verify that string content was converted to device-specific format
|
|
568
|
-
expect(capturedInitialContent).toEqual({
|
|
569
|
-
android: '<p>String content</p>',
|
|
570
|
-
ios: '<p>String content</p>',
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
jest.restoreAllMocks();
|
|
574
|
-
});
|
|
575
|
-
|
|
576
476
|
it('handles object initialContent for inapp variant', () => {
|
|
577
477
|
const deviceContent = {
|
|
578
478
|
android: '<p>Android content</p>',
|
|
579
|
-
ios: '<p>iOS content</p>'
|
|
479
|
+
ios: '<p>iOS content</p>'
|
|
580
480
|
};
|
|
581
481
|
|
|
582
482
|
render(
|
|
@@ -596,42 +496,6 @@ describe('HTMLEditor', () => {
|
|
|
596
496
|
expect(screen.getByTestId('device-toggle')).toBeInTheDocument();
|
|
597
497
|
});
|
|
598
498
|
|
|
599
|
-
it('uses provided device-specific content for inapp variant', () => {
|
|
600
|
-
// This test covers lines 110-113 in HTMLEditor.js
|
|
601
|
-
const deviceContent = {
|
|
602
|
-
android: '<p>Android content</p>',
|
|
603
|
-
ios: '<p>iOS content</p>',
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
const mockUseInAppContent = require('../hooks/useInAppContent').useInAppContent;
|
|
607
|
-
const originalUseInAppContent = jest.requireActual('../hooks/useInAppContent').useInAppContent;
|
|
608
|
-
|
|
609
|
-
let capturedInitialContent = null;
|
|
610
|
-
jest.spyOn(require('../hooks/useInAppContent'), 'useInAppContent').mockImplementation((initialContent) => {
|
|
611
|
-
capturedInitialContent = initialContent;
|
|
612
|
-
return originalUseInAppContent(initialContent, {});
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
render(
|
|
616
|
-
<TestWrapper>
|
|
617
|
-
<HTMLEditor
|
|
618
|
-
{...defaultProps}
|
|
619
|
-
variant="inapp"
|
|
620
|
-
initialContent={deviceContent}
|
|
621
|
-
/>
|
|
622
|
-
</TestWrapper>
|
|
623
|
-
);
|
|
624
|
-
|
|
625
|
-
act(() => {
|
|
626
|
-
jest.runAllTimers();
|
|
627
|
-
});
|
|
628
|
-
|
|
629
|
-
// Verify that object content was passed as-is
|
|
630
|
-
expect(capturedInitialContent).toEqual(deviceContent);
|
|
631
|
-
|
|
632
|
-
jest.restoreAllMocks();
|
|
633
|
-
});
|
|
634
|
-
|
|
635
499
|
it('handles inapp variant with layoutType', () => {
|
|
636
500
|
render(
|
|
637
501
|
<TestWrapper>
|
|
@@ -686,7 +550,7 @@ describe('HTMLEditor', () => {
|
|
|
686
550
|
// Should open fullscreen modal - now there are 2 preview panes (main + fullscreen modal)
|
|
687
551
|
const previewPanes = screen.getAllByTestId('preview-pane');
|
|
688
552
|
expect(previewPanes.length).toBeGreaterThan(1);
|
|
689
|
-
expect(previewPanes.some(
|
|
553
|
+
expect(previewPanes.some(pane => pane.getAttribute('data-fullscreen') === 'true')).toBe(true);
|
|
690
554
|
});
|
|
691
555
|
|
|
692
556
|
it('renders fullscreen modal with correct components', () => {
|
|
@@ -704,7 +568,7 @@ describe('HTMLEditor', () => {
|
|
|
704
568
|
fireEvent.click(toggleButton);
|
|
705
569
|
|
|
706
570
|
const previewPanes = screen.getAllByTestId('preview-pane');
|
|
707
|
-
expect(previewPanes.some(
|
|
571
|
+
expect(previewPanes.some(pane => pane.getAttribute('data-fullscreen') === 'true')).toBe(true);
|
|
708
572
|
});
|
|
709
573
|
|
|
710
574
|
it('renders fullscreen modal for inapp variant', () => {
|
|
@@ -742,7 +606,7 @@ describe('HTMLEditor', () => {
|
|
|
742
606
|
fireEvent.click(toggleButton);
|
|
743
607
|
|
|
744
608
|
// Should have multiple preview panes
|
|
745
|
-
|
|
609
|
+
let previewPanes = screen.getAllByTestId('preview-pane');
|
|
746
610
|
expect(previewPanes.length).toBeGreaterThan(1);
|
|
747
611
|
|
|
748
612
|
// Close fullscreen (button should still be available to close)
|
|
@@ -803,7 +667,7 @@ describe('HTMLEditor', () => {
|
|
|
803
667
|
isValidating: false,
|
|
804
668
|
getAllIssues: () => [{ message: 'Test error', severity: 'error' }],
|
|
805
669
|
isClean: () => false,
|
|
806
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
670
|
+
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
807
671
|
});
|
|
808
672
|
|
|
809
673
|
render(
|
|
@@ -824,7 +688,7 @@ describe('HTMLEditor', () => {
|
|
|
824
688
|
isValidating: false,
|
|
825
689
|
getAllIssues: () => [],
|
|
826
690
|
isClean: () => true,
|
|
827
|
-
summary: { totalErrors: 0, totalWarnings: 0 }
|
|
691
|
+
summary: { totalErrors: 0, totalWarnings: 0 }
|
|
828
692
|
});
|
|
829
693
|
|
|
830
694
|
render(
|
|
@@ -845,7 +709,7 @@ describe('HTMLEditor', () => {
|
|
|
845
709
|
it('handles readOnly prop', () => {
|
|
846
710
|
render(
|
|
847
711
|
<TestWrapper>
|
|
848
|
-
<HTMLEditor {...defaultProps} readOnly />
|
|
712
|
+
<HTMLEditor {...defaultProps} readOnly={true} />
|
|
849
713
|
</TestWrapper>
|
|
850
714
|
);
|
|
851
715
|
|
|
@@ -993,7 +857,7 @@ describe('HTMLEditor', () => {
|
|
|
993
857
|
describe('Error Handling', () => {
|
|
994
858
|
it('handles missing editorRef gracefully', () => {
|
|
995
859
|
// Mock console.warn to avoid noise in tests
|
|
996
|
-
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {
|
|
860
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
997
861
|
|
|
998
862
|
render(
|
|
999
863
|
<TestWrapper>
|
|
@@ -1020,7 +884,7 @@ describe('HTMLEditor', () => {
|
|
|
1020
884
|
focus: jest.fn(),
|
|
1021
885
|
getCursor: jest.fn(() => 0),
|
|
1022
886
|
// Missing insertText method
|
|
1023
|
-
}
|
|
887
|
+
}
|
|
1024
888
|
};
|
|
1025
889
|
|
|
1026
890
|
// Mock the ref to return an editor without insertText
|
|
@@ -1055,7 +919,7 @@ describe('HTMLEditor', () => {
|
|
|
1055
919
|
insertText: jest.fn(() => { throw new Error('Insert failed'); }),
|
|
1056
920
|
focus: jest.fn(),
|
|
1057
921
|
getCursor: jest.fn(() => 0),
|
|
1058
|
-
}
|
|
922
|
+
}
|
|
1059
923
|
};
|
|
1060
924
|
|
|
1061
925
|
const TestComponent = () => {
|
|
@@ -1121,7 +985,7 @@ describe('HTMLEditor', () => {
|
|
|
1121
985
|
current: {
|
|
1122
986
|
navigateToLine: jest.fn(() => { throw new Error('Navigation failed'); }),
|
|
1123
987
|
focus: jest.fn(),
|
|
1124
|
-
}
|
|
988
|
+
}
|
|
1125
989
|
};
|
|
1126
990
|
|
|
1127
991
|
const TestComponent = () => {
|
|
@@ -1206,8 +1070,8 @@ describe('HTMLEditor', () => {
|
|
|
1206
1070
|
onContentChange={jest.fn()}
|
|
1207
1071
|
className="test-class"
|
|
1208
1072
|
readOnly={false}
|
|
1209
|
-
showFullscreenButton
|
|
1210
|
-
autoSave
|
|
1073
|
+
showFullscreenButton={true}
|
|
1074
|
+
autoSave={true}
|
|
1211
1075
|
autoSaveInterval={30000}
|
|
1212
1076
|
/>
|
|
1213
1077
|
</TestWrapper>
|
|
@@ -1239,7 +1103,7 @@ describe('HTMLEditor', () => {
|
|
|
1239
1103
|
<TestWrapper>
|
|
1240
1104
|
<HTMLEditor
|
|
1241
1105
|
variant="inapp"
|
|
1242
|
-
autoSave
|
|
1106
|
+
autoSave={true}
|
|
1243
1107
|
autoSaveInterval={15000}
|
|
1244
1108
|
onSave={jest.fn()}
|
|
1245
1109
|
onContentChange={jest.fn()}
|
|
@@ -1276,10 +1140,10 @@ describe('HTMLEditor', () => {
|
|
|
1276
1140
|
enableRealTime: true,
|
|
1277
1141
|
debounceMs: 500,
|
|
1278
1142
|
enableSanitization: true,
|
|
1279
|
-
securityLevel: 'standard'
|
|
1143
|
+
securityLevel: 'standard'
|
|
1280
1144
|
}),
|
|
1281
1145
|
expect.any(Function), // formatSanitizerMessage
|
|
1282
|
-
expect.any(Function)
|
|
1146
|
+
expect.any(Function) // formatValidatorMessage
|
|
1283
1147
|
);
|
|
1284
1148
|
});
|
|
1285
1149
|
|
|
@@ -1302,10 +1166,10 @@ describe('HTMLEditor', () => {
|
|
|
1302
1166
|
enableRealTime: true,
|
|
1303
1167
|
debounceMs: 500,
|
|
1304
1168
|
enableSanitization: true,
|
|
1305
|
-
securityLevel: 'standard'
|
|
1169
|
+
securityLevel: 'standard'
|
|
1306
1170
|
}),
|
|
1307
1171
|
expect.any(Function), // formatSanitizerMessage
|
|
1308
|
-
expect.any(Function)
|
|
1172
|
+
expect.any(Function) // formatValidatorMessage
|
|
1309
1173
|
);
|
|
1310
1174
|
});
|
|
1311
1175
|
|
|
@@ -1371,7 +1235,7 @@ describe('HTMLEditor', () => {
|
|
|
1371
1235
|
enableRealTime: true,
|
|
1372
1236
|
debounceMs: 500,
|
|
1373
1237
|
enableSanitization: true,
|
|
1374
|
-
securityLevel: 'standard'
|
|
1238
|
+
securityLevel: 'standard'
|
|
1375
1239
|
},
|
|
1376
1240
|
expect.any(Function),
|
|
1377
1241
|
expect.any(Function)
|
|
@@ -1462,8 +1326,8 @@ describe('HTMLEditor', () => {
|
|
|
1462
1326
|
<div className="html-editor html-editor--email">
|
|
1463
1327
|
<CustomToolbar
|
|
1464
1328
|
onLabelInsert={handleLabelInsert}
|
|
1465
|
-
onToggleFullscreen={() => {
|
|
1466
|
-
onSave={() => {
|
|
1329
|
+
onToggleFullscreen={() => {}}
|
|
1330
|
+
onSave={() => {}}
|
|
1467
1331
|
/>
|
|
1468
1332
|
<div data-testid="split-container">
|
|
1469
1333
|
<div data-testid="code-editor-pane" ref={editorRef}>
|
|
@@ -1561,7 +1425,7 @@ describe('HTMLEditor', () => {
|
|
|
1561
1425
|
isValidating: false,
|
|
1562
1426
|
getAllIssues: () => [{ message: 'Test error', severity: 'error' }],
|
|
1563
1427
|
isClean: () => false,
|
|
1564
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1428
|
+
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1565
1429
|
});
|
|
1566
1430
|
|
|
1567
1431
|
// Create a custom validation display that triggers the error click handler
|
|
@@ -1637,7 +1501,7 @@ describe('HTMLEditor', () => {
|
|
|
1637
1501
|
current: {
|
|
1638
1502
|
navigateToLine: jest.fn(),
|
|
1639
1503
|
focus: jest.fn(),
|
|
1640
|
-
}
|
|
1504
|
+
}
|
|
1641
1505
|
};
|
|
1642
1506
|
|
|
1643
1507
|
// Mock validation to show errors
|
|
@@ -1645,7 +1509,7 @@ describe('HTMLEditor', () => {
|
|
|
1645
1509
|
isValidating: false,
|
|
1646
1510
|
getAllIssues: () => [{ message: 'Test error', severity: 'error' }],
|
|
1647
1511
|
isClean: () => false,
|
|
1648
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1512
|
+
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1649
1513
|
});
|
|
1650
1514
|
|
|
1651
1515
|
const TestComponent = () => {
|
|
@@ -1679,7 +1543,7 @@ describe('HTMLEditor', () => {
|
|
|
1679
1543
|
current: {
|
|
1680
1544
|
focus: jest.fn(),
|
|
1681
1545
|
// Missing navigateToLine method
|
|
1682
|
-
}
|
|
1546
|
+
}
|
|
1683
1547
|
};
|
|
1684
1548
|
|
|
1685
1549
|
const TestComponent = () => {
|
|
@@ -1759,64 +1623,41 @@ describe('HTMLEditor', () => {
|
|
|
1759
1623
|
});
|
|
1760
1624
|
|
|
1761
1625
|
describe('Loading State Coverage (Lines 343-349)', () => {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
toggleFullscreen: jest.fn(),
|
|
1779
|
-
resetLayout: jest.fn(),
|
|
1780
|
-
setResizingState: jest.fn(),
|
|
1781
|
-
handleResize: jest.fn(),
|
|
1782
|
-
handleKeyboardShortcut: jest.fn(),
|
|
1783
|
-
isMobileView: false,
|
|
1784
|
-
isDesktopView: true,
|
|
1785
|
-
minPaneSize: 20,
|
|
1786
|
-
maxPaneSize: 80,
|
|
1787
|
-
gutterSize: 10,
|
|
1788
|
-
}));
|
|
1626
|
+
// Create separate test components to isolate mock effects
|
|
1627
|
+
const LoadingTestComponent = ({ mockContent = null, mockLayout = null }) => {
|
|
1628
|
+
// Mock the hooks inline for this specific test
|
|
1629
|
+
const useEditorContentMock = jest.fn(() => mockContent);
|
|
1630
|
+
const useInAppContentMock = jest.fn(() => mockContent);
|
|
1631
|
+
const useLayoutStateMock = jest.fn(() => mockLayout);
|
|
1632
|
+
|
|
1633
|
+
// Replace the hooks temporarily
|
|
1634
|
+
React.useMemo(() => {
|
|
1635
|
+
require('../hooks/useEditorContent').useEditorContent = useEditorContentMock;
|
|
1636
|
+
require('../hooks/useInAppContent').useInAppContent = useInAppContentMock;
|
|
1637
|
+
require('../hooks/useLayoutState').useLayoutState = useLayoutStateMock;
|
|
1638
|
+
}, []);
|
|
1639
|
+
|
|
1640
|
+
return <HTMLEditor {...defaultProps} />;
|
|
1641
|
+
};
|
|
1789
1642
|
|
|
1643
|
+
it('shows loading state when content is null', () => {
|
|
1790
1644
|
render(
|
|
1791
1645
|
<TestWrapper>
|
|
1792
|
-
<
|
|
1646
|
+
<LoadingTestComponent mockContent={null} mockLayout={{ splitSizes: [50, 50] }} />
|
|
1793
1647
|
</TestWrapper>
|
|
1794
1648
|
);
|
|
1795
1649
|
|
|
1796
1650
|
// Should show loading state
|
|
1797
1651
|
expect(screen.getByText('Initializing HTML Editor...')).toBeInTheDocument();
|
|
1798
|
-
|
|
1799
|
-
// Restore original mock
|
|
1800
|
-
require('../hooks/useEditorContent').useEditorContent = originalUseEditorContent;
|
|
1801
1652
|
});
|
|
1802
1653
|
|
|
1803
1654
|
it('shows loading state when layout is null', () => {
|
|
1804
|
-
// Temporarily override the mock to return null layout
|
|
1805
|
-
require('../hooks/useLayoutState').useLayoutState = jest.fn(() => null);
|
|
1806
|
-
require('../hooks/useEditorContent').useEditorContent = jest.fn(() => ({
|
|
1807
|
-
content: '<p>Test</p>',
|
|
1808
|
-
updateContent: jest.fn(),
|
|
1809
|
-
saveContent: jest.fn(),
|
|
1810
|
-
markAsSaved: jest.fn(),
|
|
1811
|
-
isLoading: false,
|
|
1812
|
-
isDirty: false,
|
|
1813
|
-
hasContent: true,
|
|
1814
|
-
getContentSize: jest.fn(() => 20),
|
|
1815
|
-
}));
|
|
1816
|
-
|
|
1817
1655
|
render(
|
|
1818
1656
|
<TestWrapper>
|
|
1819
|
-
<
|
|
1657
|
+
<LoadingTestComponent
|
|
1658
|
+
mockContent={{ content: '<p>Test</p>' }}
|
|
1659
|
+
mockLayout={null}
|
|
1660
|
+
/>
|
|
1820
1661
|
</TestWrapper>
|
|
1821
1662
|
);
|
|
1822
1663
|
|
|
@@ -1825,12 +1666,9 @@ describe('HTMLEditor', () => {
|
|
|
1825
1666
|
});
|
|
1826
1667
|
|
|
1827
1668
|
it('shows loading state when both content and layout are null', () => {
|
|
1828
|
-
require('../hooks/useEditorContent').useEditorContent = jest.fn(() => null);
|
|
1829
|
-
require('../hooks/useLayoutState').useLayoutState = jest.fn(() => null);
|
|
1830
|
-
|
|
1831
1669
|
render(
|
|
1832
1670
|
<TestWrapper>
|
|
1833
|
-
<
|
|
1671
|
+
<LoadingTestComponent mockContent={null} mockLayout={null} />
|
|
1834
1672
|
</TestWrapper>
|
|
1835
1673
|
);
|
|
1836
1674
|
|
|
@@ -1838,43 +1676,12 @@ describe('HTMLEditor', () => {
|
|
|
1838
1676
|
});
|
|
1839
1677
|
|
|
1840
1678
|
it('renders normally when both content and layout are available', () => {
|
|
1841
|
-
require('../hooks/useEditorContent').useEditorContent = jest.fn(() => ({
|
|
1842
|
-
content: '<p>Test</p>',
|
|
1843
|
-
updateContent: jest.fn(),
|
|
1844
|
-
saveContent: jest.fn(),
|
|
1845
|
-
markAsSaved: jest.fn(),
|
|
1846
|
-
isLoading: false,
|
|
1847
|
-
isDirty: false,
|
|
1848
|
-
hasContent: true,
|
|
1849
|
-
getContentSize: jest.fn(() => 20),
|
|
1850
|
-
}));
|
|
1851
|
-
require('../hooks/useLayoutState').useLayoutState = jest.fn(() => ({
|
|
1852
|
-
splitSizes: [50, 50],
|
|
1853
|
-
splitSize: 50,
|
|
1854
|
-
viewMode: 'desktop',
|
|
1855
|
-
mobileWidth: 375,
|
|
1856
|
-
isFullscreen: false,
|
|
1857
|
-
isResizing: false,
|
|
1858
|
-
updateSplitSizes: jest.fn(),
|
|
1859
|
-
setSplitSize: jest.fn(),
|
|
1860
|
-
setViewMode: jest.fn(),
|
|
1861
|
-
toggleViewMode: jest.fn(),
|
|
1862
|
-
setMobileWidth: jest.fn(),
|
|
1863
|
-
toggleFullscreen: jest.fn(),
|
|
1864
|
-
resetLayout: jest.fn(),
|
|
1865
|
-
setResizingState: jest.fn(),
|
|
1866
|
-
handleResize: jest.fn(),
|
|
1867
|
-
handleKeyboardShortcut: jest.fn(),
|
|
1868
|
-
isMobileView: false,
|
|
1869
|
-
isDesktopView: true,
|
|
1870
|
-
minPaneSize: 20,
|
|
1871
|
-
maxPaneSize: 80,
|
|
1872
|
-
gutterSize: 10,
|
|
1873
|
-
}));
|
|
1874
|
-
|
|
1875
1679
|
render(
|
|
1876
1680
|
<TestWrapper>
|
|
1877
|
-
<
|
|
1681
|
+
<LoadingTestComponent
|
|
1682
|
+
mockContent={{ content: '<p>Test</p>' }}
|
|
1683
|
+
mockLayout={{ splitSizes: [50, 50] }}
|
|
1684
|
+
/>
|
|
1878
1685
|
</TestWrapper>
|
|
1879
1686
|
);
|
|
1880
1687
|
|
|
@@ -1895,7 +1702,7 @@ describe('HTMLEditor', () => {
|
|
|
1895
1702
|
isValidating: false,
|
|
1896
1703
|
getAllIssues: () => [{ message: 'Test error', severity: 'error' }],
|
|
1897
1704
|
isClean: () => false,
|
|
1898
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1705
|
+
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1899
1706
|
});
|
|
1900
1707
|
|
|
1901
1708
|
render(
|
|
@@ -1927,7 +1734,7 @@ describe('HTMLEditor', () => {
|
|
|
1927
1734
|
isValidating: false,
|
|
1928
1735
|
getAllIssues: () => [{ message: 'Test error', severity: 'error' }],
|
|
1929
1736
|
isClean: () => false,
|
|
1930
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1737
|
+
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
1931
1738
|
});
|
|
1932
1739
|
|
|
1933
1740
|
render(
|
|
@@ -1998,811 +1805,5 @@ describe('HTMLEditor', () => {
|
|
|
1998
1805
|
unmount();
|
|
1999
1806
|
});
|
|
2000
1807
|
});
|
|
1808
|
+
});
|
|
2001
1809
|
|
|
2002
|
-
describe('handleContextChange Coverage', () => {
|
|
2003
|
-
it('calls onContextChange when provided instead of making API call', () => {
|
|
2004
|
-
const onContextChange = jest.fn();
|
|
2005
|
-
const globalActions = {
|
|
2006
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2007
|
-
};
|
|
2008
|
-
|
|
2009
|
-
render(
|
|
2010
|
-
<TestWrapper>
|
|
2011
|
-
<HTMLEditor
|
|
2012
|
-
{...defaultProps}
|
|
2013
|
-
onContextChange={onContextChange}
|
|
2014
|
-
globalActions={globalActions}
|
|
2015
|
-
location={{ query: { type: 'embedded' } }}
|
|
2016
|
-
/>
|
|
2017
|
-
</TestWrapper>
|
|
2018
|
-
);
|
|
2019
|
-
|
|
2020
|
-
act(() => {
|
|
2021
|
-
jest.runAllTimers();
|
|
2022
|
-
});
|
|
2023
|
-
|
|
2024
|
-
// Wait for component to render
|
|
2025
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
2026
|
-
if (!codeEditorPane) {
|
|
2027
|
-
// Component might be in loading state, wait a bit more
|
|
2028
|
-
act(() => {
|
|
2029
|
-
jest.runAllTimers();
|
|
2030
|
-
});
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
|
-
// The CodeEditorPane would call onContextChange
|
|
2034
|
-
// We verify that onContextChange is passed and would be called
|
|
2035
|
-
expect(onContextChange).toBeDefined();
|
|
2036
|
-
|
|
2037
|
-
// If onContextChange is provided, globalActions.fetchSchemaForEntity should not be called
|
|
2038
|
-
// This is tested by ensuring onContextChange is used instead
|
|
2039
|
-
});
|
|
2040
|
-
|
|
2041
|
-
it('makes API call when onContextChange is not provided but globalActions is available', () => {
|
|
2042
|
-
const globalActions = {
|
|
2043
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2044
|
-
};
|
|
2045
|
-
|
|
2046
|
-
render(
|
|
2047
|
-
<TestWrapper>
|
|
2048
|
-
<HTMLEditor
|
|
2049
|
-
{...defaultProps}
|
|
2050
|
-
onContextChange={null}
|
|
2051
|
-
globalActions={globalActions}
|
|
2052
|
-
location={{ query: { type: 'embedded' } }}
|
|
2053
|
-
/>
|
|
2054
|
-
</TestWrapper>
|
|
2055
|
-
);
|
|
2056
|
-
|
|
2057
|
-
act(() => {
|
|
2058
|
-
jest.runAllTimers();
|
|
2059
|
-
});
|
|
2060
|
-
|
|
2061
|
-
// Wait for component to render
|
|
2062
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
2063
|
-
if (!toolbar) {
|
|
2064
|
-
act(() => {
|
|
2065
|
-
jest.runAllTimers();
|
|
2066
|
-
});
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
|
-
// The handleContextChange would be called by CodeEditorPane
|
|
2070
|
-
// We verify globalActions is available
|
|
2071
|
-
expect(globalActions.fetchSchemaForEntity).toBeDefined();
|
|
2072
|
-
});
|
|
2073
|
-
|
|
2074
|
-
it('does not make API call when globalActions is not available', () => {
|
|
2075
|
-
render(
|
|
2076
|
-
<TestWrapper>
|
|
2077
|
-
<HTMLEditor
|
|
2078
|
-
{...defaultProps}
|
|
2079
|
-
onContextChange={null}
|
|
2080
|
-
globalActions={null}
|
|
2081
|
-
location={{ query: { type: 'embedded' } }}
|
|
2082
|
-
/>
|
|
2083
|
-
</TestWrapper>
|
|
2084
|
-
);
|
|
2085
|
-
|
|
2086
|
-
act(() => {
|
|
2087
|
-
jest.runAllTimers();
|
|
2088
|
-
});
|
|
2089
|
-
|
|
2090
|
-
// Wait for component to render - might be in loading state
|
|
2091
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
2092
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2093
|
-
|
|
2094
|
-
// Component should render (either loaded or loading)
|
|
2095
|
-
expect(toolbar || loading).toBeTruthy();
|
|
2096
|
-
});
|
|
2097
|
-
|
|
2098
|
-
it('uses SMS layout for INAPP variant in handleContextChange', () => {
|
|
2099
|
-
const globalActions = {
|
|
2100
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2101
|
-
};
|
|
2102
|
-
|
|
2103
|
-
render(
|
|
2104
|
-
<TestWrapper>
|
|
2105
|
-
<HTMLEditor
|
|
2106
|
-
{...defaultProps}
|
|
2107
|
-
variant="inapp"
|
|
2108
|
-
onContextChange={null}
|
|
2109
|
-
globalActions={globalActions}
|
|
2110
|
-
location={{ query: { type: 'embedded' } }}
|
|
2111
|
-
/>
|
|
2112
|
-
</TestWrapper>
|
|
2113
|
-
);
|
|
2114
|
-
|
|
2115
|
-
act(() => {
|
|
2116
|
-
jest.runAllTimers();
|
|
2117
|
-
});
|
|
2118
|
-
|
|
2119
|
-
// Wait for component to render
|
|
2120
|
-
const deviceToggle = screen.queryByTestId('device-toggle');
|
|
2121
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2122
|
-
|
|
2123
|
-
// Component should render (either loaded or loading)
|
|
2124
|
-
expect(deviceToggle || loading).toBeTruthy();
|
|
2125
|
-
});
|
|
2126
|
-
|
|
2127
|
-
it('handles context change with ALL context type', () => {
|
|
2128
|
-
const globalActions = {
|
|
2129
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2130
|
-
};
|
|
2131
|
-
|
|
2132
|
-
render(
|
|
2133
|
-
<TestWrapper>
|
|
2134
|
-
<HTMLEditor
|
|
2135
|
-
{...defaultProps}
|
|
2136
|
-
onContextChange={null}
|
|
2137
|
-
globalActions={globalActions}
|
|
2138
|
-
location={{ query: { type: 'embedded' } }}
|
|
2139
|
-
/>
|
|
2140
|
-
</TestWrapper>
|
|
2141
|
-
);
|
|
2142
|
-
|
|
2143
|
-
act(() => {
|
|
2144
|
-
jest.runAllTimers();
|
|
2145
|
-
});
|
|
2146
|
-
|
|
2147
|
-
// Component should render
|
|
2148
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
2149
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2150
|
-
expect(toolbar || loading).toBeTruthy();
|
|
2151
|
-
});
|
|
2152
|
-
|
|
2153
|
-
it('handles context change with embedded type', () => {
|
|
2154
|
-
const globalActions = {
|
|
2155
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2156
|
-
};
|
|
2157
|
-
|
|
2158
|
-
render(
|
|
2159
|
-
<TestWrapper>
|
|
2160
|
-
<HTMLEditor
|
|
2161
|
-
{...defaultProps}
|
|
2162
|
-
onContextChange={null}
|
|
2163
|
-
globalActions={globalActions}
|
|
2164
|
-
location={{ query: { type: 'embedded', module: 'test' } }}
|
|
2165
|
-
/>
|
|
2166
|
-
</TestWrapper>
|
|
2167
|
-
);
|
|
2168
|
-
|
|
2169
|
-
act(() => {
|
|
2170
|
-
jest.runAllTimers();
|
|
2171
|
-
});
|
|
2172
|
-
|
|
2173
|
-
// Component should render
|
|
2174
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
2175
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2176
|
-
expect(toolbar || loading).toBeTruthy();
|
|
2177
|
-
});
|
|
2178
|
-
});
|
|
2179
|
-
|
|
2180
|
-
describe('handleLabelInsert Coverage', () => {
|
|
2181
|
-
it('handles label insert when position is null and editor is ready', () => {
|
|
2182
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2183
|
-
|
|
2184
|
-
render(
|
|
2185
|
-
<TestWrapper>
|
|
2186
|
-
<HTMLEditor {...defaultProps} />
|
|
2187
|
-
</TestWrapper>
|
|
2188
|
-
);
|
|
2189
|
-
|
|
2190
|
-
act(() => {
|
|
2191
|
-
jest.runAllTimers();
|
|
2192
|
-
});
|
|
2193
|
-
|
|
2194
|
-
// Wait for component to render
|
|
2195
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2196
|
-
if (insertButton) {
|
|
2197
|
-
fireEvent.click(insertButton);
|
|
2198
|
-
|
|
2199
|
-
// Should attempt to insert via editor ref
|
|
2200
|
-
// The mock editor has insertText method, so it should work
|
|
2201
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2202
|
-
}
|
|
2203
|
-
|
|
2204
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
2205
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2206
|
-
expect(codeEditorPane || loading).toBeTruthy();
|
|
2207
|
-
});
|
|
2208
|
-
|
|
2209
|
-
it('shows warning when editor is not available for label insert', () => {
|
|
2210
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2211
|
-
|
|
2212
|
-
// Mock CodeEditorPane to return null ref
|
|
2213
|
-
jest.doMock('../components/CodeEditorPane', () => {
|
|
2214
|
-
const React = require('react');
|
|
2215
|
-
return React.forwardRef(() => {
|
|
2216
|
-
// Return null ref
|
|
2217
|
-
React.useImperativeHandle(null, () => null);
|
|
2218
|
-
return <div data-testid="code-editor-pane">Editor</div>;
|
|
2219
|
-
});
|
|
2220
|
-
});
|
|
2221
|
-
|
|
2222
|
-
render(
|
|
2223
|
-
<TestWrapper>
|
|
2224
|
-
<HTMLEditor {...defaultProps} />
|
|
2225
|
-
</TestWrapper>
|
|
2226
|
-
);
|
|
2227
|
-
|
|
2228
|
-
act(() => {
|
|
2229
|
-
jest.runAllTimers();
|
|
2230
|
-
});
|
|
2231
|
-
|
|
2232
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2233
|
-
if (insertButton) {
|
|
2234
|
-
fireEvent.click(insertButton);
|
|
2235
|
-
// Should show warning when editor is null
|
|
2236
|
-
expect(CapNotification.warning).toHaveBeenCalled();
|
|
2237
|
-
}
|
|
2238
|
-
});
|
|
2239
|
-
|
|
2240
|
-
it('shows error when editor does not have insertText method', () => {
|
|
2241
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2242
|
-
|
|
2243
|
-
// Mock CodeEditorPane to return editor without insertText
|
|
2244
|
-
jest.doMock('../components/CodeEditorPane', () => {
|
|
2245
|
-
const React = require('react');
|
|
2246
|
-
return React.forwardRef((props, ref) => {
|
|
2247
|
-
React.useImperativeHandle(ref, () => ({
|
|
2248
|
-
focus: jest.fn(),
|
|
2249
|
-
getCursor: jest.fn(() => 0),
|
|
2250
|
-
// No insertText method
|
|
2251
|
-
}));
|
|
2252
|
-
return <div data-testid="code-editor-pane">Editor</div>;
|
|
2253
|
-
});
|
|
2254
|
-
});
|
|
2255
|
-
|
|
2256
|
-
render(
|
|
2257
|
-
<TestWrapper>
|
|
2258
|
-
<HTMLEditor {...defaultProps} />
|
|
2259
|
-
</TestWrapper>
|
|
2260
|
-
);
|
|
2261
|
-
|
|
2262
|
-
act(() => {
|
|
2263
|
-
jest.runAllTimers();
|
|
2264
|
-
});
|
|
2265
|
-
|
|
2266
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2267
|
-
if (insertButton) {
|
|
2268
|
-
fireEvent.click(insertButton);
|
|
2269
|
-
// Should show error when insertText is not available
|
|
2270
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
2271
|
-
}
|
|
2272
|
-
});
|
|
2273
|
-
|
|
2274
|
-
it('handles label insert when position is provided (already inserted)', () => {
|
|
2275
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2276
|
-
|
|
2277
|
-
render(
|
|
2278
|
-
<TestWrapper>
|
|
2279
|
-
<HTMLEditor {...defaultProps} />
|
|
2280
|
-
</TestWrapper>
|
|
2281
|
-
);
|
|
2282
|
-
|
|
2283
|
-
act(() => {
|
|
2284
|
-
jest.runAllTimers();
|
|
2285
|
-
});
|
|
2286
|
-
|
|
2287
|
-
// Simulate label insert with position (already inserted by CodeEditorPane)
|
|
2288
|
-
// This would call handleLabelInsert with a valid position
|
|
2289
|
-
const insertButton = screen.queryByText('Insert Label');
|
|
2290
|
-
if (insertButton) {
|
|
2291
|
-
fireEvent.click(insertButton);
|
|
2292
|
-
// Should show success notification
|
|
2293
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2294
|
-
}
|
|
2295
|
-
});
|
|
2296
|
-
|
|
2297
|
-
it('handles error during label insert', () => {
|
|
2298
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2299
|
-
|
|
2300
|
-
// Mock CodeEditorPane to throw error on insertText
|
|
2301
|
-
jest.doMock('../components/CodeEditorPane', () => {
|
|
2302
|
-
const React = require('react');
|
|
2303
|
-
return React.forwardRef((props, ref) => {
|
|
2304
|
-
React.useImperativeHandle(ref, () => ({
|
|
2305
|
-
insertText: jest.fn(() => {
|
|
2306
|
-
throw new Error('Insert failed');
|
|
2307
|
-
}),
|
|
2308
|
-
focus: jest.fn(),
|
|
2309
|
-
getCursor: jest.fn(() => 0),
|
|
2310
|
-
}));
|
|
2311
|
-
return <div data-testid="code-editor-pane">Editor</div>;
|
|
2312
|
-
});
|
|
2313
|
-
});
|
|
2314
|
-
|
|
2315
|
-
render(
|
|
2316
|
-
<TestWrapper>
|
|
2317
|
-
<HTMLEditor {...defaultProps} />
|
|
2318
|
-
</TestWrapper>
|
|
2319
|
-
);
|
|
2320
|
-
|
|
2321
|
-
act(() => {
|
|
2322
|
-
jest.runAllTimers();
|
|
2323
|
-
});
|
|
2324
|
-
|
|
2325
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2326
|
-
if (insertButton) {
|
|
2327
|
-
fireEvent.click(insertButton);
|
|
2328
|
-
// Should show error notification
|
|
2329
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
2330
|
-
}
|
|
2331
|
-
});
|
|
2332
|
-
});
|
|
2333
|
-
|
|
2334
|
-
describe('handleSave Coverage', () => {
|
|
2335
|
-
it('calls onSave callback when save is triggered', () => {
|
|
2336
|
-
const onSave = jest.fn();
|
|
2337
|
-
|
|
2338
|
-
render(
|
|
2339
|
-
<TestWrapper>
|
|
2340
|
-
<HTMLEditor {...defaultProps} onSave={onSave} />
|
|
2341
|
-
</TestWrapper>
|
|
2342
|
-
);
|
|
2343
|
-
|
|
2344
|
-
act(() => {
|
|
2345
|
-
jest.runAllTimers();
|
|
2346
|
-
});
|
|
2347
|
-
|
|
2348
|
-
const saveButton = screen.queryByText('Save');
|
|
2349
|
-
if (saveButton) {
|
|
2350
|
-
fireEvent.click(saveButton);
|
|
2351
|
-
// onSave should be called
|
|
2352
|
-
expect(onSave).toHaveBeenCalled();
|
|
2353
|
-
} else {
|
|
2354
|
-
// Component might be in loading state
|
|
2355
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2356
|
-
expect(loading).toBeTruthy();
|
|
2357
|
-
}
|
|
2358
|
-
});
|
|
2359
|
-
|
|
2360
|
-
it('shows success notification on save', () => {
|
|
2361
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2362
|
-
const onSave = jest.fn();
|
|
2363
|
-
|
|
2364
|
-
render(
|
|
2365
|
-
<TestWrapper>
|
|
2366
|
-
<HTMLEditor {...defaultProps} onSave={onSave} />
|
|
2367
|
-
</TestWrapper>
|
|
2368
|
-
);
|
|
2369
|
-
|
|
2370
|
-
act(() => {
|
|
2371
|
-
jest.runAllTimers();
|
|
2372
|
-
});
|
|
2373
|
-
|
|
2374
|
-
const saveButton = screen.queryByText('Save');
|
|
2375
|
-
if (saveButton) {
|
|
2376
|
-
fireEvent.click(saveButton);
|
|
2377
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2378
|
-
}
|
|
2379
|
-
});
|
|
2380
|
-
|
|
2381
|
-
it('handles save error gracefully', () => {
|
|
2382
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2383
|
-
const onSave = jest.fn(() => {
|
|
2384
|
-
throw new Error('Save failed');
|
|
2385
|
-
});
|
|
2386
|
-
|
|
2387
|
-
render(
|
|
2388
|
-
<TestWrapper>
|
|
2389
|
-
<HTMLEditor {...defaultProps} onSave={onSave} />
|
|
2390
|
-
</TestWrapper>
|
|
2391
|
-
);
|
|
2392
|
-
|
|
2393
|
-
act(() => {
|
|
2394
|
-
jest.runAllTimers();
|
|
2395
|
-
});
|
|
2396
|
-
|
|
2397
|
-
const saveButton = screen.queryByText('Save');
|
|
2398
|
-
if (saveButton) {
|
|
2399
|
-
fireEvent.click(saveButton);
|
|
2400
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
2401
|
-
}
|
|
2402
|
-
});
|
|
2403
|
-
});
|
|
2404
|
-
|
|
2405
|
-
describe('handleValidationErrorClick Coverage', () => {
|
|
2406
|
-
it('navigates to error line when editor has navigateToLine method', () => {
|
|
2407
|
-
mockUseValidationImpl.mockReturnValueOnce({
|
|
2408
|
-
isValidating: false,
|
|
2409
|
-
getAllIssues: () => [{
|
|
2410
|
-
message: 'Test error', line: 5, column: 10, severity: 'error',
|
|
2411
|
-
}],
|
|
2412
|
-
isClean: () => false,
|
|
2413
|
-
summary: { totalErrors: 1, totalWarnings: 0 },
|
|
2414
|
-
});
|
|
2415
|
-
|
|
2416
|
-
render(
|
|
2417
|
-
<TestWrapper>
|
|
2418
|
-
<HTMLEditor {...defaultProps} />
|
|
2419
|
-
</TestWrapper>
|
|
2420
|
-
);
|
|
2421
|
-
|
|
2422
|
-
act(() => {
|
|
2423
|
-
jest.runAllTimers();
|
|
2424
|
-
});
|
|
2425
|
-
|
|
2426
|
-
// Click on error
|
|
2427
|
-
const errorButton = screen.queryByText('Error at Line 5');
|
|
2428
|
-
if (errorButton) {
|
|
2429
|
-
fireEvent.click(errorButton);
|
|
2430
|
-
}
|
|
2431
|
-
|
|
2432
|
-
// Should attempt to navigate to line
|
|
2433
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
2434
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2435
|
-
expect(codeEditorPane || loading).toBeTruthy();
|
|
2436
|
-
});
|
|
2437
|
-
|
|
2438
|
-
it('focuses editor when navigateToLine is not available', () => {
|
|
2439
|
-
mockCodeEditorOptions.includeNavigateToLine = false;
|
|
2440
|
-
|
|
2441
|
-
mockUseValidationImpl.mockReturnValueOnce({
|
|
2442
|
-
isValidating: false,
|
|
2443
|
-
getAllIssues: () => [{
|
|
2444
|
-
message: 'Test error', line: 5, column: 10, severity: 'error',
|
|
2445
|
-
}],
|
|
2446
|
-
isClean: () => false,
|
|
2447
|
-
summary: { totalErrors: 1, totalWarnings: 0 },
|
|
2448
|
-
});
|
|
2449
|
-
|
|
2450
|
-
render(
|
|
2451
|
-
<TestWrapper>
|
|
2452
|
-
<HTMLEditor {...defaultProps} />
|
|
2453
|
-
</TestWrapper>
|
|
2454
|
-
);
|
|
2455
|
-
|
|
2456
|
-
act(() => {
|
|
2457
|
-
jest.runAllTimers();
|
|
2458
|
-
});
|
|
2459
|
-
|
|
2460
|
-
// Component should render
|
|
2461
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
2462
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2463
|
-
expect(codeEditorPane || loading).toBeTruthy();
|
|
2464
|
-
});
|
|
2465
|
-
});
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
describe('Additional Coverage Tests', () => {
|
|
2469
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2470
|
-
|
|
2471
|
-
beforeEach(() => {
|
|
2472
|
-
// Reset options to default
|
|
2473
|
-
mockCodeEditorOptions.includeInsertText = true;
|
|
2474
|
-
mockCodeEditorOptions.insertTextThrows = false;
|
|
2475
|
-
mockCodeEditorOptions.setRef = true;
|
|
2476
|
-
mockCodeEditorOptions.navigateToLineThrows = false;
|
|
2477
|
-
mockCodeEditorOptions.includeNavigateToLine = true;
|
|
2478
|
-
|
|
2479
|
-
// Clear specific mocks instead of all to avoid breaking other mocks
|
|
2480
|
-
CapNotification.warning.mockClear();
|
|
2481
|
-
CapNotification.error.mockClear();
|
|
2482
|
-
CapNotification.success.mockClear();
|
|
2483
|
-
|
|
2484
|
-
// Restore hooks that might have been corrupted by Loading State Coverage tests
|
|
2485
|
-
// This is necessary because Loading State Coverage tests modify the require cache
|
|
2486
|
-
// and do not restore the original mocks
|
|
2487
|
-
require('../hooks/useEditorContent').useEditorContent = () => ({
|
|
2488
|
-
content: '<p>Test content</p>',
|
|
2489
|
-
updateContent: jest.fn(),
|
|
2490
|
-
saveContent: jest.fn(),
|
|
2491
|
-
markAsSaved: jest.fn(),
|
|
2492
|
-
isLoading: false,
|
|
2493
|
-
isDirty: false,
|
|
2494
|
-
hasContent: true,
|
|
2495
|
-
getContentSize: jest.fn(() => 20),
|
|
2496
|
-
});
|
|
2497
|
-
|
|
2498
|
-
require('../hooks/useInAppContent').useInAppContent = () => ({
|
|
2499
|
-
content: '<p>Android content</p>',
|
|
2500
|
-
deviceContent: {
|
|
2501
|
-
android: '<p>Android content</p>',
|
|
2502
|
-
ios: '<p>iOS content</p>',
|
|
2503
|
-
},
|
|
2504
|
-
activeDevice: 'android',
|
|
2505
|
-
keepContentSame: false,
|
|
2506
|
-
updateContent: jest.fn(),
|
|
2507
|
-
saveContent: jest.fn(),
|
|
2508
|
-
markAsSaved: jest.fn(),
|
|
2509
|
-
switchDevice: jest.fn(),
|
|
2510
|
-
toggleContentSync: jest.fn(),
|
|
2511
|
-
getDeviceContent: (device) => `<p>${device} content</p>`,
|
|
2512
|
-
setDeviceContent: jest.fn(),
|
|
2513
|
-
getContentSize: () => 20,
|
|
2514
|
-
isLoading: false,
|
|
2515
|
-
isDirty: false,
|
|
2516
|
-
hasContent: true,
|
|
2517
|
-
});
|
|
2518
|
-
|
|
2519
|
-
require('../hooks/useLayoutState').useLayoutState = () => ({
|
|
2520
|
-
splitSizes: [50, 50],
|
|
2521
|
-
splitSize: 50,
|
|
2522
|
-
viewMode: 'desktop',
|
|
2523
|
-
mobileWidth: 375,
|
|
2524
|
-
isFullscreen: false,
|
|
2525
|
-
isResizing: false,
|
|
2526
|
-
updateSplitSizes: jest.fn(),
|
|
2527
|
-
setSplitSize: jest.fn(),
|
|
2528
|
-
setViewMode: jest.fn(),
|
|
2529
|
-
toggleViewMode: jest.fn(),
|
|
2530
|
-
setMobileWidth: jest.fn(),
|
|
2531
|
-
toggleFullscreen: jest.fn(),
|
|
2532
|
-
resetLayout: jest.fn(),
|
|
2533
|
-
setResizingState: jest.fn(),
|
|
2534
|
-
handleResize: jest.fn(),
|
|
2535
|
-
handleKeyboardShortcut: jest.fn(),
|
|
2536
|
-
isMobileView: false,
|
|
2537
|
-
isDesktopView: true,
|
|
2538
|
-
minPaneSize: 20,
|
|
2539
|
-
maxPaneSize: 80,
|
|
2540
|
-
gutterSize: 10,
|
|
2541
|
-
});
|
|
2542
|
-
});
|
|
2543
|
-
|
|
2544
|
-
describe('handleContextChange', () => {
|
|
2545
|
-
it('calls onContextChange prop when provided', () => {
|
|
2546
|
-
const onContextChange = jest.fn();
|
|
2547
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2548
|
-
|
|
2549
|
-
render(
|
|
2550
|
-
<TestWrapper>
|
|
2551
|
-
<HTMLEditor
|
|
2552
|
-
{...defaultProps}
|
|
2553
|
-
onContextChange={onContextChange}
|
|
2554
|
-
globalActions={globalActions}
|
|
2555
|
-
/>
|
|
2556
|
-
</TestWrapper>
|
|
2557
|
-
);
|
|
2558
|
-
|
|
2559
|
-
act(() => {
|
|
2560
|
-
jest.runAllTimers();
|
|
2561
|
-
});
|
|
2562
|
-
|
|
2563
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2564
|
-
|
|
2565
|
-
expect(onContextChange).toHaveBeenCalledWith('test-context');
|
|
2566
|
-
expect(globalActions.fetchSchemaForEntity).not.toHaveBeenCalled();
|
|
2567
|
-
});
|
|
2568
|
-
|
|
2569
|
-
it('calls globalActions.fetchSchemaForEntity when onContextChange is NOT provided', () => {
|
|
2570
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2571
|
-
const location = { query: { type: 'embedded' } };
|
|
2572
|
-
|
|
2573
|
-
render(
|
|
2574
|
-
<TestWrapper>
|
|
2575
|
-
<HTMLEditor
|
|
2576
|
-
{...defaultProps}
|
|
2577
|
-
globalActions={globalActions}
|
|
2578
|
-
location={location}
|
|
2579
|
-
variant="email"
|
|
2580
|
-
/>
|
|
2581
|
-
</TestWrapper>
|
|
2582
|
-
);
|
|
2583
|
-
|
|
2584
|
-
act(() => {
|
|
2585
|
-
jest.runAllTimers();
|
|
2586
|
-
});
|
|
2587
|
-
|
|
2588
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2589
|
-
|
|
2590
|
-
expect(globalActions.fetchSchemaForEntity).toHaveBeenCalledWith({
|
|
2591
|
-
layout: 'EMAIL',
|
|
2592
|
-
type: 'TAG',
|
|
2593
|
-
context: 'test-context',
|
|
2594
|
-
embedded: 'embedded',
|
|
2595
|
-
});
|
|
2596
|
-
});
|
|
2597
|
-
|
|
2598
|
-
it('handles INAPP variant in handleContextChange', () => {
|
|
2599
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2600
|
-
const location = { query: { type: 'full' } };
|
|
2601
|
-
|
|
2602
|
-
render(
|
|
2603
|
-
<TestWrapper>
|
|
2604
|
-
<HTMLEditor
|
|
2605
|
-
{...defaultProps}
|
|
2606
|
-
globalActions={globalActions}
|
|
2607
|
-
location={location}
|
|
2608
|
-
variant="inapp"
|
|
2609
|
-
/>
|
|
2610
|
-
</TestWrapper>
|
|
2611
|
-
);
|
|
2612
|
-
|
|
2613
|
-
act(() => {
|
|
2614
|
-
jest.runAllTimers();
|
|
2615
|
-
});
|
|
2616
|
-
|
|
2617
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2618
|
-
|
|
2619
|
-
expect(globalActions.fetchSchemaForEntity).toHaveBeenCalledWith({
|
|
2620
|
-
layout: 'SMS', // INAPP uses SMS layout
|
|
2621
|
-
type: 'TAG',
|
|
2622
|
-
context: 'test-context',
|
|
2623
|
-
embedded: 'full',
|
|
2624
|
-
});
|
|
2625
|
-
});
|
|
2626
|
-
|
|
2627
|
-
it('handles missing globalActions or location', () => {
|
|
2628
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2629
|
-
|
|
2630
|
-
// Case 1: No globalActions
|
|
2631
|
-
const { unmount } = render(
|
|
2632
|
-
<TestWrapper>
|
|
2633
|
-
<HTMLEditor
|
|
2634
|
-
{...defaultProps}
|
|
2635
|
-
globalActions={null}
|
|
2636
|
-
location={{}}
|
|
2637
|
-
/>
|
|
2638
|
-
</TestWrapper>
|
|
2639
|
-
);
|
|
2640
|
-
|
|
2641
|
-
act(() => {
|
|
2642
|
-
jest.runAllTimers();
|
|
2643
|
-
});
|
|
2644
|
-
|
|
2645
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2646
|
-
expect(globalActions.fetchSchemaForEntity).not.toHaveBeenCalled();
|
|
2647
|
-
unmount();
|
|
2648
|
-
|
|
2649
|
-
// Case 2: No location
|
|
2650
|
-
render(
|
|
2651
|
-
<TestWrapper>
|
|
2652
|
-
<HTMLEditor
|
|
2653
|
-
{...defaultProps}
|
|
2654
|
-
globalActions={globalActions}
|
|
2655
|
-
location={null}
|
|
2656
|
-
/>
|
|
2657
|
-
</TestWrapper>
|
|
2658
|
-
);
|
|
2659
|
-
|
|
2660
|
-
act(() => {
|
|
2661
|
-
jest.runAllTimers();
|
|
2662
|
-
});
|
|
2663
|
-
|
|
2664
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2665
|
-
expect(globalActions.fetchSchemaForEntity).not.toHaveBeenCalled();
|
|
2666
|
-
});
|
|
2667
|
-
});
|
|
2668
|
-
|
|
2669
|
-
describe('handleLabelInsert', () => {
|
|
2670
|
-
it('shows warning when editor is not ready (position null, no editor)', () => {
|
|
2671
|
-
mockCodeEditorOptions.setRef = false;
|
|
2672
|
-
|
|
2673
|
-
render(
|
|
2674
|
-
<TestWrapper>
|
|
2675
|
-
<HTMLEditor {...defaultProps} />
|
|
2676
|
-
</TestWrapper>
|
|
2677
|
-
);
|
|
2678
|
-
|
|
2679
|
-
act(() => {
|
|
2680
|
-
jest.runAllTimers();
|
|
2681
|
-
});
|
|
2682
|
-
|
|
2683
|
-
// Click the button that passes null position
|
|
2684
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2685
|
-
fireEvent.click(insertButton);
|
|
2686
|
-
|
|
2687
|
-
expect(CapNotification.warning).toHaveBeenCalledWith(
|
|
2688
|
-
expect.objectContaining({
|
|
2689
|
-
message: 'Failed to insert label',
|
|
2690
|
-
description: 'Editor is not ready. Please try again.',
|
|
2691
|
-
})
|
|
2692
|
-
);
|
|
2693
|
-
});
|
|
2694
|
-
|
|
2695
|
-
it('shows error when editor method insertText is not available', () => {
|
|
2696
|
-
mockCodeEditorOptions.includeInsertText = false;
|
|
2697
|
-
|
|
2698
|
-
render(
|
|
2699
|
-
<TestWrapper>
|
|
2700
|
-
<HTMLEditor {...defaultProps} />
|
|
2701
|
-
</TestWrapper>
|
|
2702
|
-
);
|
|
2703
|
-
|
|
2704
|
-
act(() => {
|
|
2705
|
-
jest.runAllTimers();
|
|
2706
|
-
});
|
|
2707
|
-
|
|
2708
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2709
|
-
fireEvent.click(insertButton);
|
|
2710
|
-
|
|
2711
|
-
// Should show error when method is missing
|
|
2712
|
-
expect(CapNotification.error).toHaveBeenCalledWith(
|
|
2713
|
-
expect.objectContaining({
|
|
2714
|
-
message: 'Failed to insert label',
|
|
2715
|
-
})
|
|
2716
|
-
);
|
|
2717
|
-
});
|
|
2718
|
-
|
|
2719
|
-
it('successfully inserts label when position is null', () => {
|
|
2720
|
-
mockCodeEditorOptions.includeInsertText = true;
|
|
2721
|
-
|
|
2722
|
-
render(
|
|
2723
|
-
<TestWrapper>
|
|
2724
|
-
<HTMLEditor {...defaultProps} />
|
|
2725
|
-
</TestWrapper>
|
|
2726
|
-
);
|
|
2727
|
-
|
|
2728
|
-
act(() => {
|
|
2729
|
-
jest.runAllTimers();
|
|
2730
|
-
});
|
|
2731
|
-
|
|
2732
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2733
|
-
fireEvent.click(insertButton);
|
|
2734
|
-
|
|
2735
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2736
|
-
});
|
|
2737
|
-
|
|
2738
|
-
it('shows error when insertText throws', () => {
|
|
2739
|
-
mockCodeEditorOptions.includeInsertText = true;
|
|
2740
|
-
mockCodeEditorOptions.insertTextThrows = true;
|
|
2741
|
-
|
|
2742
|
-
render(
|
|
2743
|
-
<TestWrapper>
|
|
2744
|
-
<HTMLEditor {...defaultProps} />
|
|
2745
|
-
</TestWrapper>
|
|
2746
|
-
);
|
|
2747
|
-
|
|
2748
|
-
act(() => {
|
|
2749
|
-
jest.runAllTimers();
|
|
2750
|
-
});
|
|
2751
|
-
|
|
2752
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2753
|
-
fireEvent.click(insertButton);
|
|
2754
|
-
|
|
2755
|
-
expect(CapNotification.error).toHaveBeenCalledWith(expect.objectContaining({
|
|
2756
|
-
description: 'Insert failed',
|
|
2757
|
-
}));
|
|
2758
|
-
});
|
|
2759
|
-
|
|
2760
|
-
it('shows success notification when position is provided (handled by CodeEditorPane)', () => {
|
|
2761
|
-
render(
|
|
2762
|
-
<TestWrapper>
|
|
2763
|
-
<HTMLEditor {...defaultProps} />
|
|
2764
|
-
</TestWrapper>
|
|
2765
|
-
);
|
|
2766
|
-
|
|
2767
|
-
act(() => {
|
|
2768
|
-
jest.runAllTimers();
|
|
2769
|
-
});
|
|
2770
|
-
|
|
2771
|
-
// Click the button that passes a position
|
|
2772
|
-
const insertButton = screen.getByText('Insert Label');
|
|
2773
|
-
fireEvent.click(insertButton);
|
|
2774
|
-
|
|
2775
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2776
|
-
});
|
|
2777
|
-
});
|
|
2778
|
-
|
|
2779
|
-
describe('handleValidationErrorClick', () => {
|
|
2780
|
-
it('handles error when navigateToLine throws', () => {
|
|
2781
|
-
mockCodeEditorOptions.navigateToLineThrows = true;
|
|
2782
|
-
|
|
2783
|
-
mockUseValidationImpl.mockReturnValueOnce({
|
|
2784
|
-
isValidating: false,
|
|
2785
|
-
getAllIssues: () => [{
|
|
2786
|
-
message: 'Test error', line: 5, column: 10, severity: 'error',
|
|
2787
|
-
}],
|
|
2788
|
-
isClean: () => false,
|
|
2789
|
-
summary: { totalErrors: 1, totalWarnings: 0 },
|
|
2790
|
-
});
|
|
2791
|
-
|
|
2792
|
-
render(
|
|
2793
|
-
<TestWrapper>
|
|
2794
|
-
<HTMLEditor {...defaultProps} />
|
|
2795
|
-
</TestWrapper>
|
|
2796
|
-
);
|
|
2797
|
-
|
|
2798
|
-
act(() => {
|
|
2799
|
-
jest.runAllTimers();
|
|
2800
|
-
});
|
|
2801
|
-
|
|
2802
|
-
// Click error button
|
|
2803
|
-
const errorButton = screen.getByText('Error at Line 5');
|
|
2804
|
-
fireEvent.click(errorButton);
|
|
2805
|
-
});
|
|
2806
|
-
});
|
|
2807
|
-
});
|
|
2808
|
-
});
|