use rust_scrapling::parser::selector_generation::{generate_css_selector, generate_xpath_selector};
use rust_scrapling::parser::Selector;
const HTML: &str = r#"<html><body><div id="main"><ul><li class="item">First</li><li class="item">Second</li></ul><div><p>Nested</p></div></div></body></html>"#;
#[test]
fn test_css_selector_with_id_stops_at_id() {
let sel = Selector::from_html(HTML);
let div = sel.css("#main");
assert_eq!(div.len(), 1);
let css = generate_css_selector(&div[0], false);
assert!(
css.contains("[id=\"main\"]"),
"Expected attribute-form id selector in: {}",
css
);
assert_eq!(sel.css(&css).len(), 1);
}
#[test]
fn css_selector_handles_ids_that_are_not_css_identifiers() {
let html = r#"<html><body><div id="foo.bar:baz x">content</div></body></html>"#;
let sel = Selector::from_html(html);
let div = sel.css("div");
assert_eq!(div.len(), 1);
let css = generate_css_selector(&div[0], false);
assert_eq!(css, "[id=\"foo.bar:baz x\"]");
assert_eq!(
sel.css(&css).len(),
1,
"generated selector must be parseable and find the element"
);
let html = r#"<html><body><div id='he said "hi"'>q</div></body></html>"#;
let sel = Selector::from_html(html);
let div = sel.css("div");
let css = generate_css_selector(&div[0], false);
assert_eq!(css, "[id=\"he said \\\"hi\\\"\"]");
assert_eq!(sel.css(&css).len(), 1);
}
#[test]
fn test_css_selector_for_li_includes_nth_of_type() {
let sel = Selector::from_html(HTML);
let li = sel.css("li.item");
assert!(li.len() >= 2);
let css = generate_css_selector(&li[1], true);
assert!(
css.contains("nth-of-type"),
"Expected 'nth-of-type' in: {}",
css
);
}
#[test]
fn test_xpath_selector_with_id() {
let sel = Selector::from_html(HTML);
let div = sel.css("#main");
assert_eq!(div.len(), 1);
let xpath = generate_xpath_selector(&div[0], false);
assert!(
xpath.contains("@id='main'"),
"Expected \"@id='main'\" in: {}",
xpath
);
}
#[test]
fn test_full_css_selector_includes_body() {
let sel = Selector::from_html(HTML);
let div = sel.css("#main");
assert_eq!(div.len(), 1);
let css = generate_css_selector(&div[0], true);
assert!(
css.contains("body"),
"Expected 'body' in full path: {}",
css
);
}
#[test]
fn identical_siblings_get_distinct_nth_of_type_positions() {
let html = r#"<html><body><ul><li>Apple</li><li>Apple</li><li>Apple</li></ul></body></html>"#;
let sel = Selector::from_html(html);
let items = sel.css("li");
assert_eq!(items.len(), 3);
let css1 = generate_css_selector(&items[0], true);
let css2 = generate_css_selector(&items[1], true);
let css3 = generate_css_selector(&items[2], true);
assert!(css1.contains("nth-of-type(1)"), "got: {}", css1);
assert!(css2.contains("nth-of-type(2)"), "got: {}", css2);
assert!(css3.contains("nth-of-type(3)"), "got: {}", css3);
let xp1 = generate_xpath_selector(&items[0], true);
let xp2 = generate_xpath_selector(&items[1], true);
let xp3 = generate_xpath_selector(&items[2], true);
assert!(xp1.ends_with("li[1]"), "got: {}", xp1);
assert!(xp2.ends_with("li[2]"), "got: {}", xp2);
assert!(xp3.ends_with("li[3]"), "got: {}", xp3);
}
#[test]
fn xpath_selector_escapes_id_with_single_quote() {
let html = r#"<html><body><div id="foo' or '1'='1">x</div></body></html>"#;
let sel = Selector::from_html(html);
let div = sel.css("div");
assert_eq!(div.len(), 1);
let xp = generate_xpath_selector(&div[0], false);
assert!(
xp.contains("@id=\"foo' or '1'='1\""),
"expected double-quoted id literal, got: {}",
xp
);
}