@capillarytech/creatives-library 8.0.236-alpha.7 → 8.0.236
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 +1 -1
- package/initialReducer.js +0 -2
- package/package.json +1 -1
- package/services/api.js +0 -5
- package/services/tests/api.test.js +0 -18
- package/utils/common.js +2 -1
- package/utils/commonUtils.js +1 -14
- package/utils/tests/commonUtil.test.js +0 -224
- package/utils/transformTemplateConfig.js +10 -0
- package/v2Components/CapDeviceContent/index.js +56 -61
- package/v2Components/CapTagList/index.js +0 -4
- package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
- package/v2Components/HtmlEditor/HTMLEditor.js +83 -235
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +19 -932
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +12 -17
- package/v2Components/HtmlEditor/_htmlEditor.scss +4 -2
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -2
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +131 -105
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- 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/constants.js +20 -29
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +148 -130
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -85
- 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/v2Containers/BeeEditor/index.js +80 -82
- package/v2Containers/CreativesContainer/SlideBoxContent.js +34 -69
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -2
- package/v2Containers/CreativesContainer/constants.js +0 -1
- package/v2Containers/CreativesContainer/index.js +32 -92
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +12 -4
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -15
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
- package/v2Containers/InApp/actions.js +0 -7
- package/v2Containers/InApp/constants.js +4 -20
- package/v2Containers/InApp/index.js +386 -984
- 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 +0 -3
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -2
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -9
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -4
- package/v2Containers/TagList/index.js +1 -65
- package/v2Containers/Templates/_templates.scss +1 -60
- package/v2Containers/Templates/index.js +5 -99
- package/v2Containers/Templates/messages.js +0 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -35
- 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/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 -1115
- package/v2Containers/InappAdvance/index.scss +0 -10
- package/v2Containers/InappAdvance/tests/index.test.js +0 -448
|
@@ -10,32 +10,22 @@ import '@testing-library/jest-dom';
|
|
|
10
10
|
import { IntlProvider } from 'react-intl';
|
|
11
11
|
import HTMLEditor from '../HTMLEditor';
|
|
12
12
|
|
|
13
|
-
// Options to control CodeEditorPane mock behavior
|
|
14
|
-
const mockCodeEditorOptions = {
|
|
15
|
-
includeInsertText: true,
|
|
16
|
-
insertTextThrows: false,
|
|
17
|
-
setRef: true,
|
|
18
|
-
navigateToLineThrows: false,
|
|
19
|
-
includeNavigateToLine: true,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
|
|
23
13
|
// Mock useLayoutEffect to behave like useEffect in tests
|
|
24
14
|
React.useLayoutEffect = React.useEffect;
|
|
25
15
|
|
|
26
16
|
// Mock browser APIs
|
|
27
17
|
global.IntersectionObserver = class IntersectionObserver {
|
|
28
|
-
constructor() {
|
|
29
|
-
disconnect() {
|
|
30
|
-
observe() {
|
|
31
|
-
unobserve() {
|
|
18
|
+
constructor() {}
|
|
19
|
+
disconnect() {}
|
|
20
|
+
observe() {}
|
|
21
|
+
unobserve() {}
|
|
32
22
|
};
|
|
33
23
|
|
|
34
24
|
global.ResizeObserver = class ResizeObserver {
|
|
35
|
-
constructor() {
|
|
36
|
-
disconnect() {
|
|
37
|
-
observe() {
|
|
38
|
-
unobserve() {
|
|
25
|
+
constructor() {}
|
|
26
|
+
disconnect() {}
|
|
27
|
+
observe() {}
|
|
28
|
+
unobserve() {}
|
|
39
29
|
};
|
|
40
30
|
|
|
41
31
|
// Setup window.matchMedia mock
|
|
@@ -110,9 +100,6 @@ jest.mock('../components/EditorToolbar', () => {
|
|
|
110
100
|
<button onClick={() => props.onLabelInsert && props.onLabelInsert('test-label', 10)}>
|
|
111
101
|
Insert Label
|
|
112
102
|
</button>
|
|
113
|
-
<button onClick={() => props.onLabelInsert && props.onLabelInsert('test-label', null)}>
|
|
114
|
-
Insert Label (Null Position)
|
|
115
|
-
</button>
|
|
116
103
|
<button onClick={() => props.onSave && props.onSave()}>
|
|
117
104
|
Save
|
|
118
105
|
</button>
|
|
@@ -142,42 +129,19 @@ jest.mock('../components/SplitContainer', () => {
|
|
|
142
129
|
};
|
|
143
130
|
});
|
|
144
131
|
|
|
145
|
-
|
|
146
132
|
jest.mock('../components/CodeEditorPane', () => {
|
|
147
133
|
const React = require('react');
|
|
148
134
|
return React.forwardRef(function MockCodeEditorPane(props, ref) {
|
|
149
135
|
const [value, setValue] = React.useState('');
|
|
150
136
|
|
|
151
|
-
React.useImperativeHandle(ref, () => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
getValue: jest.fn(() => value),
|
|
160
|
-
setValue: jest.fn((newValue) => setValue(newValue)),
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
if (mockCodeEditorOptions.includeNavigateToLine) {
|
|
164
|
-
methods.navigateToLine = jest.fn(() => {
|
|
165
|
-
if (mockCodeEditorOptions.navigateToLineThrows) {
|
|
166
|
-
throw new Error('Navigation failed');
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (mockCodeEditorOptions.includeInsertText) {
|
|
172
|
-
methods.insertText = jest.fn(() => {
|
|
173
|
-
if (mockCodeEditorOptions.insertTextThrows) {
|
|
174
|
-
throw new Error('Insert failed');
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return methods;
|
|
180
|
-
});
|
|
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
|
+
}));
|
|
181
145
|
|
|
182
146
|
return (
|
|
183
147
|
<div data-testid="code-editor-pane">
|
|
@@ -191,12 +155,6 @@ jest.mock('../components/CodeEditorPane', () => {
|
|
|
191
155
|
}}
|
|
192
156
|
data-testid="editor-textarea"
|
|
193
157
|
/>
|
|
194
|
-
<button
|
|
195
|
-
onClick={() => props.onContextChange && props.onContextChange('test-context')}
|
|
196
|
-
data-testid="trigger-context-change"
|
|
197
|
-
>
|
|
198
|
-
Trigger Context Change
|
|
199
|
-
</button>
|
|
200
158
|
</div>
|
|
201
159
|
);
|
|
202
160
|
});
|
|
@@ -515,40 +473,6 @@ describe('HTMLEditor', () => {
|
|
|
515
473
|
expect(screen.getByTestId('device-toggle')).toBeInTheDocument();
|
|
516
474
|
});
|
|
517
475
|
|
|
518
|
-
it('converts string initialContent to device-specific format for inapp variant', () => {
|
|
519
|
-
// This test covers lines 104-109 in HTMLEditor.js
|
|
520
|
-
const mockUseInAppContent = require('../hooks/useInAppContent').useInAppContent;
|
|
521
|
-
const originalUseInAppContent = jest.requireActual('../hooks/useInAppContent').useInAppContent;
|
|
522
|
-
|
|
523
|
-
let capturedInitialContent = null;
|
|
524
|
-
jest.spyOn(require('../hooks/useInAppContent'), 'useInAppContent').mockImplementation((initialContent) => {
|
|
525
|
-
capturedInitialContent = initialContent;
|
|
526
|
-
return originalUseInAppContent(initialContent, {});
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
render(
|
|
530
|
-
<TestWrapper>
|
|
531
|
-
<HTMLEditor
|
|
532
|
-
{...defaultProps}
|
|
533
|
-
variant="inapp"
|
|
534
|
-
initialContent="<p>String content</p>"
|
|
535
|
-
/>
|
|
536
|
-
</TestWrapper>
|
|
537
|
-
);
|
|
538
|
-
|
|
539
|
-
act(() => {
|
|
540
|
-
jest.runAllTimers();
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
// Verify that string content was converted to device-specific format
|
|
544
|
-
expect(capturedInitialContent).toEqual({
|
|
545
|
-
android: '<p>String content</p>',
|
|
546
|
-
ios: '<p>String content</p>'
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
jest.restoreAllMocks();
|
|
550
|
-
});
|
|
551
|
-
|
|
552
476
|
it('handles object initialContent for inapp variant', () => {
|
|
553
477
|
const deviceContent = {
|
|
554
478
|
android: '<p>Android content</p>',
|
|
@@ -572,42 +496,6 @@ describe('HTMLEditor', () => {
|
|
|
572
496
|
expect(screen.getByTestId('device-toggle')).toBeInTheDocument();
|
|
573
497
|
});
|
|
574
498
|
|
|
575
|
-
it('uses provided device-specific content for inapp variant', () => {
|
|
576
|
-
// This test covers lines 110-113 in HTMLEditor.js
|
|
577
|
-
const deviceContent = {
|
|
578
|
-
android: '<p>Android content</p>',
|
|
579
|
-
ios: '<p>iOS content</p>'
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
const mockUseInAppContent = require('../hooks/useInAppContent').useInAppContent;
|
|
583
|
-
const originalUseInAppContent = jest.requireActual('../hooks/useInAppContent').useInAppContent;
|
|
584
|
-
|
|
585
|
-
let capturedInitialContent = null;
|
|
586
|
-
jest.spyOn(require('../hooks/useInAppContent'), 'useInAppContent').mockImplementation((initialContent) => {
|
|
587
|
-
capturedInitialContent = initialContent;
|
|
588
|
-
return originalUseInAppContent(initialContent, {});
|
|
589
|
-
});
|
|
590
|
-
|
|
591
|
-
render(
|
|
592
|
-
<TestWrapper>
|
|
593
|
-
<HTMLEditor
|
|
594
|
-
{...defaultProps}
|
|
595
|
-
variant="inapp"
|
|
596
|
-
initialContent={deviceContent}
|
|
597
|
-
/>
|
|
598
|
-
</TestWrapper>
|
|
599
|
-
);
|
|
600
|
-
|
|
601
|
-
act(() => {
|
|
602
|
-
jest.runAllTimers();
|
|
603
|
-
});
|
|
604
|
-
|
|
605
|
-
// Verify that object content was passed as-is
|
|
606
|
-
expect(capturedInitialContent).toEqual(deviceContent);
|
|
607
|
-
|
|
608
|
-
jest.restoreAllMocks();
|
|
609
|
-
});
|
|
610
|
-
|
|
611
499
|
it('handles inapp variant with layoutType', () => {
|
|
612
500
|
render(
|
|
613
501
|
<TestWrapper>
|
|
@@ -969,7 +857,7 @@ describe('HTMLEditor', () => {
|
|
|
969
857
|
describe('Error Handling', () => {
|
|
970
858
|
it('handles missing editorRef gracefully', () => {
|
|
971
859
|
// Mock console.warn to avoid noise in tests
|
|
972
|
-
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {
|
|
860
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
973
861
|
|
|
974
862
|
render(
|
|
975
863
|
<TestWrapper>
|
|
@@ -1438,8 +1326,8 @@ describe('HTMLEditor', () => {
|
|
|
1438
1326
|
<div className="html-editor html-editor--email">
|
|
1439
1327
|
<CustomToolbar
|
|
1440
1328
|
onLabelInsert={handleLabelInsert}
|
|
1441
|
-
onToggleFullscreen={() => {
|
|
1442
|
-
onSave={() => {
|
|
1329
|
+
onToggleFullscreen={() => {}}
|
|
1330
|
+
onSave={() => {}}
|
|
1443
1331
|
/>
|
|
1444
1332
|
<div data-testid="split-container">
|
|
1445
1333
|
<div data-testid="code-editor-pane" ref={editorRef}>
|
|
@@ -1917,806 +1805,5 @@ describe('HTMLEditor', () => {
|
|
|
1917
1805
|
unmount();
|
|
1918
1806
|
});
|
|
1919
1807
|
});
|
|
1920
|
-
|
|
1921
|
-
describe('handleContextChange Coverage', () => {
|
|
1922
|
-
it('calls onContextChange when provided instead of making API call', () => {
|
|
1923
|
-
const onContextChange = jest.fn();
|
|
1924
|
-
const globalActions = {
|
|
1925
|
-
fetchSchemaForEntity: jest.fn(),
|
|
1926
|
-
};
|
|
1927
|
-
|
|
1928
|
-
render(
|
|
1929
|
-
<TestWrapper>
|
|
1930
|
-
<HTMLEditor
|
|
1931
|
-
{...defaultProps}
|
|
1932
|
-
onContextChange={onContextChange}
|
|
1933
|
-
globalActions={globalActions}
|
|
1934
|
-
location={{ query: { type: 'embedded' } }}
|
|
1935
|
-
/>
|
|
1936
|
-
</TestWrapper>
|
|
1937
|
-
);
|
|
1938
|
-
|
|
1939
|
-
act(() => {
|
|
1940
|
-
jest.runAllTimers();
|
|
1941
|
-
});
|
|
1942
|
-
|
|
1943
|
-
// Wait for component to render
|
|
1944
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
1945
|
-
if (!codeEditorPane) {
|
|
1946
|
-
// Component might be in loading state, wait a bit more
|
|
1947
|
-
act(() => {
|
|
1948
|
-
jest.runAllTimers();
|
|
1949
|
-
});
|
|
1950
|
-
}
|
|
1951
|
-
|
|
1952
|
-
// The CodeEditorPane would call onContextChange
|
|
1953
|
-
// We verify that onContextChange is passed and would be called
|
|
1954
|
-
expect(onContextChange).toBeDefined();
|
|
1955
|
-
|
|
1956
|
-
// If onContextChange is provided, globalActions.fetchSchemaForEntity should not be called
|
|
1957
|
-
// This is tested by ensuring onContextChange is used instead
|
|
1958
|
-
});
|
|
1959
|
-
|
|
1960
|
-
it('makes API call when onContextChange is not provided but globalActions is available', () => {
|
|
1961
|
-
const globalActions = {
|
|
1962
|
-
fetchSchemaForEntity: jest.fn(),
|
|
1963
|
-
};
|
|
1964
|
-
|
|
1965
|
-
render(
|
|
1966
|
-
<TestWrapper>
|
|
1967
|
-
<HTMLEditor
|
|
1968
|
-
{...defaultProps}
|
|
1969
|
-
onContextChange={null}
|
|
1970
|
-
globalActions={globalActions}
|
|
1971
|
-
location={{ query: { type: 'embedded' } }}
|
|
1972
|
-
/>
|
|
1973
|
-
</TestWrapper>
|
|
1974
|
-
);
|
|
1975
|
-
|
|
1976
|
-
act(() => {
|
|
1977
|
-
jest.runAllTimers();
|
|
1978
|
-
});
|
|
1979
|
-
|
|
1980
|
-
// Wait for component to render
|
|
1981
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
1982
|
-
if (!toolbar) {
|
|
1983
|
-
act(() => {
|
|
1984
|
-
jest.runAllTimers();
|
|
1985
|
-
});
|
|
1986
|
-
}
|
|
1987
|
-
|
|
1988
|
-
// The handleContextChange would be called by CodeEditorPane
|
|
1989
|
-
// We verify globalActions is available
|
|
1990
|
-
expect(globalActions.fetchSchemaForEntity).toBeDefined();
|
|
1991
|
-
});
|
|
1992
|
-
|
|
1993
|
-
it('does not make API call when globalActions is not available', () => {
|
|
1994
|
-
render(
|
|
1995
|
-
<TestWrapper>
|
|
1996
|
-
<HTMLEditor
|
|
1997
|
-
{...defaultProps}
|
|
1998
|
-
onContextChange={null}
|
|
1999
|
-
globalActions={null}
|
|
2000
|
-
location={{ query: { type: 'embedded' } }}
|
|
2001
|
-
/>
|
|
2002
|
-
</TestWrapper>
|
|
2003
|
-
);
|
|
2004
|
-
|
|
2005
|
-
act(() => {
|
|
2006
|
-
jest.runAllTimers();
|
|
2007
|
-
});
|
|
2008
|
-
|
|
2009
|
-
// Wait for component to render - might be in loading state
|
|
2010
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
2011
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2012
|
-
|
|
2013
|
-
// Component should render (either loaded or loading)
|
|
2014
|
-
expect(toolbar || loading).toBeTruthy();
|
|
2015
|
-
});
|
|
2016
|
-
|
|
2017
|
-
it('uses SMS layout for INAPP variant in handleContextChange', () => {
|
|
2018
|
-
const globalActions = {
|
|
2019
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2020
|
-
};
|
|
2021
|
-
|
|
2022
|
-
render(
|
|
2023
|
-
<TestWrapper>
|
|
2024
|
-
<HTMLEditor
|
|
2025
|
-
{...defaultProps}
|
|
2026
|
-
variant="inapp"
|
|
2027
|
-
onContextChange={null}
|
|
2028
|
-
globalActions={globalActions}
|
|
2029
|
-
location={{ query: { type: 'embedded' } }}
|
|
2030
|
-
/>
|
|
2031
|
-
</TestWrapper>
|
|
2032
|
-
);
|
|
2033
|
-
|
|
2034
|
-
act(() => {
|
|
2035
|
-
jest.runAllTimers();
|
|
2036
|
-
});
|
|
2037
|
-
|
|
2038
|
-
// Wait for component to render
|
|
2039
|
-
const deviceToggle = screen.queryByTestId('device-toggle');
|
|
2040
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2041
|
-
|
|
2042
|
-
// Component should render (either loaded or loading)
|
|
2043
|
-
expect(deviceToggle || loading).toBeTruthy();
|
|
2044
|
-
});
|
|
2045
|
-
|
|
2046
|
-
it('handles context change with ALL context type', () => {
|
|
2047
|
-
const globalActions = {
|
|
2048
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2049
|
-
};
|
|
2050
|
-
|
|
2051
|
-
render(
|
|
2052
|
-
<TestWrapper>
|
|
2053
|
-
<HTMLEditor
|
|
2054
|
-
{...defaultProps}
|
|
2055
|
-
onContextChange={null}
|
|
2056
|
-
globalActions={globalActions}
|
|
2057
|
-
location={{ query: { type: 'embedded' } }}
|
|
2058
|
-
/>
|
|
2059
|
-
</TestWrapper>
|
|
2060
|
-
);
|
|
2061
|
-
|
|
2062
|
-
act(() => {
|
|
2063
|
-
jest.runAllTimers();
|
|
2064
|
-
});
|
|
2065
|
-
|
|
2066
|
-
// Component should render
|
|
2067
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
2068
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2069
|
-
expect(toolbar || loading).toBeTruthy();
|
|
2070
|
-
});
|
|
2071
|
-
|
|
2072
|
-
it('handles context change with embedded type', () => {
|
|
2073
|
-
const globalActions = {
|
|
2074
|
-
fetchSchemaForEntity: jest.fn(),
|
|
2075
|
-
};
|
|
2076
|
-
|
|
2077
|
-
render(
|
|
2078
|
-
<TestWrapper>
|
|
2079
|
-
<HTMLEditor
|
|
2080
|
-
{...defaultProps}
|
|
2081
|
-
onContextChange={null}
|
|
2082
|
-
globalActions={globalActions}
|
|
2083
|
-
location={{ query: { type: 'embedded', module: 'test' } }}
|
|
2084
|
-
/>
|
|
2085
|
-
</TestWrapper>
|
|
2086
|
-
);
|
|
2087
|
-
|
|
2088
|
-
act(() => {
|
|
2089
|
-
jest.runAllTimers();
|
|
2090
|
-
});
|
|
2091
|
-
|
|
2092
|
-
// Component should render
|
|
2093
|
-
const toolbar = screen.queryByTestId('editor-toolbar');
|
|
2094
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2095
|
-
expect(toolbar || loading).toBeTruthy();
|
|
2096
|
-
});
|
|
2097
|
-
});
|
|
2098
|
-
|
|
2099
|
-
describe('handleLabelInsert Coverage', () => {
|
|
2100
|
-
it('handles label insert when position is null and editor is ready', () => {
|
|
2101
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2102
|
-
|
|
2103
|
-
render(
|
|
2104
|
-
<TestWrapper>
|
|
2105
|
-
<HTMLEditor {...defaultProps} />
|
|
2106
|
-
</TestWrapper>
|
|
2107
|
-
);
|
|
2108
|
-
|
|
2109
|
-
act(() => {
|
|
2110
|
-
jest.runAllTimers();
|
|
2111
|
-
});
|
|
2112
|
-
|
|
2113
|
-
// Wait for component to render
|
|
2114
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2115
|
-
if (insertButton) {
|
|
2116
|
-
fireEvent.click(insertButton);
|
|
2117
|
-
|
|
2118
|
-
// Should attempt to insert via editor ref
|
|
2119
|
-
// The mock editor has insertText method, so it should work
|
|
2120
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2121
|
-
}
|
|
2122
|
-
|
|
2123
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
2124
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2125
|
-
expect(codeEditorPane || loading).toBeTruthy();
|
|
2126
|
-
});
|
|
2127
|
-
|
|
2128
|
-
it('shows warning when editor is not available for label insert', () => {
|
|
2129
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2130
|
-
|
|
2131
|
-
// Mock CodeEditorPane to return null ref
|
|
2132
|
-
jest.doMock('../components/CodeEditorPane', () => {
|
|
2133
|
-
const React = require('react');
|
|
2134
|
-
return React.forwardRef(function MockCodeEditorPane() {
|
|
2135
|
-
// Return null ref
|
|
2136
|
-
React.useImperativeHandle(null, () => null);
|
|
2137
|
-
return <div data-testid="code-editor-pane">Editor</div>;
|
|
2138
|
-
});
|
|
2139
|
-
});
|
|
2140
|
-
|
|
2141
|
-
render(
|
|
2142
|
-
<TestWrapper>
|
|
2143
|
-
<HTMLEditor {...defaultProps} />
|
|
2144
|
-
</TestWrapper>
|
|
2145
|
-
);
|
|
2146
|
-
|
|
2147
|
-
act(() => {
|
|
2148
|
-
jest.runAllTimers();
|
|
2149
|
-
});
|
|
2150
|
-
|
|
2151
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2152
|
-
if (insertButton) {
|
|
2153
|
-
fireEvent.click(insertButton);
|
|
2154
|
-
// Should show warning when editor is null
|
|
2155
|
-
expect(CapNotification.warning).toHaveBeenCalled();
|
|
2156
|
-
}
|
|
2157
|
-
});
|
|
2158
|
-
|
|
2159
|
-
it('shows error when editor does not have insertText method', () => {
|
|
2160
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2161
|
-
|
|
2162
|
-
// Mock CodeEditorPane to return editor without insertText
|
|
2163
|
-
jest.doMock('../components/CodeEditorPane', () => {
|
|
2164
|
-
const React = require('react');
|
|
2165
|
-
return React.forwardRef(function MockCodeEditorPane(props, ref) {
|
|
2166
|
-
React.useImperativeHandle(ref, () => ({
|
|
2167
|
-
focus: jest.fn(),
|
|
2168
|
-
getCursor: jest.fn(() => 0),
|
|
2169
|
-
// No insertText method
|
|
2170
|
-
}));
|
|
2171
|
-
return <div data-testid="code-editor-pane">Editor</div>;
|
|
2172
|
-
});
|
|
2173
|
-
});
|
|
2174
|
-
|
|
2175
|
-
render(
|
|
2176
|
-
<TestWrapper>
|
|
2177
|
-
<HTMLEditor {...defaultProps} />
|
|
2178
|
-
</TestWrapper>
|
|
2179
|
-
);
|
|
2180
|
-
|
|
2181
|
-
act(() => {
|
|
2182
|
-
jest.runAllTimers();
|
|
2183
|
-
});
|
|
2184
|
-
|
|
2185
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2186
|
-
if (insertButton) {
|
|
2187
|
-
fireEvent.click(insertButton);
|
|
2188
|
-
// Should show error when insertText is not available
|
|
2189
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
2190
|
-
}
|
|
2191
|
-
});
|
|
2192
|
-
|
|
2193
|
-
it('handles label insert when position is provided (already inserted)', () => {
|
|
2194
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2195
|
-
|
|
2196
|
-
render(
|
|
2197
|
-
<TestWrapper>
|
|
2198
|
-
<HTMLEditor {...defaultProps} />
|
|
2199
|
-
</TestWrapper>
|
|
2200
|
-
);
|
|
2201
|
-
|
|
2202
|
-
act(() => {
|
|
2203
|
-
jest.runAllTimers();
|
|
2204
|
-
});
|
|
2205
|
-
|
|
2206
|
-
// Simulate label insert with position (already inserted by CodeEditorPane)
|
|
2207
|
-
// This would call handleLabelInsert with a valid position
|
|
2208
|
-
const insertButton = screen.queryByText('Insert Label');
|
|
2209
|
-
if (insertButton) {
|
|
2210
|
-
fireEvent.click(insertButton);
|
|
2211
|
-
// Should show success notification
|
|
2212
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2213
|
-
}
|
|
2214
|
-
});
|
|
2215
|
-
|
|
2216
|
-
it('handles error during label insert', () => {
|
|
2217
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2218
|
-
|
|
2219
|
-
// Mock CodeEditorPane to throw error on insertText
|
|
2220
|
-
jest.doMock('../components/CodeEditorPane', () => {
|
|
2221
|
-
const React = require('react');
|
|
2222
|
-
return React.forwardRef(function MockCodeEditorPane(props, ref) {
|
|
2223
|
-
React.useImperativeHandle(ref, () => ({
|
|
2224
|
-
insertText: jest.fn(() => {
|
|
2225
|
-
throw new Error('Insert failed');
|
|
2226
|
-
}),
|
|
2227
|
-
focus: jest.fn(),
|
|
2228
|
-
getCursor: jest.fn(() => 0),
|
|
2229
|
-
}));
|
|
2230
|
-
return <div data-testid="code-editor-pane">Editor</div>;
|
|
2231
|
-
});
|
|
2232
|
-
});
|
|
2233
|
-
|
|
2234
|
-
render(
|
|
2235
|
-
<TestWrapper>
|
|
2236
|
-
<HTMLEditor {...defaultProps} />
|
|
2237
|
-
</TestWrapper>
|
|
2238
|
-
);
|
|
2239
|
-
|
|
2240
|
-
act(() => {
|
|
2241
|
-
jest.runAllTimers();
|
|
2242
|
-
});
|
|
2243
|
-
|
|
2244
|
-
const insertButton = screen.queryByText('Insert Label (Null Position)');
|
|
2245
|
-
if (insertButton) {
|
|
2246
|
-
fireEvent.click(insertButton);
|
|
2247
|
-
// Should show error notification
|
|
2248
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
2249
|
-
}
|
|
2250
|
-
});
|
|
2251
|
-
});
|
|
2252
|
-
|
|
2253
|
-
describe('handleSave Coverage', () => {
|
|
2254
|
-
it('calls onSave callback when save is triggered', () => {
|
|
2255
|
-
const onSave = jest.fn();
|
|
2256
|
-
|
|
2257
|
-
render(
|
|
2258
|
-
<TestWrapper>
|
|
2259
|
-
<HTMLEditor {...defaultProps} onSave={onSave} />
|
|
2260
|
-
</TestWrapper>
|
|
2261
|
-
);
|
|
2262
|
-
|
|
2263
|
-
act(() => {
|
|
2264
|
-
jest.runAllTimers();
|
|
2265
|
-
});
|
|
2266
|
-
|
|
2267
|
-
const saveButton = screen.queryByText('Save');
|
|
2268
|
-
if (saveButton) {
|
|
2269
|
-
fireEvent.click(saveButton);
|
|
2270
|
-
// onSave should be called
|
|
2271
|
-
expect(onSave).toHaveBeenCalled();
|
|
2272
|
-
} else {
|
|
2273
|
-
// Component might be in loading state
|
|
2274
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2275
|
-
expect(loading).toBeTruthy();
|
|
2276
|
-
}
|
|
2277
|
-
});
|
|
2278
|
-
|
|
2279
|
-
it('shows success notification on save', () => {
|
|
2280
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2281
|
-
const onSave = jest.fn();
|
|
2282
|
-
|
|
2283
|
-
render(
|
|
2284
|
-
<TestWrapper>
|
|
2285
|
-
<HTMLEditor {...defaultProps} onSave={onSave} />
|
|
2286
|
-
</TestWrapper>
|
|
2287
|
-
);
|
|
2288
|
-
|
|
2289
|
-
act(() => {
|
|
2290
|
-
jest.runAllTimers();
|
|
2291
|
-
});
|
|
2292
|
-
|
|
2293
|
-
const saveButton = screen.queryByText('Save');
|
|
2294
|
-
if (saveButton) {
|
|
2295
|
-
fireEvent.click(saveButton);
|
|
2296
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2297
|
-
}
|
|
2298
|
-
});
|
|
2299
|
-
|
|
2300
|
-
it('handles save error gracefully', () => {
|
|
2301
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2302
|
-
const onSave = jest.fn(() => {
|
|
2303
|
-
throw new Error('Save failed');
|
|
2304
|
-
});
|
|
2305
|
-
|
|
2306
|
-
render(
|
|
2307
|
-
<TestWrapper>
|
|
2308
|
-
<HTMLEditor {...defaultProps} onSave={onSave} />
|
|
2309
|
-
</TestWrapper>
|
|
2310
|
-
);
|
|
2311
|
-
|
|
2312
|
-
act(() => {
|
|
2313
|
-
jest.runAllTimers();
|
|
2314
|
-
});
|
|
2315
|
-
|
|
2316
|
-
const saveButton = screen.queryByText('Save');
|
|
2317
|
-
if (saveButton) {
|
|
2318
|
-
fireEvent.click(saveButton);
|
|
2319
|
-
expect(CapNotification.error).toHaveBeenCalled();
|
|
2320
|
-
}
|
|
2321
|
-
});
|
|
2322
|
-
});
|
|
2323
|
-
|
|
2324
|
-
describe('handleValidationErrorClick Coverage', () => {
|
|
2325
|
-
it('navigates to error line when editor has navigateToLine method', () => {
|
|
2326
|
-
mockUseValidationImpl.mockReturnValueOnce({
|
|
2327
|
-
isValidating: false,
|
|
2328
|
-
getAllIssues: () => [{ message: 'Test error', line: 5, column: 10, severity: 'error' }],
|
|
2329
|
-
isClean: () => false,
|
|
2330
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
2331
|
-
});
|
|
2332
|
-
|
|
2333
|
-
render(
|
|
2334
|
-
<TestWrapper>
|
|
2335
|
-
<HTMLEditor {...defaultProps} />
|
|
2336
|
-
</TestWrapper>
|
|
2337
|
-
);
|
|
2338
|
-
|
|
2339
|
-
act(() => {
|
|
2340
|
-
jest.runAllTimers();
|
|
2341
|
-
});
|
|
2342
|
-
|
|
2343
|
-
// Click on error
|
|
2344
|
-
const errorButton = screen.queryByText('Error at Line 5');
|
|
2345
|
-
if (errorButton) {
|
|
2346
|
-
fireEvent.click(errorButton);
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
// Should attempt to navigate to line
|
|
2350
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
2351
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2352
|
-
expect(codeEditorPane || loading).toBeTruthy();
|
|
2353
|
-
});
|
|
2354
|
-
|
|
2355
|
-
it('focuses editor when navigateToLine is not available', () => {
|
|
2356
|
-
mockCodeEditorOptions.includeNavigateToLine = false;
|
|
2357
|
-
|
|
2358
|
-
mockUseValidationImpl.mockReturnValueOnce({
|
|
2359
|
-
isValidating: false,
|
|
2360
|
-
getAllIssues: () => [{ message: 'Test error', line: 5, column: 10, severity: 'error' }],
|
|
2361
|
-
isClean: () => false,
|
|
2362
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
2363
|
-
});
|
|
2364
|
-
|
|
2365
|
-
render(
|
|
2366
|
-
<TestWrapper>
|
|
2367
|
-
<HTMLEditor {...defaultProps} />
|
|
2368
|
-
</TestWrapper>
|
|
2369
|
-
);
|
|
2370
|
-
|
|
2371
|
-
act(() => {
|
|
2372
|
-
jest.runAllTimers();
|
|
2373
|
-
});
|
|
2374
|
-
|
|
2375
|
-
// Component should render
|
|
2376
|
-
const codeEditorPane = screen.queryByTestId('code-editor-pane');
|
|
2377
|
-
const loading = screen.queryByText('Initializing HTML Editor...');
|
|
2378
|
-
expect(codeEditorPane || loading).toBeTruthy();
|
|
2379
|
-
});
|
|
2380
|
-
});
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
describe('Additional Coverage Tests', () => {
|
|
2384
|
-
const CapNotification = require('@capillarytech/cap-ui-library/CapNotification');
|
|
2385
|
-
|
|
2386
|
-
beforeEach(() => {
|
|
2387
|
-
// Reset options to default
|
|
2388
|
-
mockCodeEditorOptions.includeInsertText = true;
|
|
2389
|
-
mockCodeEditorOptions.insertTextThrows = false;
|
|
2390
|
-
mockCodeEditorOptions.setRef = true;
|
|
2391
|
-
mockCodeEditorOptions.navigateToLineThrows = false;
|
|
2392
|
-
mockCodeEditorOptions.includeNavigateToLine = true;
|
|
2393
|
-
|
|
2394
|
-
// Clear specific mocks instead of all to avoid breaking other mocks
|
|
2395
|
-
CapNotification.warning.mockClear();
|
|
2396
|
-
CapNotification.error.mockClear();
|
|
2397
|
-
CapNotification.success.mockClear();
|
|
2398
|
-
|
|
2399
|
-
// Restore hooks that might have been corrupted by Loading State Coverage tests
|
|
2400
|
-
// This is necessary because Loading State Coverage tests modify the require cache
|
|
2401
|
-
// and do not restore the original mocks
|
|
2402
|
-
require('../hooks/useEditorContent').useEditorContent = () => ({
|
|
2403
|
-
content: '<p>Test content</p>',
|
|
2404
|
-
updateContent: jest.fn(),
|
|
2405
|
-
saveContent: jest.fn(),
|
|
2406
|
-
markAsSaved: jest.fn(),
|
|
2407
|
-
isLoading: false,
|
|
2408
|
-
isDirty: false,
|
|
2409
|
-
hasContent: true,
|
|
2410
|
-
getContentSize: jest.fn(() => 20)
|
|
2411
|
-
});
|
|
2412
|
-
|
|
2413
|
-
require('../hooks/useInAppContent').useInAppContent = () => ({
|
|
2414
|
-
content: '<p>Android content</p>',
|
|
2415
|
-
deviceContent: {
|
|
2416
|
-
android: '<p>Android content</p>',
|
|
2417
|
-
ios: '<p>iOS content</p>'
|
|
2418
|
-
},
|
|
2419
|
-
activeDevice: 'android',
|
|
2420
|
-
keepContentSame: false,
|
|
2421
|
-
updateContent: jest.fn(),
|
|
2422
|
-
saveContent: jest.fn(),
|
|
2423
|
-
markAsSaved: jest.fn(),
|
|
2424
|
-
switchDevice: jest.fn(),
|
|
2425
|
-
toggleContentSync: jest.fn(),
|
|
2426
|
-
getDeviceContent: (device) => `<p>${device} content</p>`,
|
|
2427
|
-
setDeviceContent: jest.fn(),
|
|
2428
|
-
getContentSize: () => 20,
|
|
2429
|
-
isLoading: false,
|
|
2430
|
-
isDirty: false,
|
|
2431
|
-
hasContent: true
|
|
2432
|
-
});
|
|
2433
|
-
|
|
2434
|
-
require('../hooks/useLayoutState').useLayoutState = () => ({
|
|
2435
|
-
splitSizes: [50, 50],
|
|
2436
|
-
splitSize: 50,
|
|
2437
|
-
viewMode: 'desktop',
|
|
2438
|
-
mobileWidth: 375,
|
|
2439
|
-
isFullscreen: false,
|
|
2440
|
-
isResizing: false,
|
|
2441
|
-
updateSplitSizes: jest.fn(),
|
|
2442
|
-
setSplitSize: jest.fn(),
|
|
2443
|
-
setViewMode: jest.fn(),
|
|
2444
|
-
toggleViewMode: jest.fn(),
|
|
2445
|
-
setMobileWidth: jest.fn(),
|
|
2446
|
-
toggleFullscreen: jest.fn(),
|
|
2447
|
-
resetLayout: jest.fn(),
|
|
2448
|
-
setResizingState: jest.fn(),
|
|
2449
|
-
handleResize: jest.fn(),
|
|
2450
|
-
handleKeyboardShortcut: jest.fn(),
|
|
2451
|
-
isMobileView: false,
|
|
2452
|
-
isDesktopView: true,
|
|
2453
|
-
minPaneSize: 20,
|
|
2454
|
-
maxPaneSize: 80,
|
|
2455
|
-
gutterSize: 10
|
|
2456
|
-
});
|
|
2457
|
-
});
|
|
2458
|
-
|
|
2459
|
-
describe('handleContextChange', () => {
|
|
2460
|
-
it('calls onContextChange prop when provided', () => {
|
|
2461
|
-
const onContextChange = jest.fn();
|
|
2462
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2463
|
-
|
|
2464
|
-
render(
|
|
2465
|
-
<TestWrapper>
|
|
2466
|
-
<HTMLEditor
|
|
2467
|
-
{...defaultProps}
|
|
2468
|
-
onContextChange={onContextChange}
|
|
2469
|
-
globalActions={globalActions}
|
|
2470
|
-
/>
|
|
2471
|
-
</TestWrapper>
|
|
2472
|
-
);
|
|
2473
|
-
|
|
2474
|
-
act(() => {
|
|
2475
|
-
jest.runAllTimers();
|
|
2476
|
-
});
|
|
2477
|
-
|
|
2478
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2479
|
-
|
|
2480
|
-
expect(onContextChange).toHaveBeenCalledWith('test-context');
|
|
2481
|
-
expect(globalActions.fetchSchemaForEntity).not.toHaveBeenCalled();
|
|
2482
|
-
});
|
|
2483
|
-
|
|
2484
|
-
it('calls globalActions.fetchSchemaForEntity when onContextChange is NOT provided', () => {
|
|
2485
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2486
|
-
const location = { query: { type: 'embedded' } };
|
|
2487
|
-
|
|
2488
|
-
render(
|
|
2489
|
-
<TestWrapper>
|
|
2490
|
-
<HTMLEditor
|
|
2491
|
-
{...defaultProps}
|
|
2492
|
-
globalActions={globalActions}
|
|
2493
|
-
location={location}
|
|
2494
|
-
variant="email"
|
|
2495
|
-
/>
|
|
2496
|
-
</TestWrapper>
|
|
2497
|
-
);
|
|
2498
|
-
|
|
2499
|
-
act(() => {
|
|
2500
|
-
jest.runAllTimers();
|
|
2501
|
-
});
|
|
2502
|
-
|
|
2503
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2504
|
-
|
|
2505
|
-
expect(globalActions.fetchSchemaForEntity).toHaveBeenCalledWith({
|
|
2506
|
-
layout: 'EMAIL',
|
|
2507
|
-
type: 'TAG',
|
|
2508
|
-
context: 'test-context',
|
|
2509
|
-
embedded: 'embedded',
|
|
2510
|
-
});
|
|
2511
|
-
});
|
|
2512
|
-
|
|
2513
|
-
it('handles INAPP variant in handleContextChange', () => {
|
|
2514
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2515
|
-
const location = { query: { type: 'full' } };
|
|
2516
|
-
|
|
2517
|
-
render(
|
|
2518
|
-
<TestWrapper>
|
|
2519
|
-
<HTMLEditor
|
|
2520
|
-
{...defaultProps}
|
|
2521
|
-
globalActions={globalActions}
|
|
2522
|
-
location={location}
|
|
2523
|
-
variant="inapp"
|
|
2524
|
-
/>
|
|
2525
|
-
</TestWrapper>
|
|
2526
|
-
);
|
|
2527
|
-
|
|
2528
|
-
act(() => {
|
|
2529
|
-
jest.runAllTimers();
|
|
2530
|
-
});
|
|
2531
|
-
|
|
2532
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2533
|
-
|
|
2534
|
-
expect(globalActions.fetchSchemaForEntity).toHaveBeenCalledWith({
|
|
2535
|
-
layout: 'SMS', // INAPP uses SMS layout
|
|
2536
|
-
type: 'TAG',
|
|
2537
|
-
context: 'test-context',
|
|
2538
|
-
embedded: 'full',
|
|
2539
|
-
});
|
|
2540
|
-
});
|
|
2541
|
-
|
|
2542
|
-
it('handles missing globalActions or location', () => {
|
|
2543
|
-
const globalActions = { fetchSchemaForEntity: jest.fn() };
|
|
2544
|
-
|
|
2545
|
-
// Case 1: No globalActions
|
|
2546
|
-
const { unmount } = render(
|
|
2547
|
-
<TestWrapper>
|
|
2548
|
-
<HTMLEditor
|
|
2549
|
-
{...defaultProps}
|
|
2550
|
-
globalActions={null}
|
|
2551
|
-
location={{}}
|
|
2552
|
-
/>
|
|
2553
|
-
</TestWrapper>
|
|
2554
|
-
);
|
|
2555
|
-
|
|
2556
|
-
act(() => {
|
|
2557
|
-
jest.runAllTimers();
|
|
2558
|
-
});
|
|
2559
|
-
|
|
2560
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2561
|
-
expect(globalActions.fetchSchemaForEntity).not.toHaveBeenCalled();
|
|
2562
|
-
unmount();
|
|
2563
|
-
|
|
2564
|
-
// Case 2: No location
|
|
2565
|
-
render(
|
|
2566
|
-
<TestWrapper>
|
|
2567
|
-
<HTMLEditor
|
|
2568
|
-
{...defaultProps}
|
|
2569
|
-
globalActions={globalActions}
|
|
2570
|
-
location={null}
|
|
2571
|
-
/>
|
|
2572
|
-
</TestWrapper>
|
|
2573
|
-
);
|
|
2574
|
-
|
|
2575
|
-
act(() => {
|
|
2576
|
-
jest.runAllTimers();
|
|
2577
|
-
});
|
|
2578
|
-
|
|
2579
|
-
fireEvent.click(screen.getByTestId('trigger-context-change'));
|
|
2580
|
-
expect(globalActions.fetchSchemaForEntity).not.toHaveBeenCalled();
|
|
2581
|
-
});
|
|
2582
|
-
});
|
|
2583
|
-
|
|
2584
|
-
describe('handleLabelInsert', () => {
|
|
2585
|
-
it('shows warning when editor is not ready (position null, no editor)', () => {
|
|
2586
|
-
mockCodeEditorOptions.setRef = false;
|
|
2587
|
-
|
|
2588
|
-
render(
|
|
2589
|
-
<TestWrapper>
|
|
2590
|
-
<HTMLEditor {...defaultProps} />
|
|
2591
|
-
</TestWrapper>
|
|
2592
|
-
);
|
|
2593
|
-
|
|
2594
|
-
act(() => {
|
|
2595
|
-
jest.runAllTimers();
|
|
2596
|
-
});
|
|
2597
|
-
|
|
2598
|
-
// Click the button that passes null position
|
|
2599
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2600
|
-
fireEvent.click(insertButton);
|
|
2601
|
-
|
|
2602
|
-
expect(CapNotification.warning).toHaveBeenCalledWith(
|
|
2603
|
-
expect.objectContaining({
|
|
2604
|
-
message: 'Failed to insert label',
|
|
2605
|
-
description: 'Editor is not ready. Please try again.',
|
|
2606
|
-
})
|
|
2607
|
-
);
|
|
2608
|
-
});
|
|
2609
|
-
|
|
2610
|
-
it('shows error when editor method insertText is not available', () => {
|
|
2611
|
-
mockCodeEditorOptions.includeInsertText = false;
|
|
2612
|
-
|
|
2613
|
-
render(
|
|
2614
|
-
<TestWrapper>
|
|
2615
|
-
<HTMLEditor {...defaultProps} />
|
|
2616
|
-
</TestWrapper>
|
|
2617
|
-
);
|
|
2618
|
-
|
|
2619
|
-
act(() => {
|
|
2620
|
-
jest.runAllTimers();
|
|
2621
|
-
});
|
|
2622
|
-
|
|
2623
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2624
|
-
fireEvent.click(insertButton);
|
|
2625
|
-
|
|
2626
|
-
// Should show error when method is missing
|
|
2627
|
-
expect(CapNotification.error).toHaveBeenCalledWith(
|
|
2628
|
-
expect.objectContaining({
|
|
2629
|
-
message: 'Failed to insert label',
|
|
2630
|
-
})
|
|
2631
|
-
);
|
|
2632
|
-
});
|
|
2633
|
-
|
|
2634
|
-
it('successfully inserts label when position is null', () => {
|
|
2635
|
-
mockCodeEditorOptions.includeInsertText = true;
|
|
2636
|
-
|
|
2637
|
-
render(
|
|
2638
|
-
<TestWrapper>
|
|
2639
|
-
<HTMLEditor {...defaultProps} />
|
|
2640
|
-
</TestWrapper>
|
|
2641
|
-
);
|
|
2642
|
-
|
|
2643
|
-
act(() => {
|
|
2644
|
-
jest.runAllTimers();
|
|
2645
|
-
});
|
|
2646
|
-
|
|
2647
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2648
|
-
fireEvent.click(insertButton);
|
|
2649
|
-
|
|
2650
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2651
|
-
});
|
|
2652
|
-
|
|
2653
|
-
it('shows error when insertText throws', () => {
|
|
2654
|
-
mockCodeEditorOptions.includeInsertText = true;
|
|
2655
|
-
mockCodeEditorOptions.insertTextThrows = true;
|
|
2656
|
-
|
|
2657
|
-
render(
|
|
2658
|
-
<TestWrapper>
|
|
2659
|
-
<HTMLEditor {...defaultProps} />
|
|
2660
|
-
</TestWrapper>
|
|
2661
|
-
);
|
|
2662
|
-
|
|
2663
|
-
act(() => {
|
|
2664
|
-
jest.runAllTimers();
|
|
2665
|
-
});
|
|
2666
|
-
|
|
2667
|
-
const insertButton = screen.getByText('Insert Label (Null Position)');
|
|
2668
|
-
fireEvent.click(insertButton);
|
|
2669
|
-
|
|
2670
|
-
expect(CapNotification.error).toHaveBeenCalledWith(expect.objectContaining({
|
|
2671
|
-
description: 'Insert failed'
|
|
2672
|
-
}));
|
|
2673
|
-
});
|
|
2674
|
-
|
|
2675
|
-
it('shows success notification when position is provided (handled by CodeEditorPane)', () => {
|
|
2676
|
-
render(
|
|
2677
|
-
<TestWrapper>
|
|
2678
|
-
<HTMLEditor {...defaultProps} />
|
|
2679
|
-
</TestWrapper>
|
|
2680
|
-
);
|
|
2681
|
-
|
|
2682
|
-
act(() => {
|
|
2683
|
-
jest.runAllTimers();
|
|
2684
|
-
});
|
|
2685
|
-
|
|
2686
|
-
// Click the button that passes a position
|
|
2687
|
-
const insertButton = screen.getByText('Insert Label');
|
|
2688
|
-
fireEvent.click(insertButton);
|
|
2689
|
-
|
|
2690
|
-
expect(CapNotification.success).toHaveBeenCalled();
|
|
2691
|
-
});
|
|
2692
|
-
});
|
|
2693
|
-
|
|
2694
|
-
describe('handleValidationErrorClick', () => {
|
|
2695
|
-
it('handles error when navigateToLine throws', () => {
|
|
2696
|
-
mockCodeEditorOptions.navigateToLineThrows = true;
|
|
2697
|
-
|
|
2698
|
-
mockUseValidationImpl.mockReturnValueOnce({
|
|
2699
|
-
isValidating: false,
|
|
2700
|
-
getAllIssues: () => [{ message: 'Test error', line: 5, column: 10, severity: 'error' }],
|
|
2701
|
-
isClean: () => false,
|
|
2702
|
-
summary: { totalErrors: 1, totalWarnings: 0 }
|
|
2703
|
-
});
|
|
2704
|
-
|
|
2705
|
-
render(
|
|
2706
|
-
<TestWrapper>
|
|
2707
|
-
<HTMLEditor {...defaultProps} />
|
|
2708
|
-
</TestWrapper>
|
|
2709
|
-
);
|
|
2710
|
-
|
|
2711
|
-
act(() => {
|
|
2712
|
-
jest.runAllTimers();
|
|
2713
|
-
});
|
|
2714
|
-
|
|
2715
|
-
// Click error button
|
|
2716
|
-
const errorButton = screen.getByText('Error at Line 5');
|
|
2717
|
-
fireEvent.click(errorButton);
|
|
2718
|
-
});
|
|
2719
|
-
});
|
|
2720
|
-
});
|
|
2721
1808
|
});
|
|
2722
1809
|
|