lifecycle.rs 6.1 KB

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