//! Regression test: a Hacker-News-shaped nested `
` layout must come out
//! right using only the general engine (UA defaults + real CSS cascade), with
//! no per-site hardcoded selectors. This guards against reintroducing the
//! site-specific hacks that used to live in obscura-render for this exact markup.
use obscura_dom::tree::NodeData;
use obscura_dom::tree_sink::parse_html;
use obscura_render::layout_dom;
const HN_HTML: &str = r##"
"##;
fn find_by_text<'a>(
tree: &'a obscura_dom::tree::DomTree,
layout: &'a obscura_render::DomLayout,
needle: &str,
) -> Option<(obscura_dom::tree::NodeId, &'a obscura_render::Rect)> {
for (id, rect) in &layout.rects {
if let Some(node) = tree.get_node(*id) {
if let NodeData::Text { contents } = &node.data {
if contents.trim() == needle {
return Some((*id, rect));
}
}
}
}
None
}
#[test]
fn hn_shaped_table_lays_out_without_site_hardcoding() {
let tree = parse_html(HN_HTML);
let layout = layout_dom(&tree, (1000.0, 1000.0));
// Every element got a rect; the tree isn't just being dropped.
assert!(layout.rects.len() > 10, "expected many laid-out elements, got {}", layout.rects.len());
// "Hacker News" (a bold link in the top bar) sits above the first
// headline row ("Exapunks (2018)"): normal top-to-bottom flow, not a
// hardcoded absolute position.
let (_, brand_rect) = find_by_text(&tree, &layout, "Hacker News").expect("brand text laid out");
let (_, headline_rect) = find_by_text(&tree, &layout, "Exapunks (2018)").expect("headline text laid out");
assert!(
headline_rect.y > brand_rect.y,
"headline should be below the header bar: brand.y={} headline.y={}",
brand_rect.y,
headline_rect.y
);
// Within the header row, "login" (right-aligned cell) sits to the right
// of "Hacker News" (left cell) — plain flex/table layout, not a magic
// per-class x-offset.
let (_, login_rect) = find_by_text(&tree, &layout, "login").expect("login text laid out");
assert!(
login_rect.x > brand_rect.x,
"login cell should be right of the brand: brand.x={} login.x={}",
brand_rect.x,
login_rect.x
);
}