diffing.rs 19 KB

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