1
0

diffing.rs 20 KB

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