//! Script element loading and execution. //! //! Walks the DOM for ` "#; let doc = run_scripts(html); // Find the div and check its text content was modified. let mut found = false; fn find_div(doc: &Document, node: NodeId, found: &mut bool) { if doc.tag_name(node) == Some("div") { if doc.get_attribute(node, "id") == Some("target") { // Check child text node. for child in doc.children(node) { if let Some(text) = doc.text_content(child) { if text == "after" { *found = true; } } } } } for child in doc.children(node) { find_div(doc, child, found); } } find_div(&doc, doc.root(), &mut found); assert!(found, "script should have modified div text to 'after'"); } #[test] fn test_multiple_scripts_share_scope() { let html = r#"
placeholder
"#; let doc = run_scripts(html); fn find_result(doc: &Document, node: NodeId) -> Option { if doc.tag_name(node) == Some("div") { if doc.get_attribute(node, "id") == Some("result") { for child in doc.children(node) { if let Some(text) = doc.text_content(child) { return Some(text.to_string()); } } } } for child in doc.children(node) { if let Some(result) = find_result(doc, child) { return Some(result); } } None } let result = find_result(&doc, doc.root()); assert_eq!(result.as_deref(), Some("43")); } #[test] fn test_unknown_type_not_executed() { let html = r#"
original
"#; let doc = run_scripts(html); fn find_target(doc: &Document, node: NodeId) -> Option { if doc.tag_name(node) == Some("div") { if doc.get_attribute(node, "id") == Some("target") { for child in doc.children(node) { if let Some(text) = doc.text_content(child) { return Some(text.to_string()); } } } } for child in doc.children(node) { if let Some(result) = find_target(doc, child) { return Some(result); } } None } let result = find_target(&doc, doc.root()); assert_eq!(result.as_deref(), Some("original")); } #[test] fn test_type_text_javascript_executes() { let html = r#"
before
"#; let doc = run_scripts(html); fn find_target(doc: &Document, node: NodeId) -> Option { if doc.tag_name(node) == Some("div") { if doc.get_attribute(node, "id") == Some("target") { for child in doc.children(node) { if let Some(text) = doc.text_content(child) { return Some(text.to_string()); } } } } for child in doc.children(node) { if let Some(result) = find_target(doc, child) { return Some(result); } } None } let result = find_target(&doc, doc.root()); assert_eq!(result.as_deref(), Some("after")); } #[test] fn test_script_error_does_not_crash() { // A script with a runtime error should not prevent subsequent scripts. let html = r#"
before
"#; let doc = run_scripts(html); fn find_target(doc: &Document, node: NodeId) -> Option { if doc.tag_name(node) == Some("div") { if doc.get_attribute(node, "id") == Some("target") { for child in doc.children(node) { if let Some(text) = doc.text_content(child) { return Some(text.to_string()); } } } } for child in doc.children(node) { if let Some(result) = find_target(doc, child) { return Some(result); } } None } let result = find_target(&doc, doc.root()); assert_eq!(result.as_deref(), Some("after")); } #[test] fn test_empty_script_no_crash() { let doc = run_scripts(""); assert!(!doc.is_empty()); } #[test] fn test_defer_scripts_run_after_sync() { // In our parse-first model, both sync and defer run after parsing. // defer scripts with src are queued; defer inline scripts are treated // as sync. Without external script loading in tests, we verify that // defer inline scripts still execute (treated as sync per spec — // defer only applies to external scripts). let html = r#"
0
"#; let doc = run_scripts(html); fn find_result(doc: &Document, node: NodeId) -> Option { if doc.tag_name(node) == Some("div") { if doc.get_attribute(node, "id") == Some("result") { for child in doc.children(node) { if let Some(text) = doc.text_content(child) { return Some(text.to_string()); } } } } for child in doc.children(node) { if let Some(result) = find_result(doc, child) { return Some(result); } } None } let result = find_result(&doc, doc.root()); // defer on inline scripts is ignored per spec, so counter=1 runs first assert_eq!(result.as_deref(), Some("1")); } #[test] fn test_script_create_element() { let html = r#"
"#; let doc = run_scripts(html); // Check that a

was added inside #container. fn find_dynamic(doc: &Document, node: NodeId) -> bool { if doc.tag_name(node) == Some("div") { if doc.get_attribute(node, "id") == Some("container") { for child in doc.children(node) { if doc.tag_name(child) == Some("p") { return true; } } } } for child in doc.children(node) { if find_dynamic(doc, child) { return true; } } false } assert!( find_dynamic(&doc, doc.root()), "script should have appended a

to #container" ); } }