Coverage for tdom/nodes_test.py: 100%
93 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-17 19:54 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-17 19:54 +0000
1import pytest
3from .nodes import Comment, DocumentType, Element, Fragment, Text
6def test_comment():
7 comment = Comment("This is a comment")
8 assert str(comment) == "<!--This is a comment-->"
11def test_comment_empty():
12 comment = Comment("")
13 assert str(comment) == "<!---->"
16def test_comment_special_chars():
17 comment = Comment("Special chars: <>&\"'")
18 assert str(comment) == "<!--Special chars: <>&\"'-->"
21def test_doctype_default():
22 doctype = DocumentType()
23 assert str(doctype) == "<!DOCTYPE html>"
26def test_doctype_custom():
27 doctype = DocumentType("xml")
28 assert str(doctype) == "<!DOCTYPE xml>"
31def test_text():
32 text = Text("Hello, world!")
33 assert str(text) == "Hello, world!"
36def test_text_escaping():
37 text = Text("<script>alert('XSS')</script>")
38 assert str(text) == "<script>alert('XSS')</script>"
41def test_text_safe():
42 class CustomHTML(str):
43 def __html__(self) -> str:
44 return "<b>Bold Text</b>"
46 text = Text(CustomHTML())
47 assert str(text) == "<b>Bold Text</b>"
50def test_fragment_empty():
51 fragment = Fragment()
52 assert str(fragment) == ""
55def test_fragment_with_text():
56 fragment = Fragment(children=[Text("test")])
57 assert str(fragment) == "test"
60def test_fragment_with_multiple_texts():
61 fragment = Fragment(children=[Text("Hello"), Text(" "), Text("World")])
62 assert str(fragment) == "Hello World"
65def test_element_no_children():
66 div = Element("div")
67 assert not div.is_void
68 assert str(div) == "<div></div>"
71def test_void_element_no_children():
72 br = Element("br")
73 assert br.is_void
74 assert str(br) == "<br />"
77def test_element_invalid_empty_tag():
78 with pytest.raises(ValueError):
79 _ = Element("")
82def test_element_is_content():
83 assert Element("script").is_content
84 assert Element("title").is_content
85 assert not Element("div").is_content
86 assert not Element("br").is_content # Void element
89def test_void_element_with_attributes():
90 br = Element("br", attrs={"class": "line-break", "hidden": None})
91 assert str(br) == '<br class="line-break" hidden />'
94def test_void_element_with_children():
95 with pytest.raises(ValueError):
96 _ = Element("br", children=[Text("should not be here")])
99def test_standard_element_with_attributes():
100 div = Element(
101 "div",
102 attrs={"id": "main", "data-role": "container", "hidden": None},
103 )
104 assert str(div) == '<div id="main" data-role="container" hidden></div>'
107def test_standard_element_with_text_child():
108 div = Element("div", children=[Text("Hello, world!")])
109 assert str(div) == "<div>Hello, world!</div>"
112def test_script_element_with_text_child():
113 node = Element(
114 "script",
115 children=[Text("if (a < b && c > d) { alert('hello & friend'); }")],
116 )
117 assert str(node) == (
118 "<script>if (a < b && c > d) { alert('hello & friend'); }</script>"
119 )
122def test_title_element_with_text_child():
123 node = Element("title", children=[Text("My & Awesome <Site>")])
124 assert str(node) == "<title>My & Awesome <Site></title>"
127def test_standard_element_with_element_children():
128 div = Element(
129 "div",
130 children=[
131 Element("h1", children=[Text("Title")]),
132 Element("p", children=[Text("This is a paragraph.")]),
133 ],
134 )
135 assert str(div) == "<div><h1>Title</h1><p>This is a paragraph.</p></div>"
138def test_element_with_fragment_with_children():
139 div = Element(
140 "div",
141 children=[
142 Fragment(
143 children=[
144 Element("div", children=[Text("wow")]),
145 Text("inside fragment"),
146 ]
147 )
148 ],
149 )
150 assert str(div) == "<div><div>wow</div>inside fragment</div>"
153def test_standard_element_with_mixed_children():
154 div = Element(
155 "div",
156 children=[
157 Text("Intro text."),
158 Element("h1", children=[Text("Title")]),
159 Text("Some more text."),
160 Element("hr"),
161 Element("p", children=[Text("This is a paragraph.")]),
162 ],
163 )
164 assert str(div) == (
165 "<div>Intro text.<h1>Title</h1>Some more text.<hr /><p>This is a paragraph.</p></div>"
166 )
169def test_complex_tree():
170 html = Fragment(
171 children=[
172 DocumentType(),
173 Element(
174 "html",
175 children=[
176 Element(
177 "head",
178 children=[
179 Element("title", children=[Text("Test Page")]),
180 Element("meta", attrs={"charset": "UTF-8"}),
181 ],
182 ),
183 Element(
184 "body",
185 attrs={"class": "main-body"},
186 children=[
187 Element("h1", children=[Text("Welcome to the Test Page")]),
188 Element(
189 "p",
190 children=[
191 Text("This is a sample paragraph with "),
192 Element("strong", children=[Text("bold text")]),
193 Text(" and "),
194 Element("em", children=[Text("italic text")]),
195 Text("."),
196 ],
197 ),
198 Element("br"),
199 Element(
200 "ul",
201 children=[
202 Element("li", children=[Text("Item 1")]),
203 Element("li", children=[Text("Item 2")]),
204 Element("li", children=[Text("Item 3")]),
205 ],
206 ),
207 ],
208 ),
209 ],
210 ),
211 ]
212 )
213 assert str(html) == (
214 "<!DOCTYPE html><html><head><title>Test Page</title>"
215 '<meta charset="UTF-8" /></head><body class="main-body">'
216 "<h1>Welcome to the Test Page</h1>"
217 "<p>This is a sample paragraph with <strong>bold text</strong> and "
218 "<em>italic text</em>.</p><br /><ul><li>Item 1</li><li>Item 2</li>"
219 "<li>Item 3</li></ul></body></html>"
220 )
223def test_dunder_html_method():
224 div = Element("div", children=[Text("Hello")])
225 assert div.__html__() == str(div)
228def test_escaping_of_text_content():
229 div = Element("div", children=[Text("<script>alert('XSS')</script>")])
230 assert str(div) == "<div><script>alert('XSS')</script></div>"
233def test_escaping_of_attribute_values():
234 div = Element("div", attrs={"class": '">XSS<'})
235 assert str(div) == '<div class="">XSS<"></div>'