This repository has been archived on 2026-08-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
el-retired/ui/crates/el-platform/src/backends/tests.rs
T

254 lines
11 KiB
Rust

//! Tests for el-platform backends.
#[cfg(test)]
mod tests {
use crate::{
backend_for, backends::{server::ServerBackend, web::WebBackend},
config::{PlatformConfig, PlatformTarget},
node::PlatformNode,
PlatformBackend,
};
// ── Test 1: PlatformTarget::from_str parses all targets ──────────────────
#[test]
fn test_platform_target_from_str() {
assert_eq!(PlatformTarget::from_str("web"), Some(PlatformTarget::Web));
assert_eq!(PlatformTarget::from_str("server"), Some(PlatformTarget::Server));
assert_eq!(PlatformTarget::from_str("ios"), Some(PlatformTarget::Ios));
assert_eq!(PlatformTarget::from_str("android"), Some(PlatformTarget::Android));
assert_eq!(PlatformTarget::from_str("macos"), Some(PlatformTarget::Macos));
assert_eq!(PlatformTarget::from_str("linux"), Some(PlatformTarget::Linux));
assert_eq!(PlatformTarget::from_str("windows"), Some(PlatformTarget::Windows));
assert_eq!(PlatformTarget::from_str("unknown"), None);
}
// ── Test 2: PlatformTarget::as_str round-trips ───────────────────────────
#[test]
fn test_platform_target_as_str() {
assert_eq!(PlatformTarget::Web.as_str(), "web");
assert_eq!(PlatformTarget::Server.as_str(), "server");
assert_eq!(PlatformTarget::Ios.as_str(), "ios");
}
// ── Test 3: is_native() identifies native targets ────────────────────────
#[test]
fn test_is_native() {
assert!(!PlatformTarget::Web.is_native());
assert!(!PlatformTarget::Server.is_native());
assert!(PlatformTarget::Ios.is_native());
assert!(PlatformTarget::Android.is_native());
assert!(PlatformTarget::Macos.is_native());
assert!(PlatformTarget::Linux.is_native());
assert!(PlatformTarget::Windows.is_native());
}
// ── Test 4: PlatformConfig defaults to web ───────────────────────────────
#[test]
fn test_platform_config_default() {
let cfg = PlatformConfig::default();
assert_eq!(cfg.target, PlatformTarget::Web);
assert!(!cfg.ssr);
}
// ── Test 5: PlatformConfig with_ssr ──────────────────────────────────────
#[test]
fn test_platform_config_with_ssr() {
let cfg = PlatformConfig::new(PlatformTarget::Server).with_ssr(true);
assert_eq!(cfg.target, PlatformTarget::Server);
assert!(cfg.ssr);
}
// ── Test 6: WebBackend renders element to HTML ───────────────────────────
#[test]
fn test_web_backend_renders_element() {
let backend = WebBackend::new();
let mut div = backend.create_element("div").unwrap();
backend.set_attribute(&mut div, "class", "container").unwrap();
backend.append_child(&mut div, backend.create_text("Hello").unwrap()).unwrap();
let html = backend.render_to_string(&div).unwrap();
assert!(html.contains("<div"), "should contain div tag");
assert!(html.contains("container"), "should contain class name");
assert!(html.contains("Hello"), "should contain text content");
assert!(html.contains("</div>"), "should close div tag");
}
// ── Test 7: ServerBackend supports SSR ───────────────────────────────────
#[test]
fn test_server_backend_supports_ssr() {
let backend = ServerBackend::new();
assert!(backend.supports_ssr());
}
// ── Test 8: ServerBackend renders full HTML page ─────────────────────────
#[test]
fn test_server_backend_render_page() {
let backend = ServerBackend::new();
let root = PlatformNode::element("div")
.with_attr("id", "content")
.with_child(PlatformNode::text("Hello World"));
let page = backend.render_page(&root, "My App", "/app.js").unwrap();
assert!(page.contains("<!DOCTYPE html>"), "should be full HTML doc");
assert!(page.contains("My App"), "should include title");
assert!(page.contains("Hello World"), "should include content");
assert!(page.contains("/app.js"), "should include script src");
}
// ── Test 9: PlatformNode::to_html renders nested tree ────────────────────
#[test]
fn test_platform_node_to_html_nested() {
let node = PlatformNode::element("ul")
.with_child(PlatformNode::element("li").with_child(PlatformNode::text("item 1")))
.with_child(PlatformNode::element("li").with_child(PlatformNode::text("item 2")));
let html = node.to_html();
assert!(html.contains("<ul>"));
assert!(html.contains("<li>item 1</li>"));
assert!(html.contains("<li>item 2</li>"));
assert!(html.contains("</ul>"));
}
// ── Test 10: PlatformNode::to_html escapes text content ──────────────────
#[test]
fn test_html_escaping() {
let node = PlatformNode::element("span")
.with_child(PlatformNode::text("<script>alert('xss')</script>"));
let html = node.to_html();
assert!(!html.contains("<script>"), "should escape <script>");
assert!(html.contains("&lt;script&gt;"), "should contain escaped form");
}
// ── Test 11: Void elements render correctly ───────────────────────────────
#[test]
fn test_void_elements() {
let node = PlatformNode::element("input").with_attr("type", "text");
let html = node.to_html();
assert!(html.contains("<input"), "should have input");
assert!(!html.contains("</input>"), "void element should not have closing tag");
assert!(html.contains("/>"), "should self-close");
}
// ── Test 12: Fragment node renders children inline ────────────────────────
#[test]
fn test_fragment_node() {
let frag = PlatformNode::fragment()
.with_child(PlatformNode::element("span").with_child(PlatformNode::text("A")))
.with_child(PlatformNode::element("span").with_child(PlatformNode::text("B")));
let html = frag.to_html();
assert!(html.contains("<span>A</span>"));
assert!(html.contains("<span>B</span>"));
// No wrapping element
assert!(!html.starts_with('<') || html.starts_with("<span>"));
}
// ── Test 13: WebBackend remove_child works ───────────────────────────────
#[test]
fn test_web_backend_remove_child() {
let backend = WebBackend::new();
let mut parent = PlatformNode::element("div");
backend
.append_child(&mut parent, PlatformNode::text("first"))
.unwrap();
backend
.append_child(&mut parent, PlatformNode::text("second"))
.unwrap();
assert_eq!(parent.children.len(), 2);
backend.remove_child(&mut parent, 0).unwrap();
assert_eq!(parent.children.len(), 1);
assert_eq!(parent.children[0].text_content(), Some("second"));
}
// ── Test 14: WebBackend replace_child works ──────────────────────────────
#[test]
fn test_web_backend_replace_child() {
let backend = WebBackend::new();
let mut parent = PlatformNode::element("div");
backend
.append_child(&mut parent, PlatformNode::text("old"))
.unwrap();
backend
.replace_child(&mut parent, 0, PlatformNode::text("new"))
.unwrap();
assert_eq!(parent.children[0].text_content(), Some("new"));
}
// ── Test 15: backend_for() returns correct backend names ─────────────────
#[test]
fn test_backend_for_names() {
assert_eq!(backend_for(&PlatformTarget::Web).name(), "web");
assert_eq!(backend_for(&PlatformTarget::Server).name(), "server");
assert_eq!(backend_for(&PlatformTarget::Ios).name(), "ios");
assert_eq!(backend_for(&PlatformTarget::Android).name(), "android");
assert_eq!(backend_for(&PlatformTarget::Macos).name(), "macos");
assert_eq!(backend_for(&PlatformTarget::Linux).name(), "linux");
assert_eq!(backend_for(&PlatformTarget::Windows).name(), "windows");
}
// ── Test 16: WebBackend bind_event emits data attribute ──────────────────
#[test]
fn test_web_backend_bind_event() {
let backend = WebBackend::new();
let mut btn = backend.create_element("button").unwrap();
backend
.bind_event(&mut btn, "click", Box::new(|_| {}))
.unwrap();
let has_attr = btn.attributes.iter().any(|a| a.name == "data-el-click");
assert!(has_attr, "should emit data-el-click attribute");
}
// ── Test 17: ServerBackend bind_event emits hydration marker ─────────────
#[test]
fn test_server_backend_bind_event() {
let backend = ServerBackend::new();
let mut btn = PlatformNode::element("button");
backend
.bind_event(&mut btn, "click", Box::new(|_| {}))
.unwrap();
let has_attr = btn.attributes.iter().any(|a| a.name.contains("data-el-click"));
assert!(has_attr, "should emit hydration marker for click event");
}
// ── Test 18: WebBackend backend does not support raw SSR flag ────────────
#[test]
fn test_web_backend_supports_ssr() {
// Web backend supports ssr (renders to HTML for hydration)
let backend = WebBackend::new();
assert!(backend.supports_ssr());
}
// ── Test 19: remove_child out of bounds returns error ────────────────────
#[test]
fn test_remove_child_out_of_bounds() {
let backend = WebBackend::new();
let mut parent = PlatformNode::element("div");
let result = backend.remove_child(&mut parent, 5);
assert!(result.is_err(), "out-of-bounds remove should return error");
}
// ── Test 20: All native backends render to HTML for testing ──────────────
#[test]
fn test_native_backends_render_to_html() {
// Native backends support render_to_string for testing and SSR fallback.
let targets = [
PlatformTarget::Ios,
PlatformTarget::Android,
PlatformTarget::Macos,
PlatformTarget::Linux,
PlatformTarget::Windows,
];
for target in &targets {
let backend = backend_for(target);
let node = PlatformNode::element("div")
.with_child(PlatformNode::text("test"));
let html = backend.render_to_string(&node).unwrap();
assert!(
html.contains("test"),
"{} backend should render text content",
target.as_str()
);
}
}
}