lifecycle.rs 6.5 KB

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