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

1import pytest 

2from markupsafe import Markup 

3 

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

5 

6 

7def test_comment(): 

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

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

10 

11 

12def test_comment_empty(): 

13 comment = Comment("") 

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

15 

16 

17def test_comment_special_chars(): 

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

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

20 

21 

22def test_doctype_default(): 

23 doctype = DocumentType() 

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

25 

26 

27def test_doctype_custom(): 

28 doctype = DocumentType("xml") 

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

30 

31 

32def test_text(): 

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

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

35 

36 

37def test_text_escaping(): 

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

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

40 

41 

42def test_text_safe(): 

43 class CustomHTML(str): 

44 def __html__(self) -> str: 

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

46 

47 text = Text(CustomHTML()) 

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

49 

50 

51def test_text_equality(): 

52 text1 = Text("<Hello>") 

53 text2 = Text(Markup("&lt;Hello&gt;")) 

54 text3 = Text(Markup("<Hello>")) 

55 assert text1 == text2 

56 assert text1 != text3 

57 

58 

59def test_fragment_empty(): 

60 fragment = Fragment() 

61 assert str(fragment) == "" 

62 

63 

64def test_fragment_with_text(): 

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

66 assert str(fragment) == "test" 

67 

68 

69def test_fragment_with_multiple_texts(): 

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

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

72 

73 

74def test_element_no_children(): 

75 div = Element("div") 

76 assert not div.is_void 

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

78 

79 

80def test_void_element_no_children(): 

81 br = Element("br") 

82 assert br.is_void 

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

84 

85 

86def test_element_invalid_empty_tag(): 

87 with pytest.raises(ValueError): 

88 _ = Element("") 

89 

90 

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 

96 

97 

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

101 

102 

103def test_void_element_with_children(): 

104 with pytest.raises(ValueError): 

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

106 

107 

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

114 

115 

116def test_standard_element_with_text_child(): 

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

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

119 

120 

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

130 

131 

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

145 

146 

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 ) 

161 

162 

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 ) 

215 

216 

217def test_dunder_html_method(): 

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

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

220 

221 

222def test_escaping_of_text_content(): 

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

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

225 

226 

227def test_escaping_of_attribute_values(): 

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

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