123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- //! Ensure that our DomUpdater maintains Rc's to closures so that they work even
- //! after dropping virtual dom nodes.
- //!
- //! To run all tests in this file:
- //!
- //! wasm-pack test crates/virtual-dom-rs --chrome --headless -- --test closures
- // #![feature(proc_macro_hygiene)]
- use std::cell::RefCell;
- use std::collections::hash_map::DefaultHasher;
- use std::rc::Rc;
- use virtual_dom_rs::prelude::*;
- use virtual_dom_rs::DomUpdater;
- use wasm_bindgen::JsCast;
- use wasm_bindgen_test;
- use wasm_bindgen_test::*;
- use web_sys::*;
- wasm_bindgen_test_configure!(run_in_browser);
- // TODO: This test current fails in headless browsers but works in non headless browsers
- // (tested in both geckodriver and chromedriver)
- // Need to figure out why
- #[wasm_bindgen_test]
- fn closure_not_dropped() {
- let text = Rc::new(RefCell::new("Start Text".to_string()));
- let document = web_sys::window().unwrap().document().unwrap();
- let mut dom_updater = None;
- {
- let mut input = make_input_component(Rc::clone(&text));
- input
- .as_velement_mut()
- .expect("Not an element")
- .attrs
- .insert("id".into(), "old-input-elem".into());
- let mount = document.create_element("div").unwrap();
- mount.set_id("mount");
- document.body().unwrap().append_child(&mount).unwrap();
- dom_updater = Some(DomUpdater::new_replace_mount(input, mount));
- let mut dom_updater = dom_updater.as_mut().unwrap();
- // Input VirtualNode from above gets dropped at the end of this block,
- // yet that element held Rc's to the Closure's that power the oninput event.
- //
- // We're patching the DOM with a new vdom, but since our new vdom doesn't contain any
- // new elements, `.create_element` won't get called and so no new Closures will be
- // created.
- //
- // So, we're testing that our old Closure's still work. The reason that they work is
- // that dom_updater maintains Rc's to those Closures.
- let mut new_node = make_input_component(Rc::clone(&text));
- new_node
- .as_velement_mut()
- .expect("Not an element")
- .attrs
- .insert("id".into(), "new-input-elem".into());
- dom_updater.update(new_node);
- }
- let dom_updater = dom_updater.as_ref().unwrap();
- let input: HtmlInputElement = document
- .get_element_by_id("new-input-elem")
- .expect("Input element")
- .dyn_into()
- .unwrap();
- let input_event = InputEvent::new("input").unwrap();
- assert_eq!(&*text.borrow(), "Start Text");
- // After dispatching the oninput event our `text` should have a value of the input elements value.
- web_sys::EventTarget::from(input)
- .dispatch_event(&input_event)
- .unwrap();
- assert_eq!(&*text.borrow(), "End Text");
- assert_eq!(
- dom_updater.active_closures.get(&1).as_ref().unwrap().len(),
- 1
- );
- }
- // We're just making sure that things compile - other tests give us confidence that the closure
- // will work just fine.
- //
- // https://github.com/chinedufn/percy/issues/81
- //
- //#[wasm_bindgen_test]
- //fn closure_with_no_params_compiles() {
- // let _making_sure_this_works = html! {
- // <div onclick=|| {}></div>
- // };
- //}
- fn make_input_component(text_clone: Rc<RefCell<String>>) -> VirtualNode {
- html! {
- <input
- // On input we'll set our Rc<RefCell<String>> value to the input elements value
- oninput=move |event: Event| {
- let input_elem = event.target().unwrap();
- let input_elem = input_elem.dyn_into::<HtmlInputElement>().unwrap();
- *text_clone.borrow_mut() = input_elem.value();
- }
- value="End Text"
- >
- }
- }
|