11"""
22Integration tests for complete markdown-it-py setup with all plugins.
33"""
4+ from bs4 import BeautifulSoup
45from django .test import TestCase
56from askbot .tests .utils import with_settings
67from askbot .utils .markup import get_md_converter , reset_md_converter
@@ -38,26 +39,88 @@ def test_footnotes(self):
3839 md = get_md_converter ()
3940 text = "Text with footnote[^1]\n \n [^1]: Footnote content"
4041 html = md .render (text )
41- self .assertIn ('footnote' , html .lower ())
42+
43+ soup = BeautifulSoup (html , 'html5lib' )
44+
45+ # Check for footnote reference (superscript with link)
46+ footnote_refs = soup .find_all ('sup' , class_ = 'footnote-ref' )
47+ self .assertEqual (len (footnote_refs ), 1 )
48+
49+ # Check for footnote section at bottom
50+ footnote_section = soup .find ('section' , class_ = 'footnotes' )
51+ self .assertIsNotNone (footnote_section )
52+
53+ # Check footnote content
54+ footnote_list = footnote_section .find ('ol' )
55+ self .assertIsNotNone (footnote_list )
56+ footnote_items = footnote_list .find_all ('li' )
57+ self .assertEqual (len (footnote_items ), 1 )
58+ self .assertIn ('Footnote content' , footnote_items [0 ].text )
4259
4360 def test_task_lists (self ):
4461 md = get_md_converter ()
4562 text = "- [ ] Unchecked\n - [x] Checked"
4663 html = md .render (text )
47- self .assertTrue ('checkbox' in html .lower () or 'task' in html .lower ())
64+
65+ soup = BeautifulSoup (html , 'html5lib' )
66+
67+ # Find all checkbox inputs
68+ checkboxes = soup .find_all ('input' , type = 'checkbox' )
69+ self .assertEqual (len (checkboxes ), 2 )
70+
71+ # Verify unchecked box
72+ self .assertFalse (checkboxes [0 ].has_attr ('checked' ))
73+
74+ # Verify checked box
75+ self .assertTrue (checkboxes [1 ].has_attr ('checked' ))
76+
77+ # Verify task list classes
78+ task_list = soup .find ('ul' , class_ = 'contains-task-list' )
79+ self .assertIsNotNone (task_list )
80+
81+ task_items = soup .find_all ('li' , class_ = 'task-list-item' )
82+ self .assertEqual (len (task_items ), 2 )
4883
4984 def test_syntax_highlighting (self ):
5085 md = get_md_converter ()
5186 text = "```python\n def hello():\n pass\n ```"
5287 html = md .render (text )
53- self .assertIn ('highlight' , html )
88+
89+ soup = BeautifulSoup (html , 'html5lib' )
90+
91+ # Check for pre > code structure
92+ pre_tag = soup .find ('pre' )
93+ self .assertIsNotNone (pre_tag )
94+
95+ code_tag = pre_tag .find ('code' )
96+ self .assertIsNotNone (code_tag )
97+
98+ # Verify language class
99+ self .assertTrue (
100+ 'language-python' in code_tag .get ('class' , []) or
101+ 'highlight' in code_tag .get ('class' , [])
102+ )
103+
104+ # Verify code content is present
105+ self .assertIn ('def hello():' , code_tag .text )
106+ self .assertIn ('pass' , code_tag .text )
54107
55108 def test_video_embedding (self ):
56109 md = get_md_converter ()
57110 text = "Check this: @[youtube](dQw4w9WgXcQ)"
58111 html = md .render (text )
59- self .assertIn ('youtube.com/embed/dQw4w9WgXcQ' , html )
60- self .assertIn ('iframe' , html )
112+
113+ soup = BeautifulSoup (html , 'html5lib' )
114+
115+ # Find iframe element
116+ iframe = soup .find ('iframe' )
117+ self .assertIsNotNone (iframe )
118+
119+ # Verify src attribute
120+ self .assertIn ('youtube.com/embed/dQw4w9WgXcQ' , iframe ['src' ])
121+
122+ # Verify surrounding text
123+ self .assertIn ('Check this:' , html )
61124
62125 @with_settings (ENABLE_AUTO_LINKING = True ,
63126 AUTO_LINK_PATTERNS = r'#bug(\d+)' ,
@@ -69,7 +132,19 @@ def test_link_patterns_enabled(self):
69132 text = "Fixed #bug123"
70133 html = md .render (text )
71134
72- self .assertIn ('bugs.example.com/123' , html )
135+ soup = BeautifulSoup (html , 'html5lib' )
136+
137+ # Find the link
138+ links = soup .find_all ('a' )
139+ self .assertEqual (len (links ), 1 )
140+
141+ link = links [0 ]
142+ self .assertEqual (link ['href' ], 'https://bugs.example.com/123' )
143+ self .assertEqual (link .text .strip (), '#bug123' )
144+
145+ # Verify surrounding text preserved
146+ paragraph = soup .find ('p' )
147+ self .assertIn ('Fixed' , paragraph .text )
73148
74149 @with_settings (MARKUP_CODE_FRIENDLY = True )
75150 def test_code_friendly_mode (self ):
@@ -93,13 +168,28 @@ def test_mathjax_math_delimiters_preserved(self):
93168 # Inline math
94169 text = "The equation $E = mc^2$ is famous"
95170 html = md .render (text )
96- self .assertTrue ('$E = mc^2$' in html or '$E = mc^2$' in html .replace (' ' , ' ' ))
171+
172+ soup = BeautifulSoup (html , 'html5lib' )
173+ paragraph = soup .find ('p' )
174+ self .assertIsNotNone (paragraph )
175+
176+ # Verify math delimiters are preserved (not converted to HTML)
177+ para_html = str (paragraph )
178+ self .assertIn ('$E = mc^2$' , para_html )
179+ self .assertNotIn ('<em>' , para_html ) # No emphasis tags in math
180+ self .assertIn ('famous' , paragraph .text )
97181
98182 # Display math
99183 text = "$$\\ int_0^1 x dx = \\ frac{1}{2}$$"
100184 html = md .render (text )
185+
186+ soup = BeautifulSoup (html , 'html5lib' )
187+
188+ # Display math should be in its own block
101189 self .assertIn ('$$' , html )
102- self .assertTrue ('\\ int_0^1' in html or r'\int_0^1' in html )
190+ # Verify LaTeX commands preserved
191+ self .assertIn ('\\ int_0^1' , html )
192+ self .assertIn ('\\ frac{1}{2}' , html )
103193
104194 @with_settings (ENABLE_MATHJAX = True )
105195 def test_mathjax_underscores_not_emphasis (self ):
@@ -110,10 +200,19 @@ def test_mathjax_underscores_not_emphasis(self):
110200 text = "$a_b$ and $x_{123}$"
111201 html = md .render (text )
112202
113- # Should NOT have <em> or <sub> tags inside math
114- # Math content should be preserved verbatim
115- self .assertTrue ('$a_b$' in html or '$a_b$' in html .replace (' ' , ' ' ))
116- self .assertTrue ('<em>' not in html or html .count ('<em>' ) == 0 )
203+ soup = BeautifulSoup (html , 'html5lib' )
204+
205+ # Verify no em or sub tags created
206+ em_tags = soup .find_all ('em' )
207+ sub_tags = soup .find_all ('sub' )
208+ self .assertEqual (len (em_tags ), 0 , "Found emphasis tags in math content" )
209+ self .assertEqual (len (sub_tags ), 0 , "Found subscript tags in math content" )
210+
211+ # Verify math delimiters preserved
212+ paragraph = soup .find ('p' )
213+ para_html = str (paragraph )
214+ self .assertIn ('$a_b$' , para_html )
215+ self .assertIn ('$x_{123}$' , para_html )
117216
118217 def test_combined_features (self ):
119218 """Test document using multiple features"""
@@ -141,9 +240,42 @@ def example():
141240"""
142241 html = md .render (text )
143242
144- # Check all features rendered
145- self .assertIn ('<h1>Title</h1>' , html )
146- self .assertIn ('<strong>bold text</strong>' , html )
147- self .assertIn ('youtube.com/embed/abc123' , html )
148- self .assertTrue ('highlight' in html or 'class="language-python"' in html )
149- self .assertIn ('<table>' , html )
243+ soup = BeautifulSoup (html , 'html5lib' )
244+
245+ # Verify heading
246+ h1 = soup .find ('h1' )
247+ self .assertIsNotNone (h1 )
248+ self .assertEqual (h1 .text .strip (), 'Title' )
249+
250+ # Verify bold text
251+ strong = soup .find ('strong' )
252+ self .assertIsNotNone (strong )
253+ self .assertEqual (strong .text , 'bold text' )
254+
255+ # Verify video iframe
256+ iframe = soup .find ('iframe' )
257+ self .assertIsNotNone (iframe )
258+ self .assertIn ('abc123' , iframe ['src' ])
259+
260+ # Verify code block with language class
261+ pre = soup .find ('pre' )
262+ self .assertIsNotNone (pre )
263+ code = pre .find ('code' )
264+ self .assertIsNotNone (code )
265+ self .assertTrue (
266+ 'language-python' in code .get ('class' , []) or
267+ 'highlight' in str (pre )
268+ )
269+ self .assertIn ('def example():' , code .text )
270+
271+ # Verify table structure
272+ table = soup .find ('table' )
273+ self .assertIsNotNone (table )
274+ th_cells = table .find_all ('th' )
275+ self .assertEqual (len (th_cells ), 2 )
276+
277+ # Verify task list
278+ checkboxes = soup .find_all ('input' , type = 'checkbox' )
279+ self .assertEqual (len (checkboxes ), 2 )
280+ self .assertTrue (checkboxes [0 ].has_attr ('checked' )) # First is checked
281+ self .assertFalse (checkboxes [1 ].has_attr ('checked' )) # Second unchecked
0 commit comments