|
| 1 | +/** |
| 2 | + * Tests for content type detection utilities |
| 3 | + */ |
| 4 | +import { containsHtml, determineEditorType } from './contentTypeUtils'; |
| 5 | + |
| 6 | +describe('contentTypeUtils', () => { |
| 7 | + describe('containsHtml', () => { |
| 8 | + describe('should return false for non-HTML content', () => { |
| 9 | + test.each([ |
| 10 | + ['empty string', ''], |
| 11 | + ['null', null], |
| 12 | + ['undefined', undefined], |
| 13 | + ['number', 123], |
| 14 | + ['plain text', 'This is just plain text'], |
| 15 | + ['text with special characters', 'Text with @#$%^&*()'], |
| 16 | + ['text with quotes', 'Text with "quotes" and \'apostrophes\''], |
| 17 | + ['text with newlines', 'Line 1\nLine 2\nLine 3'], |
| 18 | + ['text with angle brackets but not HTML', '5 < 10 and 10 > 5'], |
| 19 | + ['mathematical expressions', 'x = y < z > w'], |
| 20 | + ])('for %s', (description, input) => { |
| 21 | + expect(containsHtml(input)).toBe(false); |
| 22 | + }); |
| 23 | + }); |
| 24 | + |
| 25 | + describe('should return true for HTML content', () => { |
| 26 | + test.each([ |
| 27 | + // Basic HTML tags |
| 28 | + ['simple paragraph', '<p>Hello world</p>'], |
| 29 | + ['heading tag', '<h1>Title</h1>'], |
| 30 | + ['div element', '<div>Content</div>'], |
| 31 | + ['span element', '<span>Text</span>'], |
| 32 | + ['self-closing tag', '<br />'], |
| 33 | + ['self-closing without space', '<br/>'], |
| 34 | + |
| 35 | + // HTML tags with attributes |
| 36 | + ['tag with class', '<p class="intro">Text</p>'], |
| 37 | + ['tag with id', '<div id="content">Text</div>'], |
| 38 | + ['tag with multiple attributes', '<a href="link" target="_blank">Link</a>'], |
| 39 | + |
| 40 | + // Mixed case HTML |
| 41 | + ['uppercase tag', '<P>Paragraph</P>'], |
| 42 | + ['mixed case tag', '<DiV>Content</DiV>'], |
| 43 | + |
| 44 | + // HTML with content |
| 45 | + ['nested tags', '<div><p>Nested paragraph</p></div>'], |
| 46 | + ['multiple tags', '<h1>Title</h1><p>Paragraph</p>'], |
| 47 | + ['formatting tags', 'Text with <strong>bold</strong> and <em>italic</em>'], |
| 48 | + |
| 49 | + // Complex HTML structures |
| 50 | + ['list structure', '<ul><li>Item 1</li><li>Item 2</li></ul>'], |
| 51 | + ['table structure', '<table><tr><td>Cell</td></tr></table>'], |
| 52 | + ['form elements', '<input type="text" name="field">'], |
| 53 | + ['image tag', '<img src="image.jpg" alt="Image">'], |
| 54 | + |
| 55 | + // HTML entities |
| 56 | + ['named entities', 'Price: $100 & free shipping'], |
| 57 | + ['more entities', 'Copyright © 2024 – All rights reserved'], |
| 58 | + ['quotes entity', 'He said "Hello" to me'], |
| 59 | + ['numeric entities', 'Special char: € ©'], |
| 60 | + |
| 61 | + // HTML with text content |
| 62 | + ['HTML in mixed content', 'Introduction: <p>This is the main content.</p> End.'], |
| 63 | + ['multiple entities', 'A & B < C > D'], |
| 64 | + |
| 65 | + // Edge cases |
| 66 | + ['unclosed tag', '<p>Unclosed paragraph'], |
| 67 | + ['tag with newlines', '<p>\nMultiline\ncontent\n</p>'], |
| 68 | + ])('for %s', (description, input) => { |
| 69 | + expect(containsHtml(input)).toBe(true); |
| 70 | + }); |
| 71 | + }); |
| 72 | + }); |
| 73 | + |
| 74 | + describe('determineEditorType', () => { |
| 75 | + describe('should return "text" for non-HTML content', () => { |
| 76 | + test.each([ |
| 77 | + ['empty string', ''], |
| 78 | + ['null', null], |
| 79 | + ['undefined', undefined], |
| 80 | + ['number', 123], |
| 81 | + ['plain text', 'This is just plain text content'], |
| 82 | + ['long plain text', 'Lorem ipsum '.repeat(100)], |
| 83 | + ['text with special chars', 'Email: [email protected], Phone: (555) 123-4567'], |
| 84 | + ['mathematical content', '2 + 2 = 4, x < y, a > b'], |
| 85 | + ['code-like content', 'function() { return value < threshold; }'], |
| 86 | + ])('for %s', (description, input) => { |
| 87 | + expect(determineEditorType(input)).toBe('text'); |
| 88 | + }); |
| 89 | + }); |
| 90 | + |
| 91 | + describe('should return "html" for HTML content', () => { |
| 92 | + test.each([ |
| 93 | + // Simple HTML |
| 94 | + ['basic paragraph', '<p>Simple paragraph</p>'], |
| 95 | + ['heading', '<h2>Section Title</h2>'], |
| 96 | + ['formatted text', 'Text with <strong>bold</strong> formatting'], |
| 97 | + |
| 98 | + // Complex HTML structures |
| 99 | + ['nested elements', '<div class="intro"><h2>Title</h2><p>Content</p></div>'], |
| 100 | + ['lists', '<ul><li>First item</li><li>Second item</li></ul>'], |
| 101 | + ['tables', '<table><tr><td>Cell 1</td><td>Cell 2</td></tr></table>'], |
| 102 | + ['links and images', '<a href="/link"><img src="image.jpg" alt="Image"></a>'], |
| 103 | + |
| 104 | + // Course content examples |
| 105 | + ['course overview', '<div><h3>Course Overview</h3><p>This course covers...</p><ul><li>Topic 1</li></ul></div>'], |
| 106 | + ['about sidebar', '<div class="sidebar"><h4>About</h4><p>Prerequisites: None</p></div>'], |
| 107 | + |
| 108 | + // HTML entities |
| 109 | + ['content with entities', 'Price: $100 & includes shipping – 50% off!'], |
| 110 | + ['mixed content', 'Introduction <p>Main content with © symbol</p> conclusion'], |
| 111 | + ])('for %s', (description, input) => { |
| 112 | + expect(determineEditorType(input)).toBe('html'); |
| 113 | + }); |
| 114 | + }); |
| 115 | + |
| 116 | + describe('integration scenarios', () => { |
| 117 | + test('should handle real course overview content', () => { |
| 118 | + const courseOverview = ` |
| 119 | + <div class="course-overview"> |
| 120 | + <h2>Introduction to Computer Science</h2> |
| 121 | + <p>This course provides a comprehensive introduction to computer science concepts.</p> |
| 122 | + <h3>What You'll Learn:</h3> |
| 123 | + <ul> |
| 124 | + <li>Programming fundamentals</li> |
| 125 | + <li>Data structures and algorithms</li> |
| 126 | + <li>Software engineering practices</li> |
| 127 | + </ul> |
| 128 | + <p><strong>Prerequisites:</strong> Basic mathematics knowledge</p> |
| 129 | + <p><em>Duration:</em> 12 weeks</p> |
| 130 | + </div> |
| 131 | + `; |
| 132 | + |
| 133 | + expect(containsHtml(courseOverview)).toBe(true); |
| 134 | + expect(determineEditorType(courseOverview)).toBe('html'); |
| 135 | + }); |
| 136 | + |
| 137 | + test('should handle sidebar HTML content', () => { |
| 138 | + const sidebarHtml = ` |
| 139 | + <div class="about-sidebar"> |
| 140 | + <h4>Course Information</h4> |
| 141 | + <p><strong>Instructor:</strong> Dr. Smith</p> |
| 142 | + <p><strong>Credits:</strong> 3</p> |
| 143 | + <p><strong>Format:</strong> Online & In-person</p> |
| 144 | + <a href="/syllabus">Download Syllabus</a> |
| 145 | + </div> |
| 146 | + `; |
| 147 | + |
| 148 | + expect(containsHtml(sidebarHtml)).toBe(true); |
| 149 | + expect(determineEditorType(sidebarHtml)).toBe('html'); |
| 150 | + }); |
| 151 | + |
| 152 | + test('should handle plain text course descriptions', () => { |
| 153 | + const plainDescription = 'A beginner-friendly course covering the basics of programming. No prior experience required.'; |
| 154 | + |
| 155 | + expect(containsHtml(plainDescription)).toBe(false); |
| 156 | + expect(determineEditorType(plainDescription)).toBe('text'); |
| 157 | + }); |
| 158 | + |
| 159 | + test('should handle empty or minimal content', () => { |
| 160 | + expect(determineEditorType('')).toBe('text'); |
| 161 | + expect(determineEditorType(' ')).toBe('text'); |
| 162 | + expect(determineEditorType(null)).toBe('text'); |
| 163 | + expect(determineEditorType(undefined)).toBe('text'); |
| 164 | + }); |
| 165 | + }); |
| 166 | + }); |
| 167 | +}); |
0 commit comments