Coverage for tdom/nodes_test.py: 100%
94 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-31 17:14 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-31 17:14 +0000
1import pytest
2from markupsafe import Markup
4from .nodes import Comment, DocumentType, Element, Fragment, Text
7def test_comment():
8 comment = Comment("This is a comment")
9 assert str(comment) == "<!--This is a comment-->"
12def test_comment_empty():
13 comment = Comment("")
14 assert str(comment) == "<!---->"
17def test_comment_special_chars():
18 comment = Comment("Special chars: <>&\"'")
19 assert str(comment) == "<!--Special chars: <>&\"'-->"
22def test_doctype_default():
23 doctype = DocumentType()
24 assert str(doctype) == "<!DOCTYPE html>"
27def test_doctype_custom():
28 doctype = DocumentType("xml")
29 assert str(doctype) == "<!DOCTYPE xml>"
32def test_text():
33 text = Text("Hello, world!")
34 assert str(text) == "Hello, world!"
37def test_text_escaping():
38 text = Text("<script>alert('XSS')</script>")
39 assert str(text) == "<script>alert('XSS')</script>"
42def test_text_safe():
43 class CustomHTML(str):
44 def __html__(self) -> str:
45 return "<b>Bold Text</b>"
47 text = Text(CustomHTML())
48 assert str(text) == "<b>Bold Text</b>"
51def test_text_equality():
52 text1 = Text("<Hello>")
53 text2 = Text(Markup("<Hello>"))
54 text3 = Text(Markup("<Hello>"))
55 assert text1 == text2
56 assert text1 != text3
59def test_fragment_empty():
60 fragment = Fragment()
61 assert str(fragment) == ""
64def test_fragment_with_text():
65 fragment = Fragment(children=[Text("test")])
66 assert str(fragment) == "test"
69def test_fragment_with_multiple_texts():
70 fragment = Fragment(children=[Text("Hello"), Text(" "), Text("World")])
71 assert str(fragment) == "Hello World"
74def test_element_no_children():
75 div = Element("div")
76 assert not div.is_void
77 assert str(div) == "<div></div>"
80def test_void_element_no_children():
81 br = Element("br")
82 assert br.is_void
83 assert str(br) == "<br />"
86def test_element_invalid_empty_tag():
87 with pytest.raises(ValueError):
88 _ = Element("")
91def test_element_is_content():
92 assert Element("script").is_content
93 assert Element("title").is_content
94 assert not Element("div").is_content
95 assert not Element("br").is_content # Void element
98def test_void_element_with_attributes():
99 br = Element("br", attrs={"class": "line-break", "hidden": None})
100 assert str(br) == '<br class="line-break" hidden />'
103def test_void_element_with_children():
104 with pytest.raises(ValueError):
105 _ = Element("br", children=[Text("should not be here")])
108def test_standard_element_with_attributes():
109 div = Element(
110 "div",
111 attrs={"id": "main", "data-role": "container", "hidden": None},
112 )
113 assert str(div) == '<div id="main" data-role="container" hidden></div>'
116def test_standard_element_with_text_child():
117 div = Element("div", children=[Text("Hello, world!")])
118 assert str(div) == "<div>Hello, world!</div>"
121def test_standard_element_with_element_children():
122 div = Element(
123 "div",
124 children=[
125 Element("h1", children=[Text("Title")]),
126 Element("p", children=[Text("This is a paragraph.")]),
127 ],
128 )
129 assert str(div) == "<div><h1>Title</h1><p>This is a paragraph.</p></div>"
132def test_element_with_fragment_with_children():
133 div = Element(
134 "div",
135 children=[
136 Fragment(
137 children=[
138 Element("div", children=[Text("wow")]),
139 Text("inside fragment"),
140 ]
141 )
142 ],
143 )
144 assert str(div) == "<div><div>wow</div>inside fragment</div>"
147def test_standard_element_with_mixed_children():
148 div = Element(
149 "div",
150 children=[
151 Text("Intro text."),
152 Element("h1", children=[Text("Title")]),
153 Text("Some more text."),
154 Element("hr"),
155 Element("p", children=[Text("This is a paragraph.")]),
156 ],
157 )
158 assert str(div) == (
159 "<div>Intro text.<h1>Title</h1>Some more text.<hr /><p>This is a paragraph.</p></div>"
160 )
163def test_complex_tree():
164 html = Fragment(
165 children=[
166 DocumentType(),
167 Element(
168 "html",
169 children=[
170 Element(
171 "head",
172 children=[
173 Element("title", children=[Text("Test Page")]),
174 Element("meta", attrs={"charset": "UTF-8"}),
175 ],
176 ),
177 Element(
178 "body",
179 attrs={"class": "main-body"},
180 children=[
181 Element("h1", children=[Text("Welcome to the Test Page")]),
182 Element(
183 "p",
184 children=[
185 Text("This is a sample paragraph with "),
186 Element("strong", children=[Text("bold text")]),
187 Text(" and "),
188 Element("em", children=[Text("italic text")]),
189 Text("."),
190 ],
191 ),
192 Element("br"),
193 Element(
194 "ul",
195 children=[
196 Element("li", children=[Text("Item 1")]),
197 Element("li", children=[Text("Item 2")]),
198 Element("li", children=[Text("Item 3")]),
199 ],
200 ),
201 ],
202 ),
203 ],
204 ),
205 ]
206 )
207 assert str(html) == (
208 "<!DOCTYPE html><html><head><title>Test Page</title>"
209 '<meta charset="UTF-8" /></head><body class="main-body">'
210 "<h1>Welcome to the Test Page</h1>"
211 "<p>This is a sample paragraph with <strong>bold text</strong> and "
212 "<em>italic text</em>.</p><br /><ul><li>Item 1</li><li>Item 2</li>"
213 "<li>Item 3</li></ul></body></html>"
214 )
217def test_dunder_html_method():
218 div = Element("div", children=[Text("Hello")])
219 assert div.__html__() == str(div)
222def test_escaping_of_text_content():
223 div = Element("div", children=[Text("<script>alert('XSS')</script>")])
224 assert str(div) == "<div><script>alert('XSS')</script></div>"
227def test_escaping_of_attribute_values():
228 div = Element("div", attrs={"class": '">XSS<'})
229 assert str(div) == '<div class="">XSS<"></div>'