diff --git a/crates/html-macro/Cargo.toml b/crates/html-macro/Cargo.toml index 7a7ede29..7f0126c8 100644 --- a/crates/html-macro/Cargo.toml +++ b/crates/html-macro/Cargo.toml @@ -15,4 +15,4 @@ proc-macro = true [dependencies] proc-macro2 = "0.4" quote = "0.6.11" -syn = { version = "0.15", features = ["full", "extra-traits"] } +syn = { version = "0.15", features = ["full", "extra-traits"] } \ No newline at end of file diff --git a/crates/virtual-dom-rs/src/diff/mod.rs b/crates/virtual-dom-rs/src/diff/mod.rs index 5174ca06..3d1cf13f 100644 --- a/crates/virtual-dom-rs/src/diff/mod.rs +++ b/crates/virtual-dom-rs/src/diff/mod.rs @@ -264,21 +264,6 @@ mod tests { .test(); } - // https://github.com/chinedufn/percy/issues/62 - #[test] - fn issue_62() { - DiffTestCase { - old: html! {
}, - new: html! { a
}, - expected: vec![ - Patch::Replace(1, &VirtualNode::text("a")), - Patch::AppendChildren(0, vec![&VirtualNode::new("br")]), - ], - description: "Replace text node", - } - .test(); - } - // // TODO: Key support // #[test] // fn reorder_chldren() { diff --git a/crates/virtual-dom-rs/src/patch.rs b/crates/virtual-dom-rs/src/patch.rs index 444353e7..d53f03fc 100644 --- a/crates/virtual-dom-rs/src/patch.rs +++ b/crates/virtual-dom-rs/src/patch.rs @@ -188,8 +188,13 @@ fn apply_element_patch(node: &Element, patch: &Patch) { } } Patch::Replace(_node_idx, new_node) => { - node.replace_with_with_node_1(&new_node.create_element()) - .expect("Replaced element"); + if new_node.is_text_node() { + node.replace_with_with_node_1(&new_node.create_text_node()) + .expect("Replaced with text node"); + } else { + node.replace_with_with_node_1(&new_node.create_element()) + .expect("Replaced with element"); + } } Patch::TruncateChildren(_node_idx, num_children_remaining) => { let children = node.child_nodes(); diff --git a/crates/virtual-dom-rs/tests/diff_patch.rs b/crates/virtual-dom-rs/tests/diff_patch.rs index 87ee31f3..3e401cb8 100644 --- a/crates/virtual-dom-rs/tests/diff_patch.rs +++ b/crates/virtual-dom-rs/tests/diff_patch.rs @@ -92,7 +92,6 @@ fn text_node_siblings() { // @see virtual_node/mod.rs -> create_element() for more information let override_expected = Some( r#"
The button has been clicked: world
"# - .to_string(), ); let old1 = VirtualNode::text("The button has been clicked: "); @@ -155,13 +154,13 @@ fn replace_with_children() { } // https://github.com/chinedufn/percy/issues/62 -//#[wasm_bindgen_test] -//fn issue_62() { -// DiffPatchTest { -// desc: "Fix issue #62", -// old: html! {
}, -// new: html! { a
}, -// override_expected: None, -// } -// .test(); -//} +#[wasm_bindgen_test] +fn replace_element_with_text_node() { + DiffPatchTest { + desc: "#62: Replace element with text node", + old: html! {
}, + new: html! { a }, + override_expected: None + } + .test(); +} diff --git a/crates/virtual-dom-rs/tests/diff_patch_test_case/mod.rs b/crates/virtual-dom-rs/tests/diff_patch_test_case/mod.rs index 7ddecf96..21b0477f 100644 --- a/crates/virtual-dom-rs/tests/diff_patch_test_case/mod.rs +++ b/crates/virtual-dom-rs/tests/diff_patch_test_case/mod.rs @@ -8,14 +8,14 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; /// A test case that both diffing and patching are working in a real browser -pub struct DiffPatchTest { +pub struct DiffPatchTest<'a> { pub desc: &'static str, pub old: VirtualNode, pub new: VirtualNode, - pub override_expected: Option, + pub override_expected: Option<&'a str>, } -impl DiffPatchTest { +impl<'a> DiffPatchTest<'a> { pub fn test(&mut self) { console_error_panic_hook::set_once(); @@ -49,14 +49,19 @@ impl DiffPatchTest { virtual_dom_rs::patch(root_node, &patches); - let expected_new_root_node = match self.override_expected { - Some(ref expected) => expected.clone(), - None => self.new.to_string(), - }; + let expected_new_root_node = self.new.to_string(); + let mut expected_new_root_node = expected_new_root_node.as_str(); + + if let Some(ref expected) = self.override_expected { + expected_new_root_node = expected; + } + + web_sys::console::log_1(&format!("NEW NODE {:#?}", patched_element.outer_html()).into()); + web_sys::console::log_1(&format!("Outter HTML {:#?}", expected_new_root_node).into()); assert_eq!( - patched_element.outer_html(), - expected_new_root_node, + &patched_element.outer_html(), + &expected_new_root_node, "{}", self.desc ); diff --git a/crates/virtual-node/src/lib.rs b/crates/virtual-node/src/lib.rs index 59066376..092be31c 100644 --- a/crates/virtual-node/src/lib.rs +++ b/crates/virtual-node/src/lib.rs @@ -10,7 +10,7 @@ // Around in order to get rid of dependencies that we don't need in non wasm32 targets pub use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashSet,HashMap}; use std::fmt; pub use std::rc::Rc; @@ -28,12 +28,28 @@ use lazy_static::lazy_static; use std::ops::Deref; use std::sync::Mutex; + // Used to uniquely identify elements that contain closures so that the DomUpdater can // look them up by their unique id. // When the DomUpdater sees that the element no longer exists it will drop all of it's // Rc'd Closures for those events. lazy_static! { static ref ELEM_UNIQUE_ID: Mutex = Mutex::new(0); + + static ref SELF_CLOSING_TAGS: HashSet<&'static str> = { + let mut set = HashSet::new(); + + let mut self_closing = vec![ + "area", "base", "br", "col", "hr", "img", "input", "link", "meta", "param", "command", + "keygen", "source", + ]; + + for tag in self_closing { + set.insert(tag); + } + + set + }; } /// When building your views you'll typically use the `html!` macro to generate @@ -233,6 +249,11 @@ impl VirtualNode { pub fn is_text_node(&self) -> bool { self.text.is_some() } + + /// Whether or not this is a self closing tag such as
or + pub fn is_self_closing(&self) -> bool { + SELF_CLOSING_TAGS.contains(self.tag.as_str()) + } } impl From<&str> for VirtualNode { @@ -288,7 +309,12 @@ impl fmt::Display for VirtualNode { for child in self.children.as_ref().unwrap().iter() { write!(f, "{}", child.to_string())?; } - write!(f, "", self.tag) + + if !self.is_self_closing() { + write!(f, "", self.tag)?; + } + + Ok(()) } } } @@ -320,6 +346,14 @@ impl fmt::Debug for Events { mod tests { use super::*; + #[test] + fn self_closing_tag_to_string() { + let node = VirtualNode::new("br"); + + // No
since self closing tag + assert_eq!(&node.to_string(), "
"); + } + // TODO: Use html_macro as dev dependency and uncomment // #[test] // fn to_string() {