@capillarytech/creatives-library 8.0.271 → 8.0.272
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +2 -1
- package/initialReducer.js +2 -0
- package/package.json +1 -1
- package/services/api.js +10 -0
- package/services/tests/api.test.js +34 -0
- package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +17 -35
- package/tests/integration/TemplateCreation/api-response.js +31 -1
- package/tests/integration/TemplateCreation/msw-handler.js +2 -0
- package/utils/common.js +5 -0
- package/utils/commonUtils.js +28 -5
- package/utils/tests/commonUtil.test.js +224 -0
- package/utils/transformTemplateConfig.js +0 -10
- package/v2Components/CapDeviceContent/index.js +61 -56
- package/v2Components/CapTagList/index.js +6 -1
- package/v2Components/CapTagListWithInput/index.js +5 -1
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
- package/v2Components/ErrorInfoNote/constants.js +1 -0
- package/v2Components/ErrorInfoNote/index.js +402 -72
- package/v2Components/ErrorInfoNote/messages.js +32 -6
- package/v2Components/ErrorInfoNote/style.scss +278 -6
- package/v2Components/FormBuilder/tests/index.test.js +13 -4
- package/v2Components/HtmlEditor/HTMLEditor.js +418 -99
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +870 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1882 -133
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
- package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
- package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +23 -102
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +148 -140
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +9 -1
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +31 -6
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +22 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +7 -10
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +22 -43
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +18 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +36 -31
- package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +46 -34
- package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +6 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +52 -46
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +277 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +295 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
- package/v2Components/HtmlEditor/constants.js +45 -20
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +351 -16
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
- package/v2Components/HtmlEditor/hooks/useValidation.js +213 -56
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +102 -94
- package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +214 -45
- package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +134 -0
- package/v2Components/HtmlEditor/utils/contentSanitizer.js +40 -41
- package/v2Components/HtmlEditor/utils/htmlValidator.js +71 -72
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +158 -124
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
- package/v2Components/HtmlEditor/utils/validationAdapter.js +66 -41
- package/v2Components/HtmlEditor/utils/validationConstants.js +38 -0
- package/v2Components/MobilePushPreviewV2/constants.js +6 -0
- package/v2Components/MobilePushPreviewV2/index.js +33 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +55 -24
- package/v2Components/TemplatePreview/index.js +47 -32
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +1 -0
- package/v2Containers/BeeEditor/index.js +172 -90
- package/v2Containers/BeePopupEditor/_beePopupEditor.scss +14 -0
- package/v2Containers/BeePopupEditor/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +194 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -51
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +156 -13
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -1
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +251 -47
- package/v2Containers/CreativesContainer/messages.js +8 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +11 -2
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +103 -0
- package/v2Containers/Email/actions.js +7 -0
- package/v2Containers/Email/constants.js +5 -1
- package/v2Containers/Email/index.js +234 -29
- package/v2Containers/Email/messages.js +32 -0
- package/v2Containers/Email/reducer.js +12 -1
- package/v2Containers/Email/sagas.js +61 -7
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
- package/v2Containers/Email/tests/reducer.test.js +46 -0
- package/v2Containers/Email/tests/sagas.test.js +320 -29
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1246 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +212 -21
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +2472 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +520 -0
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +627 -79
- package/v2Containers/EmailWrapper/index.js +103 -23
- package/v2Containers/EmailWrapper/messages.js +65 -1
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +955 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +596 -82
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
- package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
- package/v2Containers/InApp/actions.js +7 -0
- package/v2Containers/InApp/constants.js +20 -4
- package/v2Containers/InApp/index.js +802 -360
- package/v2Containers/InApp/index.scss +4 -3
- package/v2Containers/InApp/messages.js +7 -3
- package/v2Containers/InApp/reducer.js +21 -3
- package/v2Containers/InApp/sagas.js +29 -9
- package/v2Containers/InApp/selectors.js +25 -5
- package/v2Containers/InApp/tests/index.test.js +154 -50
- package/v2Containers/InApp/tests/reducer.test.js +34 -0
- package/v2Containers/InApp/tests/sagas.test.js +61 -9
- package/v2Containers/InApp/tests/selectors.test.js +612 -0
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +151 -0
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +23 -0
- package/v2Containers/InAppWrapper/constants.js +16 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
- package/v2Containers/InAppWrapper/index.js +148 -0
- package/v2Containers/InAppWrapper/messages.js +49 -0
- package/v2Containers/InappAdvance/index.js +1099 -0
- package/v2Containers/InappAdvance/index.scss +10 -0
- package/v2Containers/InappAdvance/tests/index.test.js +448 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
- package/v2Containers/TagList/index.js +62 -19
- package/v2Containers/Templates/_templates.scss +60 -1
- package/v2Containers/Templates/index.js +89 -4
- package/v2Containers/Templates/messages.js +4 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +4 -2
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +0 -152
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import {
|
|
8
8
|
validateHTML,
|
|
9
9
|
validateCSS,
|
|
10
|
-
extractAndValidateCSS
|
|
10
|
+
extractAndValidateCSS,
|
|
11
11
|
} from '../htmlValidator';
|
|
12
12
|
|
|
13
13
|
// Mock liquidTemplateSupport module
|
|
@@ -15,8 +15,8 @@ jest.mock('../liquidTemplateSupport', () => ({
|
|
|
15
15
|
validateLiquidHTML: jest.fn(() => ({
|
|
16
16
|
errors: [],
|
|
17
17
|
warnings: [],
|
|
18
|
-
info: []
|
|
19
|
-
}))
|
|
18
|
+
info: [],
|
|
19
|
+
})),
|
|
20
20
|
}));
|
|
21
21
|
|
|
22
22
|
// Mock console.warn to avoid noise in tests
|
|
@@ -80,7 +80,7 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
it('handles very long HTML content', () => {
|
|
83
|
-
const longHtml =
|
|
83
|
+
const longHtml = `<p>${'a'.repeat(50000)}</p>`;
|
|
84
84
|
const result = validateHTML(longHtml);
|
|
85
85
|
|
|
86
86
|
expect(result).toBeDefined();
|
|
@@ -109,24 +109,36 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
109
109
|
const html = '<a href="javascript:alert(1)">Click</a>';
|
|
110
110
|
const result = validateHTML(html);
|
|
111
111
|
|
|
112
|
+
// Unsafe protocols are BLOCKING ERRORS (sanitizer.dangerousProtocolDetected)
|
|
112
113
|
expect(result.errors.length).toBeGreaterThan(0);
|
|
113
114
|
expect(result.isValid).toBe(false);
|
|
115
|
+
// Verify it's the correct rule
|
|
116
|
+
const error = result.errors.find((e) => e.rule === 'sanitizer.dangerousProtocolDetected');
|
|
117
|
+
expect(error).toBeDefined();
|
|
114
118
|
});
|
|
115
119
|
|
|
116
120
|
it('detects potentially unsafe data protocol', () => {
|
|
117
121
|
const html = '<img src="data:image/svg+xml,<svg>...">';
|
|
118
122
|
const result = validateHTML(html);
|
|
119
123
|
|
|
124
|
+
// Unsafe protocols are BLOCKING ERRORS (sanitizer.dangerousProtocolDetected)
|
|
120
125
|
expect(result.errors.length).toBeGreaterThan(0);
|
|
121
126
|
expect(result.isValid).toBe(false);
|
|
127
|
+
// Verify it's the correct rule
|
|
128
|
+
const error = result.errors.find((e) => e.rule === 'sanitizer.dangerousProtocolDetected');
|
|
129
|
+
expect(error).toBeDefined();
|
|
122
130
|
});
|
|
123
131
|
|
|
124
132
|
it('detects potentially unsafe vbscript protocol', () => {
|
|
125
133
|
const html = '<a href="vbscript:msgbox(1)">Click</a>';
|
|
126
134
|
const result = validateHTML(html);
|
|
127
135
|
|
|
136
|
+
// Unsafe protocols are BLOCKING ERRORS (sanitizer.dangerousProtocolDetected)
|
|
128
137
|
expect(result.errors.length).toBeGreaterThan(0);
|
|
129
138
|
expect(result.isValid).toBe(false);
|
|
139
|
+
// Verify it's the correct rule
|
|
140
|
+
const error = result.errors.find((e) => e.rule === 'sanitizer.dangerousProtocolDetected');
|
|
141
|
+
expect(error).toBeDefined();
|
|
130
142
|
});
|
|
131
143
|
|
|
132
144
|
it('handles script tags appropriately', () => {
|
|
@@ -417,7 +429,7 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
417
429
|
});
|
|
418
430
|
|
|
419
431
|
it('handles very long CSS content', () => {
|
|
420
|
-
const longCSS =
|
|
432
|
+
const longCSS = `.long { ${'color: red; '.repeat(1000)}}`;
|
|
421
433
|
const result = validateCSS(longCSS);
|
|
422
434
|
|
|
423
435
|
expect(result).toBeDefined();
|
|
@@ -436,8 +448,10 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
436
448
|
const result = validateCSS(css);
|
|
437
449
|
|
|
438
450
|
expect(result).toBeDefined();
|
|
439
|
-
|
|
440
|
-
expect(result.
|
|
451
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
452
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
453
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
454
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
441
455
|
});
|
|
442
456
|
|
|
443
457
|
it('detects empty rules', () => {
|
|
@@ -448,8 +462,10 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
448
462
|
const result = validateCSS(css);
|
|
449
463
|
|
|
450
464
|
expect(result).toBeDefined();
|
|
451
|
-
|
|
452
|
-
expect(result.
|
|
465
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
466
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
467
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
468
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
453
469
|
});
|
|
454
470
|
});
|
|
455
471
|
});
|
|
@@ -536,8 +552,10 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
536
552
|
const result = extractAndValidateCSS(html);
|
|
537
553
|
|
|
538
554
|
expect(result).toBeDefined();
|
|
539
|
-
|
|
540
|
-
expect(result.
|
|
555
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
556
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
557
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
558
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
541
559
|
});
|
|
542
560
|
});
|
|
543
561
|
|
|
@@ -576,7 +594,7 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
576
594
|
const mockHTMLHint = {
|
|
577
595
|
verify: jest.fn(() => {
|
|
578
596
|
throw new Error('HTMLHint validation failed');
|
|
579
|
-
})
|
|
597
|
+
}),
|
|
580
598
|
};
|
|
581
599
|
|
|
582
600
|
// Temporarily replace HTMLHint
|
|
@@ -585,9 +603,13 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
585
603
|
const html = '<div>Test content</div>';
|
|
586
604
|
const result = validateHTML(html);
|
|
587
605
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
expect(result
|
|
606
|
+
// HTMLHint errors are caught and handled gracefully - result should still be defined
|
|
607
|
+
// When HTMLHint throws, it's caught and a warning is added (not an error)
|
|
608
|
+
expect(result).toBeDefined();
|
|
609
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
610
|
+
// HTMLHint errors are converted to warnings in the catch block
|
|
611
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
612
|
+
expect(result.warnings[0].message).toContain('HTMLHint validation failed');
|
|
591
613
|
|
|
592
614
|
// Restore original HTMLHint
|
|
593
615
|
require('htmlhint').HTMLHint = originalHTMLHint;
|
|
@@ -640,10 +662,9 @@ describe('Enhanced htmlValidator Tests', () => {
|
|
|
640
662
|
});
|
|
641
663
|
|
|
642
664
|
it('falls back to default formatter when custom formatter fails', () => {
|
|
643
|
-
const failingFormatter = jest.fn((key, values) =>
|
|
665
|
+
const failingFormatter = jest.fn((key, values) =>
|
|
644
666
|
// Don't throw error, just return the key as fallback behavior
|
|
645
|
-
|
|
646
|
-
});
|
|
667
|
+
key);
|
|
647
668
|
|
|
648
669
|
const html = '<a href="javascript:alert(1)">Unsafe link</a>';
|
|
649
670
|
const result = validateHTML(html, 'email', failingFormatter);
|
|
@@ -721,8 +742,10 @@ line4`;
|
|
|
721
742
|
const css = '.class { }';
|
|
722
743
|
const result = validateCSS(css);
|
|
723
744
|
|
|
724
|
-
|
|
725
|
-
expect(result.
|
|
745
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
746
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
747
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
748
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
726
749
|
});
|
|
727
750
|
|
|
728
751
|
it('handles multiple consecutive unsafe protocols', () => {
|
|
@@ -755,9 +778,15 @@ line4`;
|
|
|
755
778
|
// Get the mocked module and set it to return specific results
|
|
756
779
|
const { validateLiquidHTML } = require('../liquidTemplateSupport');
|
|
757
780
|
validateLiquidHTML.mockImplementation(() => ({
|
|
758
|
-
errors: [{
|
|
759
|
-
|
|
760
|
-
|
|
781
|
+
errors: [{
|
|
782
|
+
type: 'error', message: 'Liquid error', line: 1, column: 1, rule: 'liquid-test', severity: 'error', source: 'liquid',
|
|
783
|
+
}],
|
|
784
|
+
warnings: [{
|
|
785
|
+
type: 'warning', message: 'Liquid warning', line: 1, column: 1, rule: 'liquid-test', severity: 'warning', source: 'liquid',
|
|
786
|
+
}],
|
|
787
|
+
info: [{
|
|
788
|
+
type: 'info', message: 'Liquid info', line: 1, column: 1, rule: 'liquid-test', severity: 'info', source: 'liquid',
|
|
789
|
+
}],
|
|
761
790
|
}));
|
|
762
791
|
|
|
763
792
|
const html = '<div>{{ liquid.template }}</div>';
|
|
@@ -790,7 +819,9 @@ line4`;
|
|
|
790
819
|
// Get the mocked module and set it to return only some result types
|
|
791
820
|
const { validateLiquidHTML } = require('../liquidTemplateSupport');
|
|
792
821
|
validateLiquidHTML.mockImplementation(() => ({
|
|
793
|
-
errors: [{
|
|
822
|
+
errors: [{
|
|
823
|
+
type: 'error', message: 'Liquid error', line: 1, column: 1, rule: 'liquid-test', severity: 'error', source: 'liquid',
|
|
824
|
+
}],
|
|
794
825
|
// Missing warnings and info arrays
|
|
795
826
|
}));
|
|
796
827
|
|
|
@@ -808,7 +839,9 @@ line4`;
|
|
|
808
839
|
// Get the mocked module and set it to return only warnings
|
|
809
840
|
const { validateLiquidHTML } = require('../liquidTemplateSupport');
|
|
810
841
|
validateLiquidHTML.mockImplementation(() => ({
|
|
811
|
-
warnings: [{
|
|
842
|
+
warnings: [{
|
|
843
|
+
type: 'warning', message: 'Liquid warning', line: 1, column: 1, rule: 'liquid-test', severity: 'warning', source: 'liquid',
|
|
844
|
+
}],
|
|
812
845
|
}));
|
|
813
846
|
|
|
814
847
|
const html = '<div>{{ liquid.template }}</div>';
|
|
@@ -825,7 +858,9 @@ line4`;
|
|
|
825
858
|
// Get the mocked module and set it to return only info
|
|
826
859
|
const { validateLiquidHTML } = require('../liquidTemplateSupport');
|
|
827
860
|
validateLiquidHTML.mockImplementation(() => ({
|
|
828
|
-
info: [{
|
|
861
|
+
info: [{
|
|
862
|
+
type: 'info', message: 'Liquid info', line: 1, column: 1, rule: 'liquid-test', severity: 'info', source: 'liquid',
|
|
863
|
+
}],
|
|
829
864
|
}));
|
|
830
865
|
|
|
831
866
|
const html = '<div>{{ liquid.template }}</div>';
|
|
@@ -851,8 +886,10 @@ line4`;
|
|
|
851
886
|
`;
|
|
852
887
|
const result = validateCSS(css);
|
|
853
888
|
|
|
854
|
-
|
|
855
|
-
expect(result.
|
|
889
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
890
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
891
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
892
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
856
893
|
});
|
|
857
894
|
|
|
858
895
|
it('handles CSS with nested braces', () => {
|
|
@@ -863,8 +900,10 @@ line4`;
|
|
|
863
900
|
`;
|
|
864
901
|
const result = validateCSS(css);
|
|
865
902
|
|
|
866
|
-
|
|
867
|
-
expect(result.
|
|
903
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
904
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
905
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
906
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
868
907
|
});
|
|
869
908
|
|
|
870
909
|
it('handles CSS with mixed valid and invalid rules', () => {
|
|
@@ -876,9 +915,11 @@ line4`;
|
|
|
876
915
|
`;
|
|
877
916
|
const result = validateCSS(css);
|
|
878
917
|
|
|
879
|
-
|
|
880
|
-
// Should detect at least one empty rule
|
|
881
|
-
expect(result.
|
|
918
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
919
|
+
// Should detect at least one empty rule as warning
|
|
920
|
+
expect(result.warnings.length).toBeGreaterThanOrEqual(1);
|
|
921
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
922
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
882
923
|
});
|
|
883
924
|
|
|
884
925
|
it('handles CSS validation exception scenarios', () => {
|
|
@@ -917,6 +958,126 @@ line4`;
|
|
|
917
958
|
});
|
|
918
959
|
});
|
|
919
960
|
|
|
961
|
+
describe('getSeverityLevel edge cases (lines 112-118, 159-166)', () => {
|
|
962
|
+
it('categorizes warning-level HTMLHint rules as warnings', () => {
|
|
963
|
+
// Test with HTML that triggers known warning rules like tag-pair
|
|
964
|
+
const html = '<p>Unclosed paragraph tag';
|
|
965
|
+
const result = validateHTML(html);
|
|
966
|
+
|
|
967
|
+
// Should have warnings for unclosed tag
|
|
968
|
+
expect(result).toBeDefined();
|
|
969
|
+
expect(result.warnings.length).toBeGreaterThanOrEqual(0);
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
it('categorizes attr-no-duplication rule as warning', () => {
|
|
973
|
+
const html = '<div class="test" class="duplicate">Duplicate attribute</div>';
|
|
974
|
+
const result = validateHTML(html);
|
|
975
|
+
|
|
976
|
+
expect(result).toBeDefined();
|
|
977
|
+
// Should categorize as warning based on warningRules list
|
|
978
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
it('categorizes id-unique rule as warning', () => {
|
|
982
|
+
const html = '<div id="unique"><span id="unique">Duplicate ID</span></div>';
|
|
983
|
+
const result = validateHTML(html);
|
|
984
|
+
|
|
985
|
+
expect(result).toBeDefined();
|
|
986
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
it('categorizes spec-char-escape rule as warning', () => {
|
|
990
|
+
const html = '<p>Special characters & < ></p>';
|
|
991
|
+
const result = validateHTML(html);
|
|
992
|
+
|
|
993
|
+
expect(result).toBeDefined();
|
|
994
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
it('categorizes tagname-lowercase rule as warning', () => {
|
|
998
|
+
const html = '<DIV><P>Uppercase tags</P></DIV>';
|
|
999
|
+
const result = validateHTML(html);
|
|
1000
|
+
|
|
1001
|
+
expect(result).toBeDefined();
|
|
1002
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
it('categorizes alt-require rule as warning', () => {
|
|
1006
|
+
const html = '<img src="test.jpg">';
|
|
1007
|
+
const result = validateHTML(html);
|
|
1008
|
+
|
|
1009
|
+
expect(result).toBeDefined();
|
|
1010
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
it('downgrades HTMLHint error type to warning (line 163-164)', () => {
|
|
1014
|
+
// HTMLHint "error" types that are not in warningRules should be downgraded to warning
|
|
1015
|
+
// This covers the case where type === 'error' returns 'warning'
|
|
1016
|
+
const htmlWithStructuralError = '<div><span>Missing closing span</div>';
|
|
1017
|
+
const result = validateHTML(htmlWithStructuralError);
|
|
1018
|
+
|
|
1019
|
+
expect(result).toBeDefined();
|
|
1020
|
+
// Structural HTML errors are downgraded to warnings
|
|
1021
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
it('returns info for non-warning, non-error types (line 166)', () => {
|
|
1025
|
+
// Test content that would produce info-level issues
|
|
1026
|
+
const simpleHtml = '<div></div>';
|
|
1027
|
+
const result = validateHTML(simpleHtml);
|
|
1028
|
+
|
|
1029
|
+
expect(result).toBeDefined();
|
|
1030
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
1031
|
+
// Info array should exist
|
|
1032
|
+
expect(Array.isArray(result.info)).toBe(true);
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
it('processes multiple issues with different severity levels (lines 112-118)', () => {
|
|
1036
|
+
// HTML that produces multiple issues with different severities
|
|
1037
|
+
const mixedHtml = `
|
|
1038
|
+
<DIV class="test" class="dup">
|
|
1039
|
+
<IMG src="">
|
|
1040
|
+
<P>Text
|
|
1041
|
+
</DIV>
|
|
1042
|
+
`;
|
|
1043
|
+
const result = validateHTML(mixedHtml);
|
|
1044
|
+
|
|
1045
|
+
expect(result).toBeDefined();
|
|
1046
|
+
// Should process and categorize issues correctly
|
|
1047
|
+
expect(Array.isArray(result.errors)).toBe(true);
|
|
1048
|
+
expect(Array.isArray(result.warnings)).toBe(true);
|
|
1049
|
+
expect(Array.isArray(result.info)).toBe(true);
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
it('pushes warning severity to warnings array (line 112-113)', () => {
|
|
1053
|
+
// This specifically tests when error.severity === 'warning'
|
|
1054
|
+
const htmlWithWarnings = '<DIV></DIV>'; // Uppercase tag names
|
|
1055
|
+
const result = validateHTML(htmlWithWarnings);
|
|
1056
|
+
|
|
1057
|
+
expect(result).toBeDefined();
|
|
1058
|
+
// Warnings should be in the warnings array
|
|
1059
|
+
expect(Array.isArray(result.warnings)).toBe(true);
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
it('pushes info severity to info array (line 114-115)', () => {
|
|
1063
|
+
// Content that produces info-level validation results
|
|
1064
|
+
const simpleContent = '<div><p>Valid content</p></div>';
|
|
1065
|
+
const result = validateHTML(simpleContent);
|
|
1066
|
+
|
|
1067
|
+
expect(result).toBeDefined();
|
|
1068
|
+
expect(Array.isArray(result.info)).toBe(true);
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
it('pushes other severities to warnings array as fallback (line 116-117)', () => {
|
|
1072
|
+
// This covers the else branch where unknown severities go to warnings
|
|
1073
|
+
const html = '<div>Test</div>';
|
|
1074
|
+
const result = validateHTML(html);
|
|
1075
|
+
|
|
1076
|
+
expect(result).toBeDefined();
|
|
1077
|
+
expect(Array.isArray(result.warnings)).toBe(true);
|
|
1078
|
+
});
|
|
1079
|
+
});
|
|
1080
|
+
|
|
920
1081
|
describe('extractAndValidateCSS Advanced Tests', () => {
|
|
921
1082
|
it('handles multiple style tags with mixed validity', () => {
|
|
922
1083
|
const html = `
|
|
@@ -927,8 +1088,10 @@ line4`;
|
|
|
927
1088
|
`;
|
|
928
1089
|
const result = extractAndValidateCSS(html);
|
|
929
1090
|
|
|
930
|
-
|
|
931
|
-
expect(result.
|
|
1091
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
1092
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
1093
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
1094
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
932
1095
|
});
|
|
933
1096
|
|
|
934
1097
|
it('handles style tags with complex CSS', () => {
|
|
@@ -943,17 +1106,21 @@ line4`;
|
|
|
943
1106
|
`;
|
|
944
1107
|
const result = extractAndValidateCSS(html);
|
|
945
1108
|
|
|
946
|
-
|
|
947
|
-
expect(result.
|
|
1109
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
1110
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
1111
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
1112
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
948
1113
|
});
|
|
949
1114
|
|
|
950
1115
|
it('correctly identifies unclosed style tags', () => {
|
|
951
1116
|
const html = '<style>.test { color: red; }';
|
|
952
1117
|
const result = extractAndValidateCSS(html);
|
|
953
1118
|
|
|
954
|
-
|
|
955
|
-
expect(result.
|
|
956
|
-
expect(result.
|
|
1119
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
1120
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
1121
|
+
expect(result.warnings.some((warning) => warning.rule === 'unclosed-style-tag')).toBe(true);
|
|
1122
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
1123
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
957
1124
|
});
|
|
958
1125
|
|
|
959
1126
|
it('handles multiple unclosed style tags', () => {
|
|
@@ -964,8 +1131,10 @@ line4`;
|
|
|
964
1131
|
`;
|
|
965
1132
|
const result = extractAndValidateCSS(html);
|
|
966
1133
|
|
|
967
|
-
|
|
968
|
-
expect(result.
|
|
1134
|
+
// CSS validation issues are WARNINGS (not blocking errors)
|
|
1135
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
1136
|
+
// isValid can be true if only warnings exist (warnings don't block)
|
|
1137
|
+
expect(typeof result.isValid).toBe('boolean');
|
|
969
1138
|
});
|
|
970
1139
|
});
|
|
971
1140
|
|
|
@@ -1017,10 +1186,10 @@ line4`;
|
|
|
1017
1186
|
'<table><tr><td>Table content</td></tr></table>',
|
|
1018
1187
|
'<form><input type="text"><button>Submit</button></form>',
|
|
1019
1188
|
'<ul><li>List item 1</li><li>List item 2</li></ul>',
|
|
1020
|
-
'<article><header><h1>Article</h1></header><p>Content</p></article>'
|
|
1189
|
+
'<article><header><h1>Article</h1></header><p>Content</p></article>',
|
|
1021
1190
|
];
|
|
1022
1191
|
|
|
1023
|
-
testCases.forEach(html => {
|
|
1192
|
+
testCases.forEach((html) => {
|
|
1024
1193
|
const result = validateHTML(html);
|
|
1025
1194
|
expect(result).toBeDefined();
|
|
1026
1195
|
expect(typeof result.isValid).toBe('boolean');
|
|
@@ -1039,4 +1208,4 @@ line4`;
|
|
|
1039
1208
|
expect(typeof inappResult.isValid).toBe('boolean');
|
|
1040
1209
|
});
|
|
1041
1210
|
});
|
|
1042
|
-
});
|
|
1211
|
+
});
|
|
@@ -238,3 +238,137 @@ describe('getValidationSummary', () => {
|
|
|
238
238
|
});
|
|
239
239
|
});
|
|
240
240
|
|
|
241
|
+
describe('validationAdapter error handling', () => {
|
|
242
|
+
describe('transformValidationToErrorInfo error handling', () => {
|
|
243
|
+
it('handles validation without getAllIssues method (line 33-36)', () => {
|
|
244
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
245
|
+
const validation = {
|
|
246
|
+
isValidating: false,
|
|
247
|
+
// Missing getAllIssues method
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const result = transformValidationToErrorInfo(validation);
|
|
251
|
+
|
|
252
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
253
|
+
expect.stringContaining('[validationAdapter] validation.getAllIssues is not a function'),
|
|
254
|
+
validation
|
|
255
|
+
);
|
|
256
|
+
expect(result).toEqual({
|
|
257
|
+
errorMessages: {
|
|
258
|
+
LIQUID_ERROR_MSG: [],
|
|
259
|
+
STANDARD_ERROR_MSG: [],
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
consoleSpy.mockRestore();
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('handles getAllIssues returning non-array (line 40-43)', () => {
|
|
267
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
268
|
+
const validation = {
|
|
269
|
+
isValidating: false,
|
|
270
|
+
getAllIssues: jest.fn(() => 'not an array'), // Returns string instead of array
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const result = transformValidationToErrorInfo(validation);
|
|
274
|
+
|
|
275
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
276
|
+
expect.stringContaining('[validationAdapter] validation.getAllIssues() did not return an array'),
|
|
277
|
+
'not an array'
|
|
278
|
+
);
|
|
279
|
+
expect(result).toEqual({
|
|
280
|
+
errorMessages: {
|
|
281
|
+
LIQUID_ERROR_MSG: [],
|
|
282
|
+
STANDARD_ERROR_MSG: [],
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
consoleSpy.mockRestore();
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
describe('hasValidationErrors error handling', () => {
|
|
291
|
+
it('handles validation without getAllIssues method (line 106-110)', () => {
|
|
292
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
293
|
+
const validation = {
|
|
294
|
+
isValidating: false,
|
|
295
|
+
// Missing getAllIssues method
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const result = hasValidationErrors(validation);
|
|
299
|
+
|
|
300
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
301
|
+
expect.stringContaining('[validationAdapter] validation.getAllIssues is not a function'),
|
|
302
|
+
validation
|
|
303
|
+
);
|
|
304
|
+
expect(result).toBe(false);
|
|
305
|
+
|
|
306
|
+
consoleSpy.mockRestore();
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('handles getAllIssues returning non-array (line 112-116)', () => {
|
|
310
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
311
|
+
const validation = {
|
|
312
|
+
isValidating: false,
|
|
313
|
+
getAllIssues: jest.fn(() => null), // Returns null instead of array
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const result = hasValidationErrors(validation);
|
|
317
|
+
|
|
318
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
319
|
+
expect.stringContaining('[validationAdapter] validation.getAllIssues() did not return an array'),
|
|
320
|
+
null
|
|
321
|
+
);
|
|
322
|
+
expect(result).toBe(false);
|
|
323
|
+
|
|
324
|
+
consoleSpy.mockRestore();
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
describe('getValidationSummary error handling', () => {
|
|
329
|
+
it('handles validation without getAllIssues method (line 131-135)', () => {
|
|
330
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
331
|
+
const validation = {
|
|
332
|
+
isValidating: false,
|
|
333
|
+
// Missing getAllIssues method
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const result = getValidationSummary(validation);
|
|
337
|
+
|
|
338
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
339
|
+
expect.stringContaining('[validationAdapter] validation.getAllIssues is not a function'),
|
|
340
|
+
validation
|
|
341
|
+
);
|
|
342
|
+
expect(result).toEqual({
|
|
343
|
+
totalErrors: 0,
|
|
344
|
+
totalWarnings: 0,
|
|
345
|
+
hasLiquidErrors: false,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
consoleSpy.mockRestore();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('handles getAllIssues returning non-array (line 138-141)', () => {
|
|
352
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
353
|
+
const validation = {
|
|
354
|
+
isValidating: false,
|
|
355
|
+
getAllIssues: jest.fn(() => ({})), // Returns object instead of array
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const result = getValidationSummary(validation);
|
|
359
|
+
|
|
360
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
361
|
+
expect.stringContaining('[validationAdapter] validation.getAllIssues() did not return an array'),
|
|
362
|
+
{}
|
|
363
|
+
);
|
|
364
|
+
expect(result).toEqual({
|
|
365
|
+
totalErrors: 0,
|
|
366
|
+
totalWarnings: 0,
|
|
367
|
+
hasLiquidErrors: false,
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
consoleSpy.mockRestore();
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|