1
0

closures.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //! Ensure that our DomUpdater maintains Rc's to closures so that they work even
  2. //! after dropping virtual dom nodes.
  3. //!
  4. //! To run all tests in this file:
  5. //!
  6. //! wasm-pack test crates/virtual-dom-rs --chrome --headless -- --test closures
  7. // #![feature(proc_macro_hygiene)]
  8. use std::cell::RefCell;
  9. use std::collections::hash_map::DefaultHasher;
  10. use std::rc::Rc;
  11. use virtual_dom_rs::prelude::*;
  12. use virtual_dom_rs::DomUpdater;
  13. use wasm_bindgen::JsCast;
  14. use wasm_bindgen_test;
  15. use wasm_bindgen_test::*;
  16. use web_sys::*;
  17. wasm_bindgen_test_configure!(run_in_browser);
  18. // TODO: This test current fails in headless browsers but works in non headless browsers
  19. // (tested in both geckodriver and chromedriver)
  20. // Need to figure out why
  21. #[wasm_bindgen_test]
  22. fn closure_not_dropped() {
  23. let text = Rc::new(RefCell::new("Start Text".to_string()));
  24. let document = web_sys::window().unwrap().document().unwrap();
  25. let mut dom_updater = None;
  26. {
  27. let mut input = make_input_component(Rc::clone(&text));
  28. input
  29. .as_velement_mut()
  30. .expect("Not an element")
  31. .attrs
  32. .insert("id".into(), "old-input-elem".into());
  33. let mount = document.create_element("div").unwrap();
  34. mount.set_id("mount");
  35. document.body().unwrap().append_child(&mount).unwrap();
  36. dom_updater = Some(DomUpdater::new_replace_mount(input, mount));
  37. let mut dom_updater = dom_updater.as_mut().unwrap();
  38. // Input VirtualNode from above gets dropped at the end of this block,
  39. // yet that element held Rc's to the Closure's that power the oninput event.
  40. //
  41. // We're patching the DOM with a new vdom, but since our new vdom doesn't contain any
  42. // new elements, `.create_element` won't get called and so no new Closures will be
  43. // created.
  44. //
  45. // So, we're testing that our old Closure's still work. The reason that they work is
  46. // that dom_updater maintains Rc's to those Closures.
  47. let mut new_node = make_input_component(Rc::clone(&text));
  48. new_node
  49. .as_velement_mut()
  50. .expect("Not an element")
  51. .attrs
  52. .insert("id".into(), "new-input-elem".into());
  53. dom_updater.update(new_node);
  54. }
  55. let dom_updater = dom_updater.as_ref().unwrap();
  56. let input: HtmlInputElement = document
  57. .get_element_by_id("new-input-elem")
  58. .expect("Input element")
  59. .dyn_into()
  60. .unwrap();
  61. let input_event = InputEvent::new("input").unwrap();
  62. assert_eq!(&*text.borrow(), "Start Text");
  63. // After dispatching the oninput event our `text` should have a value of the input elements value.
  64. web_sys::EventTarget::from(input)
  65. .dispatch_event(&input_event)
  66. .unwrap();
  67. assert_eq!(&*text.borrow(), "End Text");
  68. assert_eq!(
  69. dom_updater.active_closures.get(&1).as_ref().unwrap().len(),
  70. 1
  71. );
  72. }
  73. // We're just making sure that things compile - other tests give us confidence that the closure
  74. // will work just fine.
  75. //
  76. // https://github.com/chinedufn/percy/issues/81
  77. //
  78. //#[wasm_bindgen_test]
  79. //fn closure_with_no_params_compiles() {
  80. // let _making_sure_this_works = html! {
  81. // <div onclick=|| {}></div>
  82. // };
  83. //}
  84. fn make_input_component(text_clone: Rc<RefCell<String>>) -> VirtualNode {
  85. html! {
  86. <input
  87. // On input we'll set our Rc<RefCell<String>> value to the input elements value
  88. oninput=move |event: Event| {
  89. let input_elem = event.target().unwrap();
  90. let input_elem = input_elem.dyn_into::<HtmlInputElement>().unwrap();
  91. *text_clone.borrow_mut() = input_elem.value();
  92. }
  93. value="End Text"
  94. >
  95. }
  96. }