From 0bf7e06edda8ebb11a802f208d1893477d99228f Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 1 Mar 2019 01:43:45 +0200 Subject: [PATCH 1/8] Update wasm-bindgen-test --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bbe1bd2bb..93c5ae74f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,9 +16,10 @@ edition = "2018" crate-type = ["cdylib", "rlib"] [dev-dependencies] -wasm-bindgen-test = "^0.2.33" # NOTE: keep in sync with wasm-bindgen version +wasm-bindgen-test = "^0.2.37" # NOTE: keep in sync with wasm-bindgen version [dependencies] +# NOTE: keep in sync with wasm-bindgen-test version wasm-bindgen = {version = "^0.2.37", features = ["serde-serialize"]} js-sys = "0.3.6" console_error_panic_hook = "^0.1.5" From 73e2b9b700b02977be0030192243104e3d77c118 Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 1 Mar 2019 02:52:09 +0200 Subject: [PATCH 2/8] Fix some compilation warnings --- src/dom_types.rs | 6 +++--- src/lib.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/dom_types.rs b/src/dom_types.rs index 8ed5831a1..e4a344157 100644 --- a/src/dom_types.rs +++ b/src/dom_types.rs @@ -1303,11 +1303,11 @@ pub fn will_unmount(mut actions: impl FnMut(&web_sys::Node) + 'static) -> WillUn #[cfg(test)] pub mod tests { - use crate as seed; + // use crate as seed; // required for macros to work. // use crate::prelude::*; - use super::*; - use crate::{attrs, div, h1, p, section, span}; + // use super::*; + // use crate::{attrs, div, h1, p, section, span}; //use wasm_bindgen_test::*; // todo suddenly error about undec type/mod //use wasm_bindgen_test::wasm_bindgen_test_configure; diff --git a/src/lib.rs b/src/lib.rs index 1b11c4984..e9d747895 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,7 +109,7 @@ pub mod tests { use crate::prelude::*; use crate::{ div, - dom_types::{El, At, UpdateEl, mouse_ev}, + dom_types::{El, UpdateEl, mouse_ev}, vdom::Update, }; @@ -134,15 +134,15 @@ pub mod tests { } } - fn view(_state: seed::App, model: &Model) -> El { + fn view(_state: seed::App, _model: &Model) -> El { div!["Hello world"] } - fn window_events(model: &Model) -> Vec> { + fn window_events(_model: &Model) -> Vec> { vec![mouse_ev("mousemove", |_| Msg::Increment)] } - fn routes(url: &seed::Url) -> Msg { + fn routes(_url: &seed::Url) -> Msg { Msg::Increment } From 14d1987173c24129a2b4d350d10d87f7e89f7355 Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 1 Mar 2019 01:42:47 +0200 Subject: [PATCH 3/8] Implement el_added test --- src/vdom.rs | 74 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/src/vdom.rs b/src/vdom.rs index 7ab2e5ace..6fe271905 100644 --- a/src/vdom.rs +++ b/src/vdom.rs @@ -361,7 +361,7 @@ impl App { /// Populate the attached web_sys elements, ids, and nest-levels. Run this after creating a vdom, but before /// using it to process the web_sys dom. Does not attach children in the DOM. Run this on the top-level element. -pub fn setup_els(document: &Document, el_vdom: &mut El, active_level: u32, active_id: u32) +pub(crate) fn setup_els(document: &Document, el_vdom: &mut El, active_level: u32, active_id: u32) // pub for tests. where Ms: Clone + 'static, @@ -719,57 +719,69 @@ pub trait DomElLifecycle { #[cfg(test)] pub mod tests { - use wasm_bindgen_test::wasm_bindgen_test_configure; + use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); use super::*; - use wasm_bindgen_test::*; use crate as seed; // required for macros to work. use crate::{div, li, prelude::*}; - #[derive(Clone)] + #[derive(Clone, Debug)] enum Msg {} - #[ignore] - // #[wasm_bindgen_test] - #[test] + #[wasm_bindgen_test] fn el_added() { - let mut old_vdom: El = div!["text", vec![li!["child1"],]]; - let mut new_vdom: El = div!["text", vec![li!["child1"], li!["child2"]]]; + let mailbox = Mailbox::new(|_msg: Msg| {}); let doc = util::document(); - let old_ws = doc.create_element("div").unwrap(); - let new_ws = doc.create_element("div").unwrap(); + let parent = doc.create_element("div").unwrap(); - let child1 = doc.create_element("li").unwrap(); - let child2 = doc.create_element("li").unwrap(); - // TODO: make this match how you're setting text_content, eg could - // TODO: be adding a text node. - old_ws.set_text_content(Some("text")); - child1.set_text_content(Some("child1")); - child2.set_text_content(Some("child2")); + let mut vdom: El = El::empty(seed::dom_types::Tag::Div); + setup_els(&doc, &mut vdom, 0, 0); + // clone so we can keep using it after vdom is modified + let old_ws = vdom.el_ws.as_ref().unwrap().clone(); + parent.append_child(&old_ws).unwrap(); - old_ws.append_child(&child1).unwrap(); - new_ws.append_child(&child1).unwrap(); - new_ws.append_child(&child2).unwrap(); + assert_eq!(parent.children().length(), 1); + assert_eq!(old_ws.child_nodes().length(), 0); - let mailbox = Mailbox::new(|msg: Msg| {}); + vdom = { + let mut new_vdom: El = div!["text"]; + setup_els(&doc, &mut new_vdom, 0, 0); + patch(&doc, &mut vdom, &mut new_vdom, &parent, &mailbox); - let parent = doc.create_element("div").unwrap(); - patch(&doc, &mut old_vdom, &mut new_vdom, &parent, &mailbox); - unimplemented!() + assert_eq!(parent.children().length(), 1); + assert!(old_ws.is_same_node(parent.first_child().as_ref())); + assert_eq!(old_ws.child_nodes().length(), 1); + assert_eq!(old_ws.first_child().unwrap().text_content().unwrap(), "text"); + + new_vdom + }; + + { + let mut new_vdom: El = div!["text", "more text", vec![li!["even more text"]]]; + setup_els(&doc, &mut new_vdom, 0, 0); + patch(&doc, &mut vdom, &mut new_vdom, &parent, &mailbox); + + assert_eq!(parent.children().length(), 1); + assert!(old_ws.is_same_node(parent.first_child().as_ref())); + assert_eq!(old_ws.child_nodes().length(), 3); + assert_eq!(old_ws.child_nodes().item(0).unwrap().text_content().unwrap(), "text"); + assert_eq!(old_ws.child_nodes().item(1).unwrap().text_content().unwrap(), "more text"); + let child3 = old_ws.child_nodes().item(2).unwrap(); + assert_eq!(child3.node_name(), "LI"); + assert_eq!(child3.text_content().unwrap(), "even more text"); + } } - #[ignore] - #[test] - fn el_removed() { + // #[wasm_bindgen_test] + fn _el_removed() { unimplemented!() } - #[ignore] - #[test] - fn el_changed() { + // #[wasm_bindgen_test] + fn _el_changed() { unimplemented!() } } From 98173b7cc057b6eb5acafd3a35a37fb634395d93 Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 1 Mar 2019 11:43:44 +0200 Subject: [PATCH 4/8] Refactor some shared test code to a helper function --- src/routing.rs | 2 +- src/vdom.rs | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/routing.rs b/src/routing.rs index 3966b1269..4d91de8bf 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -189,7 +189,7 @@ pub fn setup_popstate_listener(app: &App, routes: fn(&Url) -> let url: Url = match ev.state().as_string() { Some(state_str) => serde_json::from_str(&state_str) - .expect("Problem deserialzing popstate state"), + .expect("Problem deserializing popstate state"), // This might happen if we go back to a page before we started routing. (?) None => { let empty: Vec = Vec::new(); diff --git a/src/vdom.rs b/src/vdom.rs index 6fe271905..4bf0dfa32 100644 --- a/src/vdom.rs +++ b/src/vdom.rs @@ -133,7 +133,7 @@ impl AppBuilder { } /// We use a struct instead of series of functions, in order to avoid passing -/// repetative sequences of parameters. +/// repetitive sequences of parameters. impl App { pub fn build( model: Mdl, @@ -161,7 +161,7 @@ impl App { let window = util::window(); let document = window .document() - .expect("Can't find the window's document."); + .expect("Can't find the window's document"); let mount_point = document .get_element_by_id(parent_div_id) @@ -730,6 +730,12 @@ pub mod tests { #[derive(Clone, Debug)] enum Msg {} + fn make_vdom(doc: &Document, el: El) -> El { + let mut vdom = el; + setup_els(doc, &mut vdom, 0, 0); + vdom + } + #[wasm_bindgen_test] fn el_added() { let mailbox = Mailbox::new(|_msg: Msg| {}); @@ -737,8 +743,7 @@ pub mod tests { let doc = util::document(); let parent = doc.create_element("div").unwrap(); - let mut vdom: El = El::empty(seed::dom_types::Tag::Div); - setup_els(&doc, &mut vdom, 0, 0); + let mut vdom = make_vdom(&doc, El::empty(seed::dom_types::Tag::Div)); // clone so we can keep using it after vdom is modified let old_ws = vdom.el_ws.as_ref().unwrap().clone(); parent.append_child(&old_ws).unwrap(); @@ -747,8 +752,7 @@ pub mod tests { assert_eq!(old_ws.child_nodes().length(), 0); vdom = { - let mut new_vdom: El = div!["text"]; - setup_els(&doc, &mut new_vdom, 0, 0); + let mut new_vdom = make_vdom(&doc, div!["text"]); patch(&doc, &mut vdom, &mut new_vdom, &parent, &mailbox); assert_eq!(parent.children().length(), 1); @@ -760,8 +764,10 @@ pub mod tests { }; { - let mut new_vdom: El = div!["text", "more text", vec![li!["even more text"]]]; - setup_els(&doc, &mut new_vdom, 0, 0); + let mut new_vdom = make_vdom( + &doc, + div!["text", "more text", vec![li!["even more text"]]], + ); patch(&doc, &mut vdom, &mut new_vdom, &parent, &mailbox); assert_eq!(parent.children().length(), 1); From ddb01018f6e1c07b5342b4801367706e92c924d5 Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 1 Mar 2019 11:50:24 +0200 Subject: [PATCH 5/8] Implement el_removed --- src/vdom.rs | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/vdom.rs b/src/vdom.rs index 4bf0dfa32..c0974ef9e 100644 --- a/src/vdom.rs +++ b/src/vdom.rs @@ -781,9 +781,44 @@ pub mod tests { } } - // #[wasm_bindgen_test] - fn _el_removed() { - unimplemented!() + #[wasm_bindgen_test] + fn el_removed() { + let mailbox = Mailbox::new(|_msg: Msg| {}); + + let doc = util::document(); + let parent = doc.create_element("div").unwrap(); + + let mut vdom = make_vdom(&doc, El::empty(seed::dom_types::Tag::Div)); + // clone so we can keep using it after vdom is modified + let old_ws = vdom.el_ws.as_ref().unwrap().clone(); + parent.append_child(&old_ws).unwrap(); + + // First add some child nodes using the vdom + vdom = { + let mut new_vdom = make_vdom( + &doc, + div!["text", "more text", vec![li!["even more text"]]], + ); + patch(&doc, &mut vdom, &mut new_vdom, &parent, &mailbox); + + assert_eq!(parent.children().length(), 1); + new_vdom + }; + + assert_eq!(parent.children().length(), 1); + assert_eq!(old_ws.child_nodes().length(), 3); + let old_child1 = old_ws.child_nodes().item(0).unwrap(); + + // Now test that patch function removes the last 2 nodes + { + let mut new_vdom = make_vdom(&doc, div!["text"]); + patch(&doc, &mut vdom, &mut new_vdom, &parent, &mailbox); + + assert_eq!(parent.children().length(), 1); + assert!(old_ws.is_same_node(parent.first_child().as_ref())); + assert_eq!(old_ws.child_nodes().length(), 1); + assert!(old_child1.is_same_node(old_ws.child_nodes().item(0).as_ref())); + } } // #[wasm_bindgen_test] From 7afc936aac1795cd3e5146f8586dd86018b3498a Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 1 Mar 2019 16:51:33 +0200 Subject: [PATCH 6/8] Take ownership of the old vdom in patch() --- src/vdom.rs | 71 +++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/vdom.rs b/src/vdom.rs index c0974ef9e..bb6079140 100644 --- a/src/vdom.rs +++ b/src/vdom.rs @@ -64,7 +64,7 @@ type StoredPopstate = RefCell>>; pub struct AppData { // Model is in a RefCell