1
0

render.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. use dioxus::prelude::*;
  2. #[test]
  3. #[allow(non_snake_case)]
  4. fn render_basic() {
  5. fn Base(cx: Scope) -> Element {
  6. rsx!(cx, div {})
  7. }
  8. let dom = VirtualDom::new(Base);
  9. let static_vnodes = rsx!(div{"hello world"});
  10. let location = CodeLocation {
  11. file: String::new(),
  12. line: 0,
  13. column: 0,
  14. };
  15. let empty_context = CapturedContext {
  16. captured: IfmtArgs {
  17. named_args: Vec::new(),
  18. },
  19. components: Vec::new(),
  20. iterators: Vec::new(),
  21. expressions: Vec::new(),
  22. listeners: Vec::new(),
  23. location: location.clone(),
  24. };
  25. let interperted_vnodes = LazyNodes::new(|factory| {
  26. dioxus_rsx_interpreter::resolve_scope(
  27. location,
  28. "div{\"hello world\"}",
  29. empty_context,
  30. factory,
  31. )
  32. });
  33. let interperted_vnodes = dom.render_vnodes(interperted_vnodes);
  34. let static_vnodes = dom.render_vnodes(static_vnodes);
  35. assert!(check_eq(interperted_vnodes, static_vnodes));
  36. }
  37. #[test]
  38. #[allow(non_snake_case)]
  39. fn render_nested() {
  40. fn Base(cx: Scope) -> Element {
  41. rsx!(cx, div {})
  42. }
  43. let dom = VirtualDom::new(Base);
  44. let static_vnodes = rsx! {
  45. div {
  46. p { "hello world" }
  47. div {
  48. p { "hello world" }
  49. }
  50. }
  51. };
  52. let location = CodeLocation {
  53. file: String::new(),
  54. line: 1,
  55. column: 0,
  56. };
  57. let empty_context = CapturedContext {
  58. captured: IfmtArgs {
  59. named_args: Vec::new(),
  60. },
  61. components: Vec::new(),
  62. iterators: Vec::new(),
  63. expressions: Vec::new(),
  64. listeners: Vec::new(),
  65. location: location.clone(),
  66. };
  67. let interperted_vnodes = LazyNodes::new(|factory| {
  68. dioxus_rsx_interpreter::resolve_scope(
  69. location,
  70. r#"div {
  71. p { "hello world" }
  72. div {
  73. p { "hello world" }
  74. }
  75. }"#,
  76. empty_context,
  77. factory,
  78. )
  79. });
  80. let interperted_vnodes = dom.render_vnodes(interperted_vnodes);
  81. let static_vnodes = dom.render_vnodes(static_vnodes);
  82. assert!(check_eq(interperted_vnodes, static_vnodes));
  83. }
  84. #[test]
  85. #[allow(non_snake_case)]
  86. fn render_component() {
  87. fn Comp(cx: Scope) -> Element {
  88. rsx!(cx, div {})
  89. }
  90. fn Base(cx: Scope) -> Element {
  91. rsx!(cx, div {})
  92. }
  93. let dom = VirtualDom::new(Base);
  94. let static_vnodes = rsx! {
  95. div {
  96. Comp {}
  97. }
  98. };
  99. let location = CodeLocation {
  100. file: String::new(),
  101. line: 2,
  102. column: 0,
  103. };
  104. let interperted_vnodes = LazyNodes::new(|factory| {
  105. let context = CapturedContext {
  106. captured: IfmtArgs {
  107. named_args: Vec::new(),
  108. },
  109. components: vec![(
  110. r#"__cx.component(Comp, fc_to_builder(Comp).build(), None, "Comp")"#,
  111. factory.component(Comp, (), None, "Comp"),
  112. )],
  113. iterators: Vec::new(),
  114. expressions: Vec::new(),
  115. listeners: Vec::new(),
  116. location: location.clone(),
  117. };
  118. dioxus_rsx_interpreter::resolve_scope(
  119. location,
  120. r#"div {
  121. Comp {}
  122. }"#,
  123. context,
  124. factory,
  125. )
  126. });
  127. let interperted_vnodes = dom.render_vnodes(interperted_vnodes);
  128. let static_vnodes = dom.render_vnodes(static_vnodes);
  129. println!("{:#?}", interperted_vnodes);
  130. println!("{:#?}", static_vnodes);
  131. assert!(check_eq(interperted_vnodes, static_vnodes));
  132. }
  133. #[test]
  134. #[allow(non_snake_case)]
  135. fn render_iterator() {
  136. fn Base(cx: Scope) -> Element {
  137. rsx!(cx, div {})
  138. }
  139. let dom = VirtualDom::new(Base);
  140. let iter = (0..10).map(|i| dom.render_vnodes(rsx! {"{i}"}));
  141. let static_vnodes = rsx! {
  142. div {
  143. iter
  144. }
  145. };
  146. let location = CodeLocation {
  147. file: String::new(),
  148. line: 3,
  149. column: 0,
  150. };
  151. let interperted_vnodes = LazyNodes::new(|factory| {
  152. let context = CapturedContext {
  153. captured: IfmtArgs {
  154. named_args: Vec::new(),
  155. },
  156. components: Vec::new(),
  157. iterators: vec![(
  158. r#"
  159. (0..10).map(|i| dom.render_vnodes(rsx!{"{i}"}))"#,
  160. factory.fragment_from_iter((0..10).map(|i| factory.text(format_args!("{i}")))),
  161. )],
  162. expressions: Vec::new(),
  163. listeners: Vec::new(),
  164. location: location.clone(),
  165. };
  166. dioxus_rsx_interpreter::resolve_scope(
  167. location,
  168. r#"div {
  169. (0..10).map(|i| dom.render_vnodes(rsx!{"{i}"}))
  170. }"#,
  171. context,
  172. factory,
  173. )
  174. });
  175. let interperted_vnodes = dom.render_vnodes(interperted_vnodes);
  176. let static_vnodes = dom.render_vnodes(static_vnodes);
  177. println!("{:#?}", interperted_vnodes);
  178. println!("{:#?}", static_vnodes);
  179. assert!(check_eq(interperted_vnodes, static_vnodes));
  180. }
  181. #[test]
  182. #[allow(non_snake_case)]
  183. fn render_captured_variable() {
  184. fn Base(cx: Scope) -> Element {
  185. rsx!(cx, div {})
  186. }
  187. let dom = VirtualDom::new(Base);
  188. let x = 10;
  189. let static_vnodes = rsx! {
  190. div {
  191. "{x}"
  192. }
  193. };
  194. let location = CodeLocation {
  195. file: String::new(),
  196. line: 4,
  197. column: 0,
  198. };
  199. let interperted_vnodes = LazyNodes::new(|factory| {
  200. let context = CapturedContext {
  201. captured: IfmtArgs {
  202. named_args: vec![FormattedArg {
  203. expr: "x",
  204. format_args: "",
  205. result: x.to_string(),
  206. }],
  207. },
  208. components: Vec::new(),
  209. iterators: Vec::new(),
  210. expressions: Vec::new(),
  211. listeners: Vec::new(),
  212. location: location.clone(),
  213. };
  214. dioxus_rsx_interpreter::resolve_scope(
  215. location,
  216. r#"div {
  217. "{x}"
  218. }"#,
  219. context,
  220. factory,
  221. )
  222. });
  223. let interperted_vnodes = dom.render_vnodes(interperted_vnodes);
  224. let static_vnodes = dom.render_vnodes(static_vnodes);
  225. println!("{:#?}", interperted_vnodes);
  226. println!("{:#?}", static_vnodes);
  227. assert!(check_eq(interperted_vnodes, static_vnodes));
  228. }
  229. #[test]
  230. #[allow(non_snake_case)]
  231. fn render_listener() {
  232. fn Base(cx: Scope) -> Element {
  233. rsx!(cx, div {})
  234. }
  235. let dom = VirtualDom::new(Base);
  236. let static_vnodes = rsx! {
  237. div {
  238. onclick: |_| println!("clicked")
  239. }
  240. };
  241. let location = CodeLocation {
  242. file: String::new(),
  243. line: 5,
  244. column: 0,
  245. };
  246. let interperted_vnodes = LazyNodes::new(|factory| {
  247. let f = |_| println!("clicked");
  248. let f = factory.bump().alloc(f);
  249. let context = CapturedContext {
  250. captured: IfmtArgs {
  251. named_args: Vec::new(),
  252. },
  253. components: Vec::new(),
  254. iterators: Vec::new(),
  255. expressions: Vec::new(),
  256. listeners: vec![(
  257. r#"dioxus_elements::on::onclick(__cx, |_| println!("clicked"))"#,
  258. dioxus_elements::on::onclick(factory, f),
  259. )],
  260. location: location.clone(),
  261. };
  262. dioxus_rsx_interpreter::resolve_scope(
  263. location,
  264. r#"div {
  265. onclick: |_| println!("clicked")
  266. }"#,
  267. context,
  268. factory,
  269. )
  270. });
  271. let interperted_vnodes = dom.render_vnodes(interperted_vnodes);
  272. let static_vnodes = dom.render_vnodes(static_vnodes);
  273. println!("{:#?}", interperted_vnodes);
  274. println!("{:#?}", static_vnodes);
  275. assert!(check_eq(interperted_vnodes, static_vnodes));
  276. }
  277. fn check_eq<'a>(a: &'a VNode<'a>, b: &'a VNode<'a>) -> bool {
  278. match (a, b) {
  279. (VNode::Text(t_a), VNode::Text(t_b)) => t_a.text == t_b.text,
  280. (VNode::Element(e_a), VNode::Element(e_b)) => {
  281. e_a.attributes
  282. .iter()
  283. .zip(e_b.attributes.iter())
  284. .all(|(a, b)| {
  285. a.is_static == b.is_static
  286. && a.is_volatile == b.is_volatile
  287. && a.name == b.name
  288. && a.value == b.value
  289. && a.namespace == b.namespace
  290. })
  291. && e_a
  292. .children
  293. .iter()
  294. .zip(e_b.children.iter())
  295. .all(|(a, b)| check_eq(a, b))
  296. && e_a.key == e_b.key
  297. && e_a.tag == e_b.tag
  298. && e_a.namespace == e_b.namespace
  299. && e_a
  300. .listeners
  301. .iter()
  302. .zip(e_b.listeners.iter())
  303. .all(|(a, b)| a.event == b.event)
  304. }
  305. (VNode::Fragment(f_a), VNode::Fragment(f_b)) => {
  306. f_a.key == f_b.key
  307. && f_a
  308. .children
  309. .iter()
  310. .zip(f_b.children.iter())
  311. .all(|(a, b)| check_eq(a, b))
  312. }
  313. (VNode::Component(c_a), VNode::Component(c_b)) => {
  314. c_a.can_memoize == c_b.can_memoize
  315. && c_a.key == c_b.key
  316. && c_a.fn_name == c_b.fn_name
  317. && c_a.user_fc == c_b.user_fc
  318. }
  319. (VNode::Placeholder(_), VNode::Placeholder(_)) => true,
  320. _ => false,
  321. }
  322. }