lifecycle.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. static App: Component = |cx| {
  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. static App: Component = |cx| {
  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. static Child: Component = |cx| {
  85. cx.render(rsx! {
  86. h1 {}
  87. })
  88. };
  89. let mut dom = VirtualDom::new(App);
  90. let edits = dom.rebuild();
  91. assert_eq!(
  92. edits.edits,
  93. [
  94. CreateTextNode { text: "Text0", root: 1 },
  95. AppendChildren { many: 1 },
  96. ]
  97. );
  98. let edits = dom.hard_diff(ScopeId(0));
  99. assert_eq!(
  100. edits.edits,
  101. [
  102. CreateElement { tag: "div", root: 2 },
  103. ReplaceWith { root: 1, m: 1 },
  104. ]
  105. );
  106. let edits = dom.hard_diff(ScopeId(0));
  107. assert_eq!(
  108. edits.edits,
  109. [
  110. CreateTextNode { text: "Text2", root: 3 },
  111. ReplaceWith { root: 2, m: 1 },
  112. ]
  113. );
  114. let edits = dom.hard_diff(ScopeId(0));
  115. assert_eq!(
  116. edits.edits,
  117. [
  118. CreateElement { tag: "h1", root: 4 },
  119. ReplaceWith { root: 3, m: 1 },
  120. ]
  121. );
  122. let edits = dom.hard_diff(ScopeId(0));
  123. assert_eq!(
  124. edits.edits,
  125. [CreatePlaceholder { root: 5 }, ReplaceWith { root: 4, m: 1 },]
  126. );
  127. let edits = dom.hard_diff(ScopeId(0));
  128. assert_eq!(
  129. edits.edits,
  130. [
  131. CreateTextNode { text: "text 3", root: 6 },
  132. ReplaceWith { root: 5, m: 1 },
  133. ]
  134. );
  135. let edits = dom.hard_diff(ScopeId(0));
  136. assert_eq!(
  137. edits.edits,
  138. [
  139. CreateTextNode { text: "text 0", root: 7 },
  140. CreateTextNode { text: "text 1", root: 8 },
  141. ReplaceWith { root: 6, m: 2 },
  142. ]
  143. );
  144. let edits = dom.hard_diff(ScopeId(0));
  145. assert_eq!(
  146. edits.edits,
  147. [
  148. CreateElement { tag: "h1", root: 9 },
  149. ReplaceWith { root: 7, m: 1 },
  150. Remove { root: 8 },
  151. ]
  152. );
  153. }
  154. #[test]
  155. fn component_swap() {
  156. static App: Component = |cx| {
  157. let render_phase = cx.use_hook(|_| 0);
  158. *render_phase += 1;
  159. cx.render(match *render_phase {
  160. 0 => rsx!(
  161. div {
  162. NavBar {}
  163. Dashboard {}
  164. }
  165. ),
  166. 1 => rsx!(
  167. div {
  168. NavBar {}
  169. Results {}
  170. }
  171. ),
  172. 2 => rsx!(
  173. div {
  174. NavBar {}
  175. Dashboard {}
  176. }
  177. ),
  178. 3 => rsx!(
  179. div {
  180. NavBar {}
  181. Results {}
  182. }
  183. ),
  184. 4 => rsx!(
  185. div {
  186. NavBar {}
  187. Dashboard {}
  188. }
  189. ),
  190. _ => rsx!("blah"),
  191. })
  192. };
  193. static NavBar: Component = |cx| {
  194. println!("running navbar");
  195. cx.render(rsx! {
  196. h1 {
  197. "NavBar"
  198. {(0..3).map(|f| rsx!(NavLink {}))}
  199. }
  200. })
  201. };
  202. static NavLink: Component = |cx| {
  203. println!("running navlink");
  204. cx.render(rsx! {
  205. h1 {
  206. "NavLink"
  207. }
  208. })
  209. };
  210. static Dashboard: Component = |cx| {
  211. println!("running dashboard");
  212. cx.render(rsx! {
  213. div {
  214. "dashboard"
  215. }
  216. })
  217. };
  218. static Results: Component = |cx| {
  219. println!("running results");
  220. cx.render(rsx! {
  221. div {
  222. "results"
  223. }
  224. })
  225. };
  226. let mut dom = VirtualDom::new(App);
  227. let edits = dom.rebuild();
  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. let edits = dom.work_with_deadline(|| false);
  234. dbg!(&edits);
  235. let edits = dom.work_with_deadline(|| false);
  236. dbg!(&edits);
  237. }