diffing.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. #![allow(unused, non_upper_case_globals)]
  2. //! Diffing Tests
  3. //!
  4. //! These tests only verify that the diffing algorithm works properly for single components.
  5. //!
  6. //! It does not validated that component lifecycles work properly. This is done in another test file.
  7. use dioxus::{core_macro::rsx_without_templates, prelude::*};
  8. fn new_dom() -> VirtualDom {
  9. VirtualDom::new(|cx| cx.render(rsx_without_templates!("hi")))
  10. }
  11. use dioxus_core::DomEdit::*;
  12. /// Should push the text node onto the stack and modify it
  13. #[test]
  14. fn html_and_rsx_generate_the_same_output() {
  15. let dom = new_dom();
  16. let (create, change) = dom.diff_lazynodes(
  17. rsx_without_templates! ( div { "Hello world" } ),
  18. rsx_without_templates! ( div { "Goodbye world" } ),
  19. );
  20. assert_eq!(
  21. create.edits,
  22. [
  23. CreateElement { root: Some(1,), tag: "div", children: 0 },
  24. CreateTextNode { root: Some(2,), text: "Hello world" },
  25. AppendChildren { root: Some(1,), children: vec![2] },
  26. AppendChildren { root: Some(0,), children: vec![1] },
  27. ]
  28. );
  29. assert_eq!(
  30. change.edits,
  31. [SetText { root: Some(2,), text: "Goodbye world" },]
  32. );
  33. }
  34. /// Should result in 3 elements on the stack
  35. #[test]
  36. fn fragments_create_properly() {
  37. let dom = new_dom();
  38. let create = dom.create_vnodes(rsx_without_templates! {
  39. div { "Hello a" }
  40. div { "Hello b" }
  41. div { "Hello c" }
  42. });
  43. assert_eq!(
  44. create.edits,
  45. [
  46. CreateElement { root: Some(1,), tag: "div", children: 0 },
  47. CreateTextNode { root: Some(2,), text: "Hello a" },
  48. AppendChildren { root: Some(1,), children: vec![2,] },
  49. CreateElement { root: Some(3,), tag: "div", children: 0 },
  50. CreateTextNode { root: Some(4,), text: "Hello b" },
  51. AppendChildren { root: Some(3,), children: vec![4,] },
  52. CreateElement { root: Some(5,), tag: "div", children: 0 },
  53. CreateTextNode { root: Some(6,), text: "Hello c" },
  54. AppendChildren { root: Some(5,), children: vec![6,] },
  55. AppendChildren { root: Some(0,), children: vec![1, 3, 5,] },
  56. ]
  57. );
  58. }
  59. /// Should result in the creation of an anchor (placeholder) and then a replacewith
  60. #[test]
  61. fn empty_fragments_create_anchors() {
  62. let dom = new_dom();
  63. let left = rsx_without_templates!({ (0..0).map(|_f| rsx_without_templates! { div {}}) });
  64. let right = rsx_without_templates!({ (0..1).map(|_f| rsx_without_templates! { div {}}) });
  65. let (create, change) = dom.diff_lazynodes(left, right);
  66. assert_eq!(
  67. create.edits,
  68. [
  69. CreatePlaceholder { root: Some(1,) },
  70. AppendChildren { root: Some(0,), children: vec![1,] },
  71. ]
  72. );
  73. assert_eq!(
  74. change.edits,
  75. [
  76. CreateElement { root: Some(2,), tag: "div", children: 0 },
  77. ReplaceWith { root: Some(1,), nodes: vec![2,] },
  78. ]
  79. );
  80. }
  81. /// Should result in the creation of an anchor (placeholder) and then a replacewith m=5
  82. #[test]
  83. fn empty_fragments_create_many_anchors() {
  84. let dom = new_dom();
  85. let left = rsx_without_templates!({ (0..0).map(|_f| rsx_without_templates! { div {}}) });
  86. let right = rsx_without_templates!({ (0..5).map(|_f| rsx_without_templates! { div {}}) });
  87. let (create, change) = dom.diff_lazynodes(left, right);
  88. assert_eq!(
  89. create.edits,
  90. [
  91. CreatePlaceholder { root: Some(1,) },
  92. AppendChildren { root: Some(0,), children: vec![1,] },
  93. ]
  94. );
  95. assert_eq!(
  96. change.edits,
  97. [
  98. CreateElement { root: Some(2,), tag: "div", children: 0 },
  99. CreateElement { root: Some(3,), tag: "div", children: 0 },
  100. CreateElement { root: Some(4,), tag: "div", children: 0 },
  101. CreateElement { root: Some(5,), tag: "div", children: 0 },
  102. CreateElement { root: Some(6,), tag: "div", children: 0 },
  103. ReplaceWith { root: Some(1,), nodes: vec![2, 3, 4, 5, 6,] },
  104. ]
  105. );
  106. }
  107. /// Should result in the creation of an anchor (placeholder) and then a replacewith
  108. /// Includes child nodes inside the fragment
  109. #[test]
  110. fn empty_fragments_create_anchors_with_many_children() {
  111. let dom = new_dom();
  112. let left = rsx_without_templates!({ (0..0).map(|_| rsx_without_templates! { div {} }) });
  113. let right = rsx_without_templates!({
  114. (0..3).map(|f| {
  115. rsx_without_templates! { div { "hello: {f}" }}
  116. })
  117. });
  118. let (create, change) = dom.diff_lazynodes(left, right);
  119. assert_eq!(
  120. create.edits,
  121. [
  122. CreatePlaceholder { root: Some(1,) },
  123. AppendChildren { root: Some(0,), children: vec![1,] },
  124. ]
  125. );
  126. assert_eq!(
  127. change.edits,
  128. [
  129. CreateElement { root: Some(2,), tag: "div", children: 0 },
  130. CreateTextNode { root: Some(3,), text: "hello: 0" },
  131. AppendChildren { root: Some(2,), children: vec![3,] },
  132. CreateElement { root: Some(4,), tag: "div", children: 0 },
  133. CreateTextNode { root: Some(5,), text: "hello: 1" },
  134. AppendChildren { root: Some(4,), children: vec![5,] },
  135. CreateElement { root: Some(6,), tag: "div", children: 0 },
  136. CreateTextNode { root: Some(7,), text: "hello: 2" },
  137. AppendChildren { root: Some(6,), children: vec![7,] },
  138. ReplaceWith { root: Some(1,), nodes: vec![2, 4, 6,] },
  139. ]
  140. );
  141. }
  142. /// Should result in every node being pushed and then replaced with an anchor
  143. #[test]
  144. fn many_items_become_fragment() {
  145. let dom = new_dom();
  146. let left = rsx_without_templates!({
  147. (0..2).map(|_| {
  148. rsx_without_templates! { div { "hello" }}
  149. })
  150. });
  151. let right = rsx_without_templates!({ (0..0).map(|_| rsx_without_templates! { div {} }) });
  152. let (create, change) = dom.diff_lazynodes(left, right);
  153. assert_eq!(
  154. create.edits,
  155. [
  156. CreateElement { root: Some(1,), tag: "div", children: 0 },
  157. CreateTextNode { root: Some(2,), text: "hello" },
  158. AppendChildren { root: Some(1,), children: vec![2,] },
  159. CreateElement { root: Some(3,), tag: "div", children: 0 },
  160. CreateTextNode { root: Some(4,), text: "hello" },
  161. AppendChildren { root: Some(3,), children: vec![4,] },
  162. AppendChildren { root: Some(0,), children: vec![1, 3,] },
  163. ]
  164. );
  165. assert_eq!(
  166. change.edits,
  167. [
  168. CreatePlaceholder { root: Some(5,) },
  169. ReplaceWith { root: Some(1,), nodes: vec![5,] },
  170. Remove { root: Some(3,) },
  171. ]
  172. );
  173. }
  174. /// Should result in no edits
  175. #[test]
  176. fn two_equal_fragments_are_equal() {
  177. let dom = new_dom();
  178. let left = rsx_without_templates!({
  179. (0..2).map(|_| {
  180. rsx_without_templates! { div { "hello" }}
  181. })
  182. });
  183. let right = rsx_without_templates!({
  184. (0..2).map(|_| {
  185. rsx_without_templates! { div { "hello" }}
  186. })
  187. });
  188. let (_create, change) = dom.diff_lazynodes(left, right);
  189. assert!(change.edits.is_empty());
  190. }
  191. /// Should result the creation of more nodes appended after the old last node
  192. #[test]
  193. fn two_fragments_with_differrent_elements_are_differet() {
  194. let dom = new_dom();
  195. let left = rsx_without_templates!(
  196. { (0..2).map(|_| rsx_without_templates! { div { }} ) }
  197. p {}
  198. );
  199. let right = rsx_without_templates!(
  200. { (0..5).map(|_| rsx_without_templates! (h1 { }) ) }
  201. p {}
  202. );
  203. let (_create, changes) = dom.diff_lazynodes(left, right);
  204. assert_eq!(
  205. changes.edits,
  206. [
  207. CreateElement { root: Some(4,), tag: "h1", children: 0 },
  208. CreateElement { root: Some(5,), tag: "h1", children: 0 },
  209. CreateElement { root: Some(6,), tag: "h1", children: 0 },
  210. InsertAfter { root: Some(2,), nodes: vec![4, 5, 6,] },
  211. CreateElement { root: Some(7,), tag: "h1", children: 0 },
  212. ReplaceWith { root: Some(1,), nodes: vec![7,] }, // notice how 1 gets re-used
  213. CreateElement { root: Some(1,), tag: "h1", children: 0 },
  214. ReplaceWith { root: Some(2,), nodes: vec![1,] },
  215. ]
  216. );
  217. }
  218. /// Should result in multiple nodes destroyed - with changes to the first nodes
  219. #[test]
  220. fn two_fragments_with_differrent_elements_are_differet_shorter() {
  221. let dom = new_dom();
  222. let left = rsx_without_templates!(
  223. {(0..5).map(|f| {rsx_without_templates! { div { }}})}
  224. p {}
  225. );
  226. let right = rsx_without_templates!(
  227. {(0..2).map(|f| {rsx_without_templates! { h1 { }}})}
  228. p {}
  229. );
  230. let (create, change) = dom.diff_lazynodes(left, right);
  231. assert_eq!(
  232. create.edits,
  233. [
  234. CreateElement { root: Some(1,), tag: "div", children: 0 },
  235. CreateElement { root: Some(2,), tag: "div", children: 0 },
  236. CreateElement { root: Some(3,), tag: "div", children: 0 },
  237. CreateElement { root: Some(4,), tag: "div", children: 0 },
  238. CreateElement { root: Some(5,), tag: "div", children: 0 },
  239. CreateElement { root: Some(6,), tag: "p", children: 0 },
  240. AppendChildren { root: Some(0,), children: vec![1, 2, 3, 4, 5, 6,] },
  241. ]
  242. );
  243. // note: key reuse is always the last node that got used
  244. // slab maintains a linked list, essentially
  245. assert_eq!(
  246. change.edits,
  247. [
  248. Remove { root: Some(3,) },
  249. Remove { root: Some(4,) },
  250. Remove { root: Some(5,) },
  251. CreateElement { root: Some(5,), tag: "h1", children: 0 }, // 5 gets reused
  252. ReplaceWith { root: Some(1,), nodes: vec![5,] }, // 1 gets deleted
  253. CreateElement { root: Some(1,), tag: "h1", children: 0 }, // 1 gets reused
  254. ReplaceWith { root: Some(2,), nodes: vec![1,] },
  255. ]
  256. );
  257. }
  258. /// Should result in multiple nodes destroyed - with no changes
  259. #[test]
  260. fn two_fragments_with_same_elements_are_differet() {
  261. let dom = new_dom();
  262. let left = rsx_without_templates!(
  263. {(0..2).map(|f| rsx_without_templates! { div { }})}
  264. p {}
  265. );
  266. let right = rsx_without_templates!(
  267. {(0..5).map(|f| rsx_without_templates! { div { }})}
  268. p {}
  269. );
  270. let (create, change) = dom.diff_lazynodes(left, right);
  271. assert_eq!(
  272. create.edits,
  273. [
  274. CreateElement { root: Some(1,), tag: "div", children: 0 },
  275. CreateElement { root: Some(2,), tag: "div", children: 0 },
  276. CreateElement { root: Some(3,), tag: "p", children: 0 },
  277. AppendChildren { root: Some(0,), children: vec![1, 2, 3,] },
  278. ]
  279. );
  280. assert_eq!(
  281. change.edits,
  282. [
  283. CreateElement { root: Some(4,), tag: "div", children: 0 },
  284. CreateElement { root: Some(5,), tag: "div", children: 0 },
  285. CreateElement { root: Some(6,), tag: "div", children: 0 },
  286. InsertAfter { root: Some(2,), nodes: vec![4, 5, 6,] },
  287. ]
  288. );
  289. }
  290. /// should result in the removal of elements
  291. #[test]
  292. fn keyed_diffing_order() {
  293. let dom = new_dom();
  294. let left = rsx_without_templates!(
  295. {(0..5).map(|f| {rsx_without_templates! { div { key: "{f}" }}})}
  296. p {"e"}
  297. );
  298. let right = rsx_without_templates!(
  299. {(0..2).map(|f| rsx_without_templates! { div { key: "{f}" }})}
  300. p {"e"}
  301. );
  302. let (create, change) = dom.diff_lazynodes(left, right);
  303. assert_eq!(
  304. change.edits,
  305. [
  306. Remove { root: Some(3,) },
  307. Remove { root: Some(4,) },
  308. Remove { root: Some(5,) },
  309. ]
  310. );
  311. }
  312. /// Should result in moves, but not removals or additions
  313. #[test]
  314. fn keyed_diffing_out_of_order() {
  315. let dom = new_dom();
  316. let left = rsx_without_templates!({
  317. [0, 1, 2, 3, /**/ 4, 5, 6, /**/ 7, 8, 9].iter().map(|f| {
  318. rsx_without_templates! { div { key: "{f}" }}
  319. })
  320. });
  321. let right = rsx_without_templates!({
  322. [0, 1, 2, 3, /**/ 6, 4, 5, /**/ 7, 8, 9].iter().map(|f| {
  323. rsx_without_templates! { div { key: "{f}" }}
  324. })
  325. });
  326. let (_, changes) = dom.diff_lazynodes(left, right);
  327. assert_eq!(
  328. changes.edits,
  329. [InsertBefore { root: Some(5,), nodes: vec![7,] },]
  330. );
  331. }
  332. /// Should result in moves only
  333. #[test]
  334. fn keyed_diffing_out_of_order_adds() {
  335. let dom = new_dom();
  336. let left = rsx_without_templates!({
  337. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  338. rsx_without_templates! { div { key: "{f}" }}
  339. })
  340. });
  341. let right = rsx_without_templates!({
  342. [/**/ 8, 7, 4, 5, 6 /**/].iter().map(|f| {
  343. rsx_without_templates! { div { key: "{f}" }}
  344. })
  345. });
  346. let (_, change) = dom.diff_lazynodes(left, right);
  347. assert_eq!(
  348. change.edits,
  349. [InsertBefore { root: Some(1,), nodes: vec![5, 4,] },]
  350. );
  351. }
  352. /// Should result in moves only
  353. #[test]
  354. fn keyed_diffing_out_of_order_adds_2() {
  355. let dom = new_dom();
  356. let left = rsx_without_templates!({
  357. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  358. rsx_without_templates! { div { key: "{f}" }}
  359. })
  360. });
  361. let right = rsx_without_templates!({
  362. [/**/ 7, 8, 4, 5, 6 /**/].iter().map(|f| {
  363. rsx_without_templates! { div { key: "{f}" }}
  364. })
  365. });
  366. let (_, change) = dom.diff_lazynodes(left, right);
  367. assert_eq!(
  368. change.edits,
  369. [InsertBefore { root: Some(1,), nodes: vec![4, 5,] },]
  370. );
  371. }
  372. /// Should result in moves onl
  373. #[test]
  374. fn keyed_diffing_out_of_order_adds_3() {
  375. let dom = new_dom();
  376. let left = rsx_without_templates!({
  377. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  378. rsx_without_templates! { div { key: "{f}" }}
  379. })
  380. });
  381. let right = rsx_without_templates!({
  382. [/**/ 4, 8, 7, 5, 6 /**/].iter().map(|f| {
  383. rsx_without_templates! { div { key: "{f}" }}
  384. })
  385. });
  386. let (_, change) = dom.diff_lazynodes(left, right);
  387. assert_eq!(
  388. change.edits,
  389. [InsertBefore { root: Some(2,), nodes: vec![5, 4,] },]
  390. );
  391. }
  392. /// Should result in moves onl
  393. #[test]
  394. fn keyed_diffing_out_of_order_adds_4() {
  395. let dom = new_dom();
  396. let left = rsx_without_templates!({
  397. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  398. rsx_without_templates! { div { key: "{f}" }}
  399. })
  400. });
  401. let right = rsx_without_templates!({
  402. [/**/ 4, 5, 8, 7, 6 /**/].iter().map(|f| {
  403. rsx_without_templates! { div { key: "{f}" }}
  404. })
  405. });
  406. let (_, change) = dom.diff_lazynodes(left, right);
  407. assert_eq!(
  408. change.edits,
  409. [InsertBefore { root: Some(3), nodes: vec![5, 4,] },]
  410. );
  411. }
  412. /// Should result in moves onl
  413. #[test]
  414. fn keyed_diffing_out_of_order_adds_5() {
  415. let dom = new_dom();
  416. let left = rsx_without_templates!({
  417. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  418. rsx_without_templates! { div { key: "{f}" }}
  419. })
  420. });
  421. let right = rsx_without_templates!({
  422. [/**/ 4, 5, 6, 8, 7 /**/].iter().map(|f| {
  423. rsx_without_templates! { div { key: "{f}" }}
  424. })
  425. });
  426. let (_, change) = dom.diff_lazynodes(left, right);
  427. assert_eq!(
  428. change.edits,
  429. [InsertBefore { root: Some(4), nodes: vec![5] }]
  430. );
  431. }
  432. #[test]
  433. fn keyed_diffing_additions() {
  434. let dom = new_dom();
  435. let left = rsx_without_templates!({
  436. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  437. rsx_without_templates! { div { key: "{f}" }}
  438. })
  439. });
  440. let right = rsx_without_templates!({
  441. [/**/ 4, 5, 6, 7, 8, 9, 10 /**/].iter().map(|f| {
  442. rsx_without_templates! { div { key: "{f}" }}
  443. })
  444. });
  445. let (_, change) = dom.diff_lazynodes(left, right);
  446. assert_eq!(
  447. change.edits,
  448. [
  449. CreateElement { root: Some(6,), tag: "div", children: 0 },
  450. CreateElement { root: Some(7,), tag: "div", children: 0 },
  451. InsertAfter { root: Some(5,), nodes: vec![6, 7,] },
  452. ]
  453. );
  454. }
  455. #[test]
  456. fn keyed_diffing_additions_and_moves_on_ends() {
  457. let dom = new_dom();
  458. let left = rsx_without_templates!({
  459. [/**/ 4, 5, 6, 7 /**/].iter().map(|f| {
  460. rsx_without_templates! { div { key: "{f}" }}
  461. })
  462. });
  463. let right = rsx_without_templates!({
  464. [/**/ 7, 4, 5, 6, 11, 12 /**/].iter().map(|f| {
  465. rsx_without_templates! { div { key: "{f}" }}
  466. })
  467. });
  468. let (_, change) = dom.diff_lazynodes(left, right);
  469. println!("{:?}", change);
  470. assert_eq!(
  471. change.edits,
  472. [
  473. // create 11, 12
  474. CreateElement { root: Some(5), tag: "div", children: 0 },
  475. CreateElement { root: Some(6), tag: "div", children: 0 },
  476. InsertAfter { root: Some(3), nodes: vec![5, 6] },
  477. // // move 7 to the front
  478. InsertBefore { root: Some(1), nodes: vec![4] }
  479. ]
  480. );
  481. }
  482. #[test]
  483. fn keyed_diffing_additions_and_moves_in_middle() {
  484. let dom = new_dom();
  485. let left = rsx_without_templates!({
  486. [/**/ 1, 2, 3, 4 /**/].iter().map(|f| {
  487. rsx_without_templates! { div { key: "{f}" }}
  488. })
  489. });
  490. let right = rsx_without_templates!({
  491. [/**/ 4, 1, 7, 8, 2, 5, 6, 3 /**/].iter().map(|f| {
  492. rsx_without_templates! { div { key: "{f}" }}
  493. })
  494. });
  495. // LIS: 4, 5, 6
  496. let (_, change) = dom.diff_lazynodes(left, right);
  497. println!("{:#?}", change);
  498. assert_eq!(
  499. change.edits,
  500. [
  501. // create 5, 6
  502. CreateElement { root: Some(5,), tag: "div", children: 0 },
  503. CreateElement { root: Some(6,), tag: "div", children: 0 },
  504. InsertBefore { root: Some(3,), nodes: vec![5, 6,] },
  505. // create 7, 8
  506. CreateElement { root: Some(7,), tag: "div", children: 0 },
  507. CreateElement { root: Some(8,), tag: "div", children: 0 },
  508. InsertBefore { root: Some(2,), nodes: vec![7, 8,] },
  509. // move 7
  510. InsertBefore { root: Some(1,), nodes: vec![4,] },
  511. ]
  512. );
  513. }
  514. #[test]
  515. fn controlled_keyed_diffing_out_of_order() {
  516. let dom = new_dom();
  517. let left = rsx_without_templates!({
  518. [4, 5, 6, 7].iter().map(|f| {
  519. rsx_without_templates! { div { key: "{f}" }}
  520. })
  521. });
  522. let right = rsx_without_templates!({
  523. [0, 5, 9, 6, 4].iter().map(|f| {
  524. rsx_without_templates! { div { key: "{f}" }}
  525. })
  526. });
  527. // LIS: 5, 6
  528. let (_, changes) = dom.diff_lazynodes(left, right);
  529. println!("{:#?}", &changes);
  530. assert_eq!(
  531. changes.edits,
  532. [
  533. // remove 7
  534. Remove { root: Some(4,) },
  535. // move 4 to after 6
  536. InsertAfter { root: Some(3,), nodes: vec![1,] },
  537. // create 9 and insert before 6
  538. CreateElement { root: Some(4,), tag: "div", children: 0 },
  539. InsertBefore { root: Some(3,), nodes: vec![4,] },
  540. // create 0 and insert before 5
  541. CreateElement { root: Some(5,), tag: "div", children: 0 },
  542. InsertBefore { root: Some(2,), nodes: vec![5,] },
  543. ]
  544. );
  545. }
  546. #[test]
  547. fn controlled_keyed_diffing_out_of_order_max_test() {
  548. let dom = new_dom();
  549. let left = rsx_without_templates!({
  550. [0, 1, 2, 3, 4].iter().map(|f| {
  551. rsx_without_templates! { div { key: "{f}" }}
  552. })
  553. });
  554. let right = rsx_without_templates!({
  555. [3, 0, 1, 10, 2].iter().map(|f| {
  556. rsx_without_templates! { div { key: "{f}" }}
  557. })
  558. });
  559. let (_, changes) = dom.diff_lazynodes(left, right);
  560. println!("{:#?}", &changes);
  561. assert_eq!(
  562. changes.edits,
  563. [
  564. Remove { root: Some(5,) },
  565. CreateElement { root: Some(5,), tag: "div", children: 0 },
  566. InsertBefore { root: Some(3,), nodes: vec![5,] },
  567. InsertBefore { root: Some(1,), nodes: vec![4,] },
  568. ]
  569. );
  570. }
  571. // noticed some weird behavior in the desktop interpreter
  572. // just making sure it doesnt happen in the core implementation
  573. #[test]
  574. fn remove_list() {
  575. let dom = new_dom();
  576. let left = rsx_without_templates!({
  577. (0..10).rev().take(5).map(|i| {
  578. rsx_without_templates! { Fragment { key: "{i}", "{i}" }}
  579. })
  580. });
  581. let right = rsx_without_templates!({
  582. (0..10).rev().take(2).map(|i| {
  583. rsx_without_templates! { Fragment { key: "{i}", "{i}" }}
  584. })
  585. });
  586. let (create, changes) = dom.diff_lazynodes(left, right);
  587. // dbg!(create);
  588. // dbg!(changes);
  589. assert_eq!(
  590. changes.edits,
  591. // remove 5, 4, 3
  592. [
  593. Remove { root: Some(3) },
  594. Remove { root: Some(4) },
  595. Remove { root: Some(5) }
  596. ]
  597. );
  598. }
  599. // noticed some weird behavior in the desktop interpreter
  600. // just making sure it doesnt happen in the core implementation
  601. #[test]
  602. fn remove_list_nokeyed() {
  603. let dom = new_dom();
  604. let left = rsx_without_templates!({
  605. (0..10).rev().take(5).map(|i| {
  606. rsx_without_templates! { Fragment { "{i}" }}
  607. })
  608. });
  609. let right = rsx_without_templates!({
  610. (0..10).rev().take(2).map(|i| {
  611. rsx_without_templates! { Fragment { "{i}" }}
  612. })
  613. });
  614. let (create, changes) = dom.diff_lazynodes(left, right);
  615. assert_eq!(
  616. changes.edits,
  617. [
  618. // remove 5, 4, 3
  619. Remove { root: Some(3) },
  620. Remove { root: Some(4) },
  621. Remove { root: Some(5) },
  622. ]
  623. );
  624. }
  625. #[test]
  626. fn add_nested_elements() {
  627. let vdom = new_dom();
  628. let (_create, change) = vdom.diff_lazynodes(
  629. rsx_without_templates! {
  630. div{}
  631. },
  632. rsx_without_templates! {
  633. div{
  634. div{}
  635. }
  636. },
  637. );
  638. assert_eq!(
  639. change.edits,
  640. [
  641. CreateElement { root: Some(2), tag: "div", children: 0 },
  642. AppendChildren { root: Some(1), children: vec![2] },
  643. ]
  644. );
  645. }
  646. #[test]
  647. fn add_listeners() {
  648. let vdom = new_dom();
  649. let (_create, change) = vdom.diff_lazynodes(
  650. rsx_without_templates! {
  651. div{}
  652. },
  653. rsx_without_templates! {
  654. div{
  655. onkeyup: |_| {},
  656. onkeydown: |_| {},
  657. }
  658. },
  659. );
  660. assert_eq!(
  661. change.edits,
  662. [
  663. NewEventListener { event_name: "keyup", scope: ScopeId(0), root: Some(1) },
  664. NewEventListener { event_name: "keydown", scope: ScopeId(0), root: Some(1) },
  665. ]
  666. );
  667. }
  668. #[test]
  669. fn remove_listeners() {
  670. let vdom = new_dom();
  671. let (_create, change) = vdom.diff_lazynodes(
  672. rsx_without_templates! {
  673. div{
  674. onkeyup: |_| {},
  675. onkeydown: |_| {},
  676. }
  677. },
  678. rsx_without_templates! {
  679. div{}
  680. },
  681. );
  682. assert_eq!(
  683. change.edits,
  684. [
  685. RemoveEventListener { event: "keyup", root: Some(1) },
  686. RemoveEventListener { event: "keydown", root: Some(1) },
  687. ]
  688. );
  689. }
  690. #[test]
  691. fn diff_listeners() {
  692. let vdom = new_dom();
  693. let (_create, change) = vdom.diff_lazynodes(
  694. rsx_without_templates! {
  695. div{
  696. onkeydown: |_| {},
  697. }
  698. },
  699. rsx_without_templates! {
  700. div{
  701. onkeyup: |_| {},
  702. }
  703. },
  704. );
  705. assert_eq!(
  706. change.edits,
  707. [
  708. RemoveEventListener { root: Some(1), event: "keydown" },
  709. NewEventListener { event_name: "keyup", scope: ScopeId(0), root: Some(1) }
  710. ]
  711. );
  712. }