lifecycle.rs 6.2 KB

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