Skip to main content

hpx_browser/
html_parser.rs

1use 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}