lifecycle.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #![allow(unused, non_upper_case_globals)]
  2. //! Tests for the lifecycle of components.
  3. use dioxus::prelude::*;
  4. use dioxus_core as dioxus;
  5. use dioxus_core::DomEdit::*;
  6. use dioxus_core::ScopeId;
  7. use dioxus_core_macro::*;
  8. use dioxus_html as dioxus_elements;
  9. use std::sync::{Arc, Mutex};
  10. mod test_logging;
  11. const IS_LOGGING_ENABLED: bool = true;
  12. type Shared<T> = Arc<Mutex<T>>;
  13. #[test]
  14. fn manual_diffing() {
  15. struct AppProps {
  16. value: Shared<&'static str>,
  17. }
  18. static App: Component<AppProps> = |cx| {
  19. let val = cx.props.value.lock().unwrap();
  20. cx.render(rsx! { div { "{val}" } })
  21. };
  22. let value = Arc::new(Mutex::new("Hello"));
  23. let mut dom = VirtualDom::new_with_props(App, AppProps { value: value.clone() });
  24. let _ = dom.rebuild();
  25. *value.lock().unwrap() = "goodbye";
  26. let edits = dom.rebuild();
  27. log::debug!("edits: {:?}", edits);
  28. }
  29. #[test]
  30. fn events_generate() {
  31. fn app(cx: Scope) -> Element {
  32. let count = cx.use_hook(|_| 0);
  33. let inner = match *count {
  34. 0 => {
  35. rsx! {
  36. div {
  37. onclick: move |_| *count += 1,
  38. div {
  39. "nested"
  40. }
  41. "Click me!"
  42. }
  43. }
  44. }
  45. _ => todo!(),
  46. };
  47. cx.render(inner)
  48. };
  49. let mut dom = VirtualDom::new(app);
  50. let mut channel = dom.get_scheduler_channel();
  51. assert!(dom.has_work());
  52. let edits = dom.rebuild();
  53. assert_eq!(
  54. edits.edits,
  55. [
  56. CreateElement { tag: "div", root: 1 },
  57. NewEventListener { event_name: "click", scope: ScopeId(0), root: 1 },
  58. CreateElement { tag: "div", root: 2 },
  59. CreateTextNode { text: "nested", root: 3 },
  60. AppendChildren { many: 1 },
  61. CreateTextNode { text: "Click me!", root: 4 },
  62. AppendChildren { many: 2 },
  63. AppendChildren { many: 1 },
  64. ]
  65. )
  66. }
  67. #[test]
  68. fn components_generate() {
  69. fn app(cx: Scope) -> Element {
  70. let render_phase = cx.use_hook(|_| 0);
  71. *render_phase += 1;
  72. cx.render(match *render_phase {
  73. 1 => rsx!("Text0"),
  74. 2 => rsx!(div {}),
  75. 3 => rsx!("Text2"),
  76. 4 => rsx!(Child {}),
  77. 5 => rsx!({ None as Option<()> }),
  78. 6 => rsx!("text 3"),
  79. 7 => rsx!({ (0..2).map(|f| rsx!("text {f}")) }),
  80. 8 => rsx!(Child {}),
  81. _ => todo!(),
  82. })
  83. };
  84. fn Child(cx: Scope) -> Element {
  85. log::debug!("Running child");
  86. cx.render(rsx! {
  87. h1 {}
  88. })
  89. }
  90. let mut dom = VirtualDom::new(app);
  91. let edits = dom.rebuild();
  92. assert_eq!(
  93. edits.edits,
  94. [
  95. CreateTextNode { text: "Text0", root: 1 },
  96. AppendChildren { many: 1 },
  97. ]
  98. );
  99. assert_eq!(
  100. dom.hard_diff(ScopeId(0)).edits,
  101. [
  102. CreateElement { tag: "div", root: 2 },
  103. ReplaceWith { root: 1, m: 1 },
  104. ]
  105. );
  106. assert_eq!(
  107. dom.hard_diff(ScopeId(0)).edits,
  108. [
  109. CreateTextNode { text: "Text2", root: 1 },
  110. ReplaceWith { root: 2, m: 1 },
  111. ]
  112. );
  113. // child {}
  114. assert_eq!(
  115. dom.hard_diff(ScopeId(0)).edits,
  116. [
  117. CreateElement { tag: "h1", root: 2 },
  118. ReplaceWith { root: 1, m: 1 },
  119. ]
  120. );
  121. // placeholder
  122. assert_eq!(
  123. dom.hard_diff(ScopeId(0)).edits,
  124. [CreatePlaceholder { root: 1 }, ReplaceWith { root: 2, m: 1 },]
  125. );
  126. assert_eq!(
  127. dom.hard_diff(ScopeId(0)).edits,
  128. [
  129. CreateTextNode { text: "text 3", root: 2 },
  130. ReplaceWith { root: 1, m: 1 },
  131. ]
  132. );
  133. assert_eq!(
  134. dom.hard_diff(ScopeId(0)).edits,
  135. [
  136. CreateTextNode { text: "text 0", root: 1 },
  137. CreateTextNode { text: "text 1", root: 3 },
  138. ReplaceWith { root: 2, m: 2 },
  139. ]
  140. );
  141. assert_eq!(
  142. dom.hard_diff(ScopeId(0)).edits,
  143. [
  144. CreateElement { tag: "h1", root: 2 },
  145. ReplaceWith { root: 1, m: 1 },
  146. Remove { root: 3 },
  147. ]
  148. );
  149. }
  150. #[test]
  151. fn component_swap() {
  152. fn app(cx: Scope) -> Element {
  153. let render_phase = cx.use_hook(|_| 0);
  154. *render_phase += 1;
  155. cx.render(match *render_phase {
  156. 0 => rsx!(
  157. div {
  158. NavBar {}
  159. Dashboard {}
  160. }
  161. ),
  162. 1 => rsx!(
  163. div {
  164. NavBar {}
  165. Results {}
  166. }
  167. ),
  168. 2 => rsx!(
  169. div {
  170. NavBar {}
  171. Dashboard {}
  172. }
  173. ),
  174. 3 => rsx!(
  175. div {
  176. NavBar {}
  177. Results {}
  178. }
  179. ),
  180. 4 => rsx!(
  181. div {
  182. NavBar {}
  183. Dashboard {}
  184. }
  185. ),
  186. _ => rsx!("blah"),
  187. })
  188. };
  189. static NavBar: Component = |cx| {
  190. println!("running navbar");
  191. cx.render(rsx! {
  192. h1 {
  193. "NavBar"
  194. {(0..3).map(|f| rsx!(NavLink {}))}
  195. }
  196. })
  197. };
  198. static NavLink: Component = |cx| {
  199. println!("running navlink");
  200. cx.render(rsx! {
  201. h1 {
  202. "NavLink"
  203. }
  204. })
  205. };
  206. static Dashboard: Component = |cx| {
  207. println!("running dashboard");
  208. cx.render(rsx! {
  209. div {
  210. "dashboard"
  211. }
  212. })
  213. };
  214. static Results: Component = |cx| {
  215. println!("running results");
  216. cx.render(rsx! {
  217. div {
  218. "results"
  219. }
  220. })
  221. };
  222. let mut dom = VirtualDom::new(app);
  223. let edits = dom.rebuild();
  224. dbg!(&edits);
  225. let edits = dom.work_with_deadline(|| false);
  226. dbg!(&edits);
  227. let edits = dom.work_with_deadline(|| false);
  228. dbg!(&edits);
  229. let edits = dom.work_with_deadline(|| false);
  230. dbg!(&edits);
  231. let edits = dom.work_with_deadline(|| false);
  232. dbg!(&edits);
  233. }