use std::result::Result as StdResult; use visdom::types::BoxDynError; use visdom::Vis; type Result = StdResult<(), BoxDynError>; #[test] fn test_attribute_selector() -> Result { let html = r##" "##; let root = Vis::load(html)?; let lang = root.find("#lang"); let links = lang.children(""); // equal let equal_en = links.filter("[lang='en']"); assert_eq!(equal_en.length(), 1); // begin with let begin_en = links.filter("[lang^='en']"); assert_eq!(begin_en.length(), 3); // end with let end_en = links.filter("[lang$='en']"); assert_eq!(end_en.length(), 2); // appear let appear_en = links.filter("[lang*='en']"); assert_eq!(appear_en.length(), 4); // equal or begin with `en-` let split_en = links.filter("[lang|= en]"); assert_eq!(split_en.length(), 2); // not equal to `en` let not_en = links.filter("[lang!=en]"); assert_eq!(not_en.length(), 3); // split list en let ws_en = links.filter("[lang~='en']"); assert_eq!(ws_en.length(), 2); // special cases let html = r##" "##; let root = Vis::load(html)?; let lang = root.find("#lang"); assert_eq!(lang.find("a[lang^='']").length(), 0); assert_eq!(lang.find("a[lang$='']").length(), 0); assert_eq!(lang.find("a[lang*='']").length(), 0); assert_eq!(lang.find("a[lang~='']").length(), 0); assert_eq!(lang.find("a[lang^='a']").length(), 0); assert_eq!(lang.find("a[lang$='b']").length(), 0); assert_eq!(lang.find("a[lang*='c']").length(), 0); assert_eq!(lang.find("a[lang~='d']").length(), 0); assert_eq!(lang.find("a[lang!='']").length(), 0); assert_eq!(lang.find("a[lang!='anything']").length(), 2); assert_eq!(lang.find("a[lang='']").length(), 2); assert_eq!(lang.find("a[lang]").length(), 2); assert_eq!(lang.find("a[lang|='']").length(), 2); Ok(()) } #[test] fn test_id_selector() -> Result { let html = r##" "##; let root = Vis::load(html)?; let lang = root.find("#lang"); assert_eq!(lang.length(), 1); // link let link = root.find("#link"); assert_eq!(link.length(), 1); assert_eq!(link.filter("#lang #link").length(), 1); // nested let link = root.find("#lang #link"); assert_eq!(link.length(), 1); // limit parent let link = root.find("nav #link"); assert_eq!(link.length(), 1); // not found let link = root.find("#none #link"); assert_eq!(link.length(), 0); Ok(()) } #[test] fn test_class_selector() -> Result { let html = r##" "##; let root = Vis::load(html)?; let lang = root.find("#lang"); assert_eq!(lang.find(".link").length(), 2); assert_eq!(lang.find(".en").length(), 2); assert_eq!(lang.find(".en.link").length(), 1); assert_eq!(lang.find("a.link[class|='en']").length(), 1); Ok(()) } #[test] fn test_tagname_selector() -> Result { // ignore tag name cases let html = r##"
"##; let root = Vis::load(html)?; let div = root.find("div"); assert_eq!(div.length(), 1); assert_eq!(div.get(0).unwrap().tag_name(), "DIV"); // tagname with namespace let html = r##" "##; let root = Vis::load(html)?; let item = root.find("FORM\\:ITEM"); assert_eq!(item.length(), 1); assert_eq!(item.get(0).unwrap().tag_name(), "FORM:ITEM"); Ok(()) } #[test] fn test_selector_pseudo_checked() -> Result { // normal select let html = r#""#; let root = Vis::load(html)?; let select = root.find("select"); let options = select.find("option"); assert_eq!(options.length(), 3); let selected_options = options.filter(":checked"); assert_eq!(selected_options.length(), 1); assert_eq!(selected_options.val().to_string(), "1"); let selected_options = root.find("select > option:checked"); assert_eq!(selected_options.length(), 1); assert_eq!(selected_options.val().to_string(), "1"); let selected_options = select.find(":checked"); assert_eq!(selected_options.length(), 1); assert_eq!(selected_options.val().to_string(), "1"); // normal select let html = r#""#; let root = Vis::load(html)?; let select = root.find("select"); let options = select.find("option"); assert_eq!(options.length(), 3); let selected_options = options.filter(":checked"); assert_eq!(selected_options.length(), 0); // normal select let html = r#""#; let root = Vis::load(html)?; let select = root.find("select"); let options = select.find("option"); assert_eq!(options.length(), 3); let selected_options = options.filter(":checked"); assert_eq!(selected_options.length(), 1); assert_eq!(selected_options.val().to_string(), "3"); // normal select let html = r#""#; let root = Vis::load(html)?; let select = root.find("select"); let options = select.find("option"); assert_eq!(options.length(), 4); let selected_options = options.filter(":checked"); assert_eq!(selected_options.length(), 1); assert_eq!(selected_options.val().to_string(), "0"); // normal select let html = r#""#; let root = Vis::load(html)?; let select = root.find("select"); let options = select.find("option"); assert_eq!(options.length(), 4); let selected_options = options.filter(":checked"); assert_eq!(selected_options.length(), 1); assert_eq!(selected_options.val().to_string(), "3"); // multiple select let html = r#""#; let root = Vis::load(html)?; let select = root.find("select"); let options = select.find("option"); assert_eq!(options.length(), 3); let selected_options = options.filter(":checked"); assert_eq!(selected_options.length(), 0); // multiple select let html = r#""#; let root = Vis::load(html)?; let select = root.find("select"); let options = select.find("option"); assert_eq!(options.length(), 3); let selected_options = options.filter(":checked"); assert_eq!(selected_options.length(), 2); assert_eq!( selected_options .map(|_, ele| ele.value().to_string()) .join(","), "2,3" ); // input type radio let html = r#""#; let root = Vis::load(html)?; let radios = root.find("input[name='radioinput']"); assert_eq!(radios.length(), 3); let selected_radio = radios.filter(":checked"); assert_eq!(selected_radio.length(), 1); assert_eq!(selected_radio.val().to_string(), "3"); // input type checkbox let html = r#""#; let root = Vis::load(html)?; let chkbox = root.find("input[name='chkbox']"); assert_eq!(chkbox.length(), 3); let selected_chkbox = chkbox.filter(":checked"); assert_eq!(selected_chkbox.length(), 2); assert_eq!( selected_chkbox .map(|_, ele| ele.value().to_string()) .join(","), "2,3" ); Ok(()) } #[test] fn test_selector_pseudo_header() -> Result { let html = r#"

"#; let root = Vis::load(html)?; let hgroups = root.find(":header"); assert_eq!(hgroups.length(), 1); let not_hgroups = root.find(":not(:header)"); assert_eq!(not_hgroups.length(), 1); Ok(()) } #[test] fn test_selector_pseudo_root() -> Result { let html = r#"

abc

"#; let root = Vis::load(html)?; // non html document, root is empty let html_element = root.find(":root"); assert_eq!(html_element.length(), 0); // html document let html = r#""#; let root = Vis::load(html)?; let html_element = root.find(":root"); assert_eq!(html_element.length(), 1); assert_eq!(html_element.get(0).unwrap().tag_name(), "HTML"); // html document let html_element = root.find("html:root"); assert_eq!(html_element.length(), 1); assert_eq!(html_element.get(0).unwrap().tag_name(), "HTML"); Ok(()) } #[test] fn test_selector_pseudo_empty() -> Result { let html = r#"

abc

"#; let root = Vis::load(html)?; // empty let empty = root.find(":empty"); assert_eq!(empty.length(), 2); Ok(()) } #[test] fn test_selector_pseudo_contains() -> Result { let html = r#"

abc

a&
"#; let root = Vis::load(html)?; // has 'a' let text_a = root.find(":contains('a')"); assert_eq!(text_a.length(), 2); // 'b' let text_b = root.find(":contains('b')"); assert_eq!(text_b.length(), 1); // escape ; let text_escape = root.find(":contains(\"&\")"); assert_eq!(text_escape.length(), 1); // more let html = r##"

Visdom

Visdom!

Vis dom!

"##; let root = Vis::load(html)?; let content = root.find("#content"); assert_eq!(content.find("p:contains('Visdom')").length(), 2); // npsp;   space: assert_eq!(content.find("p:contains(\"Vis dom\")").length(), 0); // no quote assert_eq!(content.find("p:contains(Visdom)").length(), 2); // contains empty assert_eq!( content.find("p:contains()").length(), content.find("p").length() ); // contains chinese characters let html = r#"

Visdom is awesome

Visdom 很好用

"#; let root = Vis::load(html)?; assert_eq!(root.find("p:contains('好用')").length(), 1); Ok(()) } #[test] fn test_selector_pseudo_only_child() -> Result { let html = r#" :only-child "#; let root = Vis::load(html)?; // :only-child let only_child = root.find("li:only-child"); assert_eq!(only_child.length(), 2); assert!(only_child.eq(0).parent("").is(".list1")); assert!(only_child.eq(1).parent("").is(".list3")); Ok(()) } #[test] fn test_selector_pseudo_first_child() -> Result { let html = r#" :first-child "#; let root = Vis::load(html)?; // :first-child let first_child = root.find("li:first-child"); assert_eq!(first_child.length(), 1); assert_eq!(first_child.text(), "item1"); // prev :first-child let prev_first_child = first_child.prev_all(":first-child"); assert_eq!(prev_first_child.length(), 0); // next :first-child let next_first_child = first_child.next_all(":first-child"); assert_eq!(next_first_child.length(), 0); // nested let html = r#" :first-child "#; let root = Vis::load(html)?; let list = root.find("ul.list"); let items = list.find("li:first-child"); assert_eq!(items.length(), 3); let items_first_name = items.eq(0).attr("name"); let items_second_name = items.eq(1).attr("name"); let items_third_name = items.eq(2).attr("name"); assert!(items_first_name.is_some() && items_first_name.unwrap().is_str("item-1")); assert!(items_second_name.is_some() && items_second_name.unwrap().is_str("item-1-sub-item-1")); assert!(items_third_name.is_some() && items_third_name.unwrap().is_str("item-2-sub-item-1")); Ok(()) } #[test] fn test_selector_pseudo_last_child() -> Result { let html = r#" :last-child "#; let root = Vis::load(html)?; // :last-child let last_child = root.find("li:last-child"); assert_eq!(last_child.length(), 1); assert_eq!(last_child.text(), "item9"); // prev :first-child let prev_last_child = last_child.prev_all(":last-child"); assert_eq!(prev_last_child.length(), 0); // next :first-child let next_last_child = last_child.next_all(":last-child"); assert_eq!(next_last_child.length(), 0); Ok(()) } #[test] fn test_selector_pseudo_nth_child() -> Result { let html = r#" :nth-child "#; let root = Vis::load(html)?; let ul = root.find("ul"); // :nth-child(0) let child = ul.find(":nth-child(0)"); assert_eq!(child.length(), 0); // :nth-child(-2n + 3) let child = ul.find(":nth-child(-2n + 3)"); assert_eq!(child.length(), 2); assert_eq!(child.text(), "item1item3"); // :nth-child(1) let child = ul.find(":nth-child(1)"); assert_eq!(child.length(), 1); assert_eq!(child.text(), "item1"); let child = ul.children(":nth-child(10)"); assert_eq!(child.length(), 0); // :nth-child(odd) let odd_childs = ul.find(":nth-child(odd)"); assert_eq!(odd_childs.length(), 5); assert_eq!(odd_childs.text(), "item1item3item5item7item9"); // :nth-child(even) let even_childs = ul.find(":nth-child( even )"); assert_eq!(even_childs.length(), 4); assert_eq!(even_childs.text(), "item2item4item6item8"); // :nth-child(3n) let childs_3n = ul.find(":nth-child(3n)"); assert_eq!(childs_3n.length(), 3); assert_eq!(childs_3n.text(), "item3item6item9"); // group selector let nth_group_child = ul.find(":nth-child(2n),:nth-child(10),:nth-child(1),:nth-child(n+8)"); assert_eq!(nth_group_child.length(), 6); // filter let childs_3n_2n = childs_3n.filter(":nth-child(2n)"); assert_eq!(childs_3n_2n.length(), 1); assert_eq!(childs_3n_2n.text(), "item6"); // group selector let html = format!("", "
  • ".repeat(3000)); let root = Vis::load(&html)?; let ul = root.find("ul"); let nth_group_child = ul.find(":nth-child(6n),:nth-child(3n),:nth-child(2n)"); assert_eq!( nth_group_child.length(), ul.find(":nth-child(2n),:nth-child(3n)").length() ); Ok(()) } #[test] fn test_selector_pseudo_nth_last_child() -> Result { let html = r#" :nth-last-child "#; let root = Vis::load(html)?; let ul = root.find("ul"); // :nth-last-child(1) let child = ul.children(":nth-last-child(1)"); assert_eq!(child.length(), 1); assert_eq!(child.text(), "item9"); // :nth-last-child(odd) let odd_last_childs = ul.find(":nth-last-child(odd)"); assert_eq!(odd_last_childs.length(), 5); assert_eq!(odd_last_childs.text(), "item1item3item5item7item9"); // :nth-last-child(3n) let childs_last_3n = ul.find(":nth-last-child(3n)"); assert_eq!(childs_last_3n.length(), 3); assert_eq!(childs_last_3n.text(), "item1item4item7"); // :nth-last-child(3n):nth-last-child(2n) let childs_last_3n_2n = childs_last_3n.filter(":nth-last-child(2n)"); assert_eq!(childs_last_3n_2n.length(), 1); assert_eq!(childs_last_3n_2n.text(), "item4"); Ok(()) } #[test] fn test_selector_pseudo_only_of_type() -> Result { let html = r#" :only-of-type
    only strong This is span1, this is a only b, this is another span2
    "#; let root = Vis::load(html)?; let content = root.find("#content"); // :only-of-type let only_of_type = content.find(":only-of-type"); assert_eq!(only_of_type.length(), 2); assert_eq!(only_of_type.text(), "only strongonly b"); // prev_all let prevs_only_of_type = content.find("b").prev_all(":only-of-type"); assert_eq!(prevs_only_of_type.length(), 1); assert_eq!(prevs_only_of_type.text(), "only strong"); Ok(()) } #[test] fn test_selector_pseudo_first_of_type() -> Result { let html = r#" :first-of-type
    dt1
    dd1
    dd2
    dd3
    dt2
    dd4
    dt3
    dd5
    dd6
    "#; let root = Vis::load(html)?; let dl = root.find("dl"); // :first-of-type let type_child = dl.find(":first-of-type"); assert_eq!(type_child.length(), 2); assert_eq!(type_child.text(), "dt1dd1"); // prevs let type_child_prevs = type_child.prev_all(":first-of-type"); assert_eq!(type_child_prevs.length(), 1); assert_eq!(type_child_prevs.text(), "dt1"); // nexts let type_child_nexts = type_child.next_all(":first-of-type"); assert_eq!(type_child_nexts.length(), 1); assert_eq!(type_child_nexts.text(), "dd1"); Ok(()) } #[test] fn test_selector_pseudo_last_of_type() -> Result { let html = r#" :last-of-type
    dt1
    dd1
    dd2
    dd3
    dt2
    dd4
    dt3
    dd5
    dd6
    "#; let root = Vis::load(html)?; let dl = root.find("dl"); // :last-of-type let type_child = dl.find(":last-of-type"); assert_eq!(type_child.length(), 2); assert_eq!(type_child.text(), "dt3dd6"); // prevs let type_child_prevs = type_child.prev_all(":last-of-type"); assert_eq!(type_child_prevs.length(), 1); assert_eq!(type_child_prevs.text(), "dt3"); // nexts let type_child_nexts = type_child.next_all(":last-of-type"); assert_eq!(type_child_nexts.length(), 1); assert_eq!(type_child_nexts.text(), "dd6"); Ok(()) } #[test] fn test_selector_pseudo_nth_of_type() -> Result { let html = r#" :nth-of-type
    dt1
    dd1
    dd2
    dd3
    dt2
    dd4
    dt3
    dd5
    dd6
    "#; let root = Vis::load(html)?; let dl = root.find("dl"); // :nth-of-type(0) let type_child = dl.children(":nth-of-type(0)"); assert_eq!(type_child.length(), 0); // :nth-of-type(1) let type_child = dl.find(":nth-of-type(1)"); assert_eq!(type_child.length(), 2); assert_eq!(type_child.text(), "dt1dd1"); // :nth-of-type(odd) let odd_type_childs = dl.find(":nth-of-type(odd)"); assert_eq!(odd_type_childs.length(), 5); assert_eq!(odd_type_childs.text(), "dt1dd1dd3dt3dd5"); // :nth-of-type(3n) let childs_type_3n = dl.find(":nth-of-type(3n)"); assert_eq!(childs_type_3n.length(), 3); assert_eq!(childs_type_3n.text(), "dd3dt3dd6"); // :nth-of-type(3n):nth-of-type(2n) let childs_type_3n_2n = childs_type_3n.filter(":nth-of-type(2n)"); assert_eq!(childs_type_3n_2n.length(), 1); assert_eq!(childs_type_3n_2n.text(), "dd6"); // prevs let childs_type_3n_2n_prevs = childs_type_3n_2n.prev_all(":nth-of-type(3n)"); assert_eq!(childs_type_3n_2n_prevs.length(), 2); assert_eq!(childs_type_3n_2n_prevs.text(), "dd3dt3"); Ok(()) } #[test] fn test_selector_pseudo_nth_last_of_type() -> Result { let html = r#" :nth-last-of-type
    dt1
    dd1
    dd2
    dd3
    dt2
    dd4
    dt3
    dd5
    dd6
    "#; let root = Vis::load(html)?; let dl = root.find("dl"); // :nth-last-of-type(1) let last_type_child = dl.find(":nth-last-of-type(1)"); assert_eq!(last_type_child.length(), 2); assert_eq!(last_type_child.text(), "dt3dd6"); // :nth-last-of-type(odd) let last_odd_type_childs = dl.find(":nth-last-of-type(odd)"); assert_eq!(last_odd_type_childs.length(), 5); assert_eq!(last_odd_type_childs.text(), "dt1dd2dd4dt3dd6",); // :nth-last-of-type(3n) let childs_type_last_3n = dl.find(":nth-last-of-type(3n)"); assert_eq!(childs_type_last_3n.length(), 3); assert_eq!(childs_type_last_3n.text(), "dt1dd1dd4"); // :nth-last-of-type(3n):nth-last-of-type(2n) let childs_type_last_3n_2n = childs_type_last_3n.filter(":nth-last-of-type(2n)"); assert_eq!(childs_type_last_3n_2n.length(), 1); assert_eq!(childs_type_last_3n_2n.text(), "dd1"); // prevs let childs_type_last_3n_2n_prevs = childs_type_last_3n_2n.prev_all(":nth-last-of-type(3n)"); assert_eq!(childs_type_last_3n_2n_prevs.length(), 1); assert_eq!(childs_type_last_3n_2n_prevs.text(), "dt1"); // nexts let childs_type_last_3n_2n_nests = childs_type_last_3n_2n.next_all(":nth-last-of-type(3n)"); assert_eq!(childs_type_last_3n_2n_nests.length(), 1); assert_eq!(childs_type_last_3n_2n_nests.text(), "dd4"); Ok(()) } #[test] fn test_selector_pseudo_not() -> Result { let html = r#" :not
    dt1
    dd1
    dd2
    dd3
    dt2
    dd4
    dt3
    dd5
    dd6
    "#; let root = Vis::load(html)?; let dl = root.find("dl"); // not dt let not_dt = dl.children(":not(dt)"); assert_eq!(not_dt.length(), 6); // not dt and dd let not_dt_dd = dl.children(":not(dt,dd)"); assert_eq!(not_dt_dd.length(), 0); // not dt and dd let not_dt_dd = dl.children(":not(dt,:not(dt))"); assert_eq!(not_dt_dd.length(), 0); // not dt let not_dt_first = dl.children(":not(dt:nth-child(-n + 1))"); assert_eq!(not_dt_first.length(), 8); assert_eq!(not_dt_first.eq(0).text(), "dd1"); Ok(()) } #[test] fn test_selector_pseudo_has() -> Result { let html = r#"

    1

    2
    3

    4

    "#; let root = Vis::load(html)?; let container = root.find("#container"); assert_eq!(container.length(), 1); // div not has a let div_no_has_p = container.children("div:not(:has(p))"); assert_eq!(div_no_has_p.length(), 2); assert_eq!(div_no_has_p.text(), "23"); // divs let divs = container.children("div"); // has p let div_has_p = divs.has("p"); assert_eq!(div_has_p.length(), 2); assert_eq!(div_has_p.text(), "14"); // has no p let div_no_has_p = divs.not(":has(p)"); assert_eq!(div_no_has_p.length(), 2); assert_eq!(div_no_has_p.text(), "23"); Ok(()) } #[test] fn test_wrong_selector_splitter() -> Result { let root = Vis::load("anything")?; assert!(root.find(">,").is_empty()); Ok(()) } #[test] fn test_wrong_selector_empty_start() -> Result { let root = Vis::load("anything")?; assert!(root.find(",b").is_empty()); Ok(()) } #[test] fn test_wrong_selector_empty_end() -> Result { let root = Vis::load("anything")?; assert!(root.find("b,").is_empty()); Ok(()) } #[test] fn test_wrong_selector_wrong_nested() { let root = Vis::load("anything").unwrap(); assert!(root.find(":not(:not(:a)").is_empty()); }