hpx_browser/
html_parser.rs1use blitz_dom::{BaseDocument, DocumentConfig, StyleThreading};
2use blitz_html::HtmlDocument;
3
4use crate::dom::Dom;
5
6pub fn parse_html(html: &str) -> Dom {
7 let mut config = DocumentConfig::default();
8 config.style_threading = StyleThreading::Sequential;
9 config.base_url = Some("http://localhost".to_string());
10 let html_doc = HtmlDocument::from_html(html, config);
11 let base: BaseDocument = html_doc.into();
12 Dom::from_base(base)
13}
14
15#[cfg(test)]
16mod tests {
17 use super::*;
18 use crate::dom::{DomElement, NodeId, QualName};
19
20 fn find_child_by_tag(dom: &Dom, parent: NodeId, tag: &str) -> NodeId {
21 dom.child_elements(parent)
22 .into_iter()
23 .find(|&id| {
24 dom.get(id)
25 .map(|n| n.is_element_with_tag(tag))
26 .unwrap_or(false)
27 })
28 .unwrap()
29 }
30
31 #[test]
32 fn parse_basic_html() {
33 let dom = parse_html("<html><body><h1>Hello</h1></body></html>");
34 let children = dom.children(NodeId::DOCUMENT);
35 assert!(!children.is_empty(), "Document should have children");
36 }
37
38 #[test]
39 fn parse_has_html_element() {
40 let dom = parse_html("<html><head></head><body><p>Test</p></body></html>");
41 let doc_children = dom.child_elements(NodeId::DOCUMENT);
42 assert!(!doc_children.is_empty());
43
44 let html_el = DomElement::new(&dom, doc_children[0]).unwrap();
45 assert_eq!(html_el.local_name(), "html");
46 }
47
48 #[test]
49 fn parse_text_content() {
50 let dom = parse_html("<html><body><p>Hello world</p></body></html>");
51 let html = dom.child_elements(NodeId::DOCUMENT)[0];
52 let body = find_child_by_tag(&dom, html, "body");
53 let p = dom.child_elements(body)[0];
54 assert_eq!(dom.text_content(p), "Hello world");
55 }
56
57 #[test]
58 fn parse_attributes() {
59 let dom = parse_html("<div id=\"main\" class=\"container\">test</div>");
60 let html = dom.child_elements(NodeId::DOCUMENT)[0];
61 let body = find_child_by_tag(&dom, html, "body");
62 let div = dom.child_elements(body)[0];
63 let el = DomElement::new(&dom, div).unwrap();
64
65 assert_eq!(el.id(), Some("main"));
66 assert!(el.has_class("container"));
67 }
68
69 #[test]
70 fn parse_nested_structure() {
71 let dom = parse_html("<html><body><div><span>a</span><span>b</span></div></body></html>");
72 let html = dom.child_elements(NodeId::DOCUMENT)[0];
73 let body = find_child_by_tag(&dom, html, "body");
74 let div = find_child_by_tag(&dom, body, "div");
75
76 let spans = dom.child_elements(div);
77 assert!(!spans.is_empty(), "expected at least 1 span");
78 assert_eq!(dom.text_content(div), "ab");
79 }
80
81 #[test]
82 fn bdd_parse_simple_html_via_parser() {
83 let dom = parse_html("<html><body><h1>Hello</h1></body></html>");
84 assert!(dom.get(NodeId::DOCUMENT).is_some());
85
86 let html = dom.child_elements(NodeId::DOCUMENT)[0];
87 let body = find_child_by_tag(&dom, html, "body");
88 let h1 = find_child_by_tag(&dom, body, "h1");
89
90 assert_eq!(dom.text_content(h1), "Hello");
91 }
92
93 #[test]
94 fn bdd_query_elements_via_parser() {
95 let dom = parse_html("<div class='content'><p>First</p><p>Second</p></div>");
96 let ps = dom.get_elements_by_tag_name(NodeId::DOCUMENT, "p");
97 assert_eq!(ps.len(), 2);
98 assert_eq!(dom.text_content(ps[0]), "First");
99 }
100
101 #[test]
102 fn bdd_mutate_dom_via_parser() {
103 let dom = parse_html("<div><span>Old</span></div>");
104 let html = dom.child_elements(NodeId::DOCUMENT)[0];
105 let body = find_child_by_tag(&dom, html, "body");
106 let div = find_child_by_tag(&dom, body, "div");
107
108 let mut dom = dom;
109 let p = dom.create_element(QualName::new("p"), vec![]);
110 let text = dom.create_text("New".to_string());
111 dom.append_child(div, p);
112 dom.append_child(p, text);
113
114 assert_eq!(dom.children(div).len(), 2);
115 }
116}