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

1import pytest 

2 

3from .nodes import Comment, DocumentType, Element, Fragment, Text 

4 

5 

6def test_comment(): 

7 comment = Comment("This is a comment") 

8 assert str(comment) == "<!--This is a comment-->" 

9 

10 

11def test_comment_empty(): 

12 comment = Comment("") 

13 assert str(comment) == "<!---->" 

14 

15 

16def test_comment_special_chars(): 

17 comment = Comment("Special chars: <>&\"'") 

18 assert str(comment) == "<!--Special chars: <>&\"'-->" 

19 

20 

21def test_doctype_default(): 

22 doctype = DocumentType() 

23 assert str(doctype) == "<!DOCTYPE html>" 

24 

25 

26def test_doctype_custom(): 

27 doctype = DocumentType("xml") 

28 assert str(doctype) == "<!DOCTYPE xml>" 

29 

30 

31def test_text(): 

32 text = Text("Hello, world!") 

33 assert str(text) == "Hello, world!" 

34 

35 

36def test_text_escaping(): 

37 text = Text("<script>alert('XSS')</script>") 

38 assert str(text) == "&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;" 

39 

40 

41def test_text_safe(): 

42 class CustomHTML(str): 

43 def __html__(self) -> str: 

44 return "<b>Bold Text</b>" 

45 

46 text = Text(CustomHTML()) 

47 assert str(text) == "<b>Bold Text</b>" 

48 

49 

50def test_fragment_empty(): 

51 fragment = Fragment() 

52 assert str(fragment) == "" 

53 

54 

55def test_fragment_with_text(): 

56 fragment = Fragment(children=[Text("test")]) 

57 assert str(fragment) == "test" 

58 

59 

60def test_fragment_with_multiple_texts(): 

61 fragment = Fragment(children=[Text("Hello"), Text(" "), Text("World")]) 

62 assert str(fragment) == "Hello World" 

63 

64 

65def test_element_no_children(): 

66 div = Element("div") 

67 assert not div.is_void 

68 assert str(div) == "<div></div>" 

69 

70 

71def test_void_element_no_children(): 

72 br = Element("br") 

73 assert br.is_void 

74 assert str(br) == "<br />" 

75 

76 

77def test_element_invalid_empty_tag(): 

78 with pytest.raises(ValueError): 

79 _ = Element("") 

80 

81 

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 

87 

88 

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 />' 

92 

93 

94def test_void_element_with_children(): 

95 with pytest.raises(ValueError): 

96 _ = Element("br", children=[Text("should not be here")]) 

97 

98 

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>' 

105 

106 

107def test_standard_element_with_text_child(): 

108 div = Element("div", children=[Text("Hello, world!")]) 

109 assert str(div) == "<div>Hello, world!</div>" 

110 

111 

112def test_script_element_with_text_child(): 

113 node = Element( 

114 "script", 

115 children=[Text("if (a < b && c > d) { alert('hello &amp; friend'); }")], 

116 ) 

117 assert str(node) == ( 

118 "<script>if (a < b && c > d) { alert('hello &amp; friend'); }</script>" 

119 ) 

120 

121 

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>" 

125 

126 

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>" 

136 

137 

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>" 

151 

152 

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 ) 

167 

168 

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 ) 

221 

222 

223def test_dunder_html_method(): 

224 div = Element("div", children=[Text("Hello")]) 

225 assert div.__html__() == str(div) 

226 

227 

228def test_escaping_of_text_content(): 

229 div = Element("div", children=[Text("<script>alert('XSS')</script>")]) 

230 assert str(div) == "<div>&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;</div>" 

231 

232 

233def test_escaping_of_attribute_values(): 

234 div = Element("div", attrs={"class": '">XSS<'}) 

235 assert str(div) == '<div class="&#34;&gt;XSS&lt;"></div>'