dom_updater.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 dom_updater
  7. // #![feature(proc_macro_hygiene)]
  8. use console_error_panic_hook;
  9. use std::cell::RefCell;
  10. use std::collections::hash_map::DefaultHasher;
  11. use std::hash::{Hash, Hasher};
  12. use std::rc::Rc;
  13. use virtual_dom_rs::prelude::*;
  14. use virtual_dom_rs::DomUpdater;
  15. use wasm_bindgen::JsCast;
  16. use wasm_bindgen_test;
  17. use wasm_bindgen_test::*;
  18. use web_sys::*;
  19. wasm_bindgen_test_configure!(run_in_browser);
  20. // Verify that our DomUpdater's patch method works.
  21. // We test a simple case here, since diff_patch.rs is responsible for testing more complex
  22. // diffing and patching.
  23. #[wasm_bindgen_test]
  24. fn patches_dom() {
  25. console_error_panic_hook::set_once();
  26. let document = web_sys::window().unwrap().document().unwrap();
  27. let vdom = html! { <div></div> };
  28. let mut dom_updater = DomUpdater::new(vdom);
  29. let new_vdom = html! { <div id="patched"></div> };
  30. dom_updater.update(new_vdom);
  31. document
  32. .body()
  33. .unwrap()
  34. .append_child(&dom_updater.root_node());
  35. assert_eq!(document.query_selector("#patched").unwrap().is_some(), true);
  36. }
  37. // When you replace a DOM node with another DOM node we need to make sure that the closures
  38. // from the new DOM node are stored by the DomUpdater otherwise they'll get dropped and
  39. // won't work.
  40. #[wasm_bindgen_test]
  41. fn updates_active_closure_on_replace() {
  42. console_error_panic_hook::set_once();
  43. let document = web_sys::window().unwrap().document().unwrap();
  44. let body = document.body().unwrap();
  45. let old = html! { <div> </div> };
  46. let mut dom_updater = DomUpdater::new_append_to_mount(old, &body);
  47. let text = Rc::new(RefCell::new("Start Text".to_string()));
  48. let text_clone = Rc::clone(&text);
  49. let id = "update-active-closures-on-replace";
  50. {
  51. let replace_node = html! {
  52. <input
  53. id=id
  54. oninput=move |event: Event| {
  55. let input_elem = event.target().unwrap();
  56. let input_elem = input_elem.dyn_into::<HtmlInputElement>().unwrap();
  57. *text_clone.borrow_mut() = input_elem.value();
  58. }
  59. value="End Text"
  60. >
  61. };
  62. // New node replaces old node.
  63. // We are testing that we've stored this new node's closures even though `new` will be dropped
  64. // at the end of this block.
  65. dom_updater.update(replace_node);
  66. }
  67. let input_event = InputEvent::new("input").unwrap();
  68. assert_eq!(&*text.borrow(), "Start Text");
  69. // After dispatching the oninput event our `text` should have a value of the input elements value.
  70. let input = document.get_element_by_id(&id).unwrap();
  71. web_sys::EventTarget::from(input)
  72. .dispatch_event(&input_event)
  73. .unwrap();
  74. assert_eq!(&*text.borrow(), "End Text");
  75. }
  76. // When you replace a DOM node with another DOM node we need to make sure that the closures
  77. // from the new DOM node are stored by the DomUpdater otherwise they'll get dropped and
  78. // won't work.
  79. #[wasm_bindgen_test]
  80. fn updates_active_closures_on_append() {
  81. console_error_panic_hook::set_once();
  82. let document = web_sys::window().unwrap().document().unwrap();
  83. let body = document.body().unwrap();
  84. let old = html! { <div> </div> };
  85. let mut dom_updater = DomUpdater::new_append_to_mount(old, &body);
  86. let text = Rc::new(RefCell::new("Start Text".to_string()));
  87. let text_clone = Rc::clone(&text);
  88. let id = "update-active-closures-on-append";
  89. {
  90. let append_node = html! {
  91. <div>
  92. <input
  93. id=id
  94. oninput=move |event: Event| {
  95. let input_elem = event.target().unwrap();
  96. let input_elem = input_elem.dyn_into::<HtmlInputElement>().unwrap();
  97. *text_clone.borrow_mut() = input_elem.value();
  98. }
  99. value="End Text"
  100. >
  101. </div>
  102. };
  103. // New node gets appended into the DOM.
  104. // We are testing that we've stored this new node's closures even though `new` will be dropped
  105. // at the end of this block.
  106. dom_updater.update(append_node);
  107. }
  108. let input_event = InputEvent::new("input").unwrap();
  109. assert_eq!(&*text.borrow(), "Start Text");
  110. // After dispatching the oninput event our `text` should have a value of the input elements value.
  111. let input = document.get_element_by_id(id).unwrap();
  112. web_sys::EventTarget::from(input)
  113. .dispatch_event(&input_event)
  114. .unwrap();
  115. assert_eq!(&*text.borrow(), "End Text");
  116. }