|
@@ -6,661 +6,298 @@
|
|
|
//!
|
|
|
//! It does not validated that component lifecycles work properly. This is done in another test file.
|
|
|
|
|
|
-use dioxus::{core_macro::rsx_without_templates, prelude::*};
|
|
|
+use dioxus::core::{ElementId, Mutation::*};
|
|
|
+use dioxus::prelude::*;
|
|
|
|
|
|
-fn new_dom() -> VirtualDom {
|
|
|
- VirtualDom::new(|cx| cx.render(rsx_without_templates!("hi")))
|
|
|
-}
|
|
|
-
|
|
|
-use dioxus_core::DomEdit::*;
|
|
|
-
|
|
|
-/// Should push the text node onto the stack and modify it
|
|
|
-#[test]
|
|
|
-fn html_and_rsx_generate_the_same_output() {
|
|
|
- let dom = new_dom();
|
|
|
- let (create, change) = dom.diff_lazynodes(
|
|
|
- rsx_without_templates! ( div { "Hello world" } ),
|
|
|
- rsx_without_templates! ( div { "Goodbye world" } ),
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- create.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(1,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(2,), text: "Hello world" },
|
|
|
- AppendChildren { root: Some(1,), children: vec![2] },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1] },
|
|
|
- ]
|
|
|
- );
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [SetText { root: Some(2,), text: "Goodbye world" },]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in 3 elements on the stack
|
|
|
-#[test]
|
|
|
-fn fragments_create_properly() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let create = dom.create_vnodes(rsx_without_templates! {
|
|
|
- div { "Hello a" }
|
|
|
- div { "Hello b" }
|
|
|
- div { "Hello c" }
|
|
|
- });
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- create.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(1,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(2,), text: "Hello a" },
|
|
|
- AppendChildren { root: Some(1,), children: vec![2,] },
|
|
|
- CreateElement { root: Some(3,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(4,), text: "Hello b" },
|
|
|
- AppendChildren { root: Some(3,), children: vec![4,] },
|
|
|
- CreateElement { root: Some(5,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(6,), text: "Hello c" },
|
|
|
- AppendChildren { root: Some(5,), children: vec![6,] },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1, 3, 5,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in the creation of an anchor (placeholder) and then a replacewith
|
|
|
-#[test]
|
|
|
-fn empty_fragments_create_anchors() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({ (0..0).map(|_f| rsx_without_templates! { div {}}) });
|
|
|
- let right = rsx_without_templates!({ (0..1).map(|_f| rsx_without_templates! { div {}}) });
|
|
|
-
|
|
|
- let (create, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- create.edits,
|
|
|
- [
|
|
|
- CreatePlaceholder { root: Some(1,) },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1,] },
|
|
|
- ]
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(2,), tag: "div", children: 0 },
|
|
|
- ReplaceWith { root: Some(1,), nodes: vec![2,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in the creation of an anchor (placeholder) and then a replacewith m=5
|
|
|
-#[test]
|
|
|
-fn empty_fragments_create_many_anchors() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({ (0..0).map(|_f| rsx_without_templates! { div {}}) });
|
|
|
- let right = rsx_without_templates!({ (0..5).map(|_f| rsx_without_templates! { div {}}) });
|
|
|
-
|
|
|
- let (create, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- create.edits,
|
|
|
- [
|
|
|
- CreatePlaceholder { root: Some(1,) },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(2,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(3,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(4,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(5,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(6,), tag: "div", children: 0 },
|
|
|
- ReplaceWith { root: Some(1,), nodes: vec![2, 3, 4, 5, 6,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in the creation of an anchor (placeholder) and then a replacewith
|
|
|
-/// Includes child nodes inside the fragment
|
|
|
-#[test]
|
|
|
-fn empty_fragments_create_anchors_with_many_children() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({ (0..0).map(|_| rsx_without_templates! { div {} }) });
|
|
|
- let right = rsx_without_templates!({
|
|
|
- (0..3).map(|f| {
|
|
|
- rsx_without_templates! { div { "hello: {f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let (create, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- create.edits,
|
|
|
- [
|
|
|
- CreatePlaceholder { root: Some(1,) },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(2,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(3,), text: "hello: 0" },
|
|
|
- AppendChildren { root: Some(2,), children: vec![3,] },
|
|
|
- CreateElement { root: Some(4,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(5,), text: "hello: 1" },
|
|
|
- AppendChildren { root: Some(4,), children: vec![5,] },
|
|
|
- CreateElement { root: Some(6,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(7,), text: "hello: 2" },
|
|
|
- AppendChildren { root: Some(6,), children: vec![7,] },
|
|
|
- ReplaceWith { root: Some(1,), nodes: vec![2, 4, 6,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in every node being pushed and then replaced with an anchor
|
|
|
+/// Should result in moves, but not removals or additions
|
|
|
#[test]
|
|
|
-fn many_items_become_fragment() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- (0..2).map(|_| {
|
|
|
- rsx_without_templates! { div { "hello" }}
|
|
|
- })
|
|
|
+fn keyed_diffing_out_of_order() {
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order = match cx.generation() % 2 {
|
|
|
+ 0 => &[0, 1, 2, 3, /**/ 4, 5, 6, /**/ 7, 8, 9],
|
|
|
+ 1 => &[0, 1, 2, 3, /**/ 6, 4, 5, /**/ 7, 8, 9],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
- let right = rsx_without_templates!({ (0..0).map(|_| rsx_without_templates! { div {} }) });
|
|
|
-
|
|
|
- let (create, change) = dom.diff_lazynodes(left, right);
|
|
|
|
|
|
assert_eq!(
|
|
|
- create.edits,
|
|
|
+ dom.rebuild().santize().edits,
|
|
|
[
|
|
|
- CreateElement { root: Some(1,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(2,), text: "hello" },
|
|
|
- AppendChildren { root: Some(1,), children: vec![2,] },
|
|
|
- CreateElement { root: Some(3,), tag: "div", children: 0 },
|
|
|
- CreateTextNode { root: Some(4,), text: "hello" },
|
|
|
- AppendChildren { root: Some(3,), children: vec![4,] },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1, 3,] },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(4,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(5,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(6,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(7,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(8,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(9,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(10,) },
|
|
|
+ AppendChildren { m: 10 },
|
|
|
]
|
|
|
);
|
|
|
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
+ dom.render_immediate().edits,
|
|
|
[
|
|
|
- CreatePlaceholder { root: Some(5,) },
|
|
|
- ReplaceWith { root: Some(1,), nodes: vec![5,] },
|
|
|
- Remove { root: Some(3,) },
|
|
|
+ PushRoot { id: ElementId(7,) },
|
|
|
+ InsertBefore { id: ElementId(5,), m: 1 },
|
|
|
]
|
|
|
- );
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
-/// Should result in no edits
|
|
|
+/// Should result in moves only
|
|
|
#[test]
|
|
|
-fn two_equal_fragments_are_equal() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- (0..2).map(|_| {
|
|
|
- rsx_without_templates! { div { "hello" }}
|
|
|
- })
|
|
|
- });
|
|
|
- let right = rsx_without_templates!({
|
|
|
- (0..2).map(|_| {
|
|
|
- rsx_without_templates! { div { "hello" }}
|
|
|
- })
|
|
|
+fn keyed_diffing_out_of_order_adds() {
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order = match cx.generation() % 2 {
|
|
|
+ 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
|
|
|
+ 1 => &[/**/ 8, 7, 4, 5, 6 /**/],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let (_create, change) = dom.diff_lazynodes(left, right);
|
|
|
- assert!(change.edits.is_empty());
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result the creation of more nodes appended after the old last node
|
|
|
-#[test]
|
|
|
-fn two_fragments_with_differrent_elements_are_differet() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!(
|
|
|
- { (0..2).map(|_| rsx_without_templates! { div { }} ) }
|
|
|
- p {}
|
|
|
- );
|
|
|
- let right = rsx_without_templates!(
|
|
|
- { (0..5).map(|_| rsx_without_templates! (h1 { }) ) }
|
|
|
- p {}
|
|
|
- );
|
|
|
-
|
|
|
- let (_create, changes) = dom.diff_lazynodes(left, right);
|
|
|
- assert_eq!(
|
|
|
- changes.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(4,), tag: "h1", children: 0 },
|
|
|
- CreateElement { root: Some(5,), tag: "h1", children: 0 },
|
|
|
- CreateElement { root: Some(6,), tag: "h1", children: 0 },
|
|
|
- InsertAfter { root: Some(2,), nodes: vec![4, 5, 6,] },
|
|
|
- CreateElement { root: Some(7,), tag: "h1", children: 0 },
|
|
|
- ReplaceWith { root: Some(1,), nodes: vec![7,] }, // notice how 1 gets re-used
|
|
|
- CreateElement { root: Some(1,), tag: "h1", children: 0 },
|
|
|
- ReplaceWith { root: Some(2,), nodes: vec![1,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in multiple nodes destroyed - with changes to the first nodes
|
|
|
-#[test]
|
|
|
-fn two_fragments_with_differrent_elements_are_differet_shorter() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!(
|
|
|
- {(0..5).map(|f| {rsx_without_templates! { div { }}})}
|
|
|
- p {}
|
|
|
- );
|
|
|
- let right = rsx_without_templates!(
|
|
|
- {(0..2).map(|f| {rsx_without_templates! { h1 { }}})}
|
|
|
- p {}
|
|
|
- );
|
|
|
-
|
|
|
- let (create, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- create.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(1,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(2,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(3,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(4,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(5,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(6,), tag: "p", children: 0 },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1, 2, 3, 4, 5, 6,] },
|
|
|
- ]
|
|
|
- );
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
- // note: key reuse is always the last node that got used
|
|
|
- // slab maintains a linked list, essentially
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
+ dom.render_immediate().edits,
|
|
|
[
|
|
|
- Remove { root: Some(3,) },
|
|
|
- Remove { root: Some(4,) },
|
|
|
- Remove { root: Some(5,) },
|
|
|
- CreateElement { root: Some(5,), tag: "h1", children: 0 }, // 5 gets reused
|
|
|
- ReplaceWith { root: Some(1,), nodes: vec![5,] }, // 1 gets deleted
|
|
|
- CreateElement { root: Some(1,), tag: "h1", children: 0 }, // 1 gets reused
|
|
|
- ReplaceWith { root: Some(2,), nodes: vec![1,] },
|
|
|
+ PushRoot { id: ElementId(5,) },
|
|
|
+ PushRoot { id: ElementId(4,) },
|
|
|
+ InsertBefore { id: ElementId(1,), m: 2 },
|
|
|
]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in multiple nodes destroyed - with no changes
|
|
|
-#[test]
|
|
|
-fn two_fragments_with_same_elements_are_differet() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!(
|
|
|
- {(0..2).map(|f| rsx_without_templates! { div { }})}
|
|
|
- p {}
|
|
|
- );
|
|
|
- let right = rsx_without_templates!(
|
|
|
- {(0..5).map(|f| rsx_without_templates! { div { }})}
|
|
|
- p {}
|
|
|
- );
|
|
|
-
|
|
|
- let (create, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- create.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(1,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(2,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(3,), tag: "p", children: 0 },
|
|
|
- AppendChildren { root: Some(0,), children: vec![1, 2, 3,] },
|
|
|
- ]
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(4,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(5,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(6,), tag: "div", children: 0 },
|
|
|
- InsertAfter { root: Some(2,), nodes: vec![4, 5, 6,] },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// should result in the removal of elements
|
|
|
-#[test]
|
|
|
-fn keyed_diffing_order() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!(
|
|
|
- {(0..5).map(|f| {rsx_without_templates! { div { key: "{f}" }}})}
|
|
|
- p {"e"}
|
|
|
- );
|
|
|
- let right = rsx_without_templates!(
|
|
|
- {(0..2).map(|f| rsx_without_templates! { div { key: "{f}" }})}
|
|
|
- p {"e"}
|
|
|
- );
|
|
|
-
|
|
|
- let (create, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- Remove { root: Some(3,) },
|
|
|
- Remove { root: Some(4,) },
|
|
|
- Remove { root: Some(5,) },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in moves, but not removals or additions
|
|
|
-#[test]
|
|
|
-fn keyed_diffing_out_of_order() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [0, 1, 2, 3, /**/ 4, 5, 6, /**/ 7, 8, 9].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [0, 1, 2, 3, /**/ 6, 4, 5, /**/ 7, 8, 9].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let (_, changes) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- changes.edits,
|
|
|
- [InsertBefore { root: Some(5,), nodes: vec![7,] },]
|
|
|
- );
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
/// Should result in moves only
|
|
|
#[test]
|
|
|
-fn keyed_diffing_out_of_order_adds() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 8, 7, 4, 5, 6 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [InsertBefore { root: Some(1,), nodes: vec![5, 4,] },]
|
|
|
- );
|
|
|
-}
|
|
|
-/// Should result in moves only
|
|
|
-#[test]
|
|
|
-fn keyed_diffing_out_of_order_adds_2() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 7, 8, 4, 5, 6 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [InsertBefore { root: Some(1,), nodes: vec![4, 5,] },]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/// Should result in moves onl
|
|
|
-#[test]
|
|
|
fn keyed_diffing_out_of_order_adds_3() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order = match cx.generation() % 2 {
|
|
|
+ 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
|
|
|
+ 1 => &[/**/ 4, 8, 7, 5, 6 /**/],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 4, 8, 7, 5, 6 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
- [InsertBefore { root: Some(2,), nodes: vec![5, 4,] },]
|
|
|
+ dom.render_immediate().edits,
|
|
|
+ [
|
|
|
+ PushRoot { id: ElementId(5,) },
|
|
|
+ PushRoot { id: ElementId(4,) },
|
|
|
+ InsertBefore { id: ElementId(2,), m: 2 },
|
|
|
+ ]
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/// Should result in moves onl
|
|
|
#[test]
|
|
|
fn keyed_diffing_out_of_order_adds_4() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 8, 7, 6 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order = match cx.generation() % 2 {
|
|
|
+ 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
|
|
|
+ 1 => &[/**/ 4, 5, 8, 7, 6 /**/],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
- [InsertBefore { root: Some(3), nodes: vec![5, 4,] },]
|
|
|
+ dom.render_immediate().edits,
|
|
|
+ [
|
|
|
+ PushRoot { id: ElementId(5,) },
|
|
|
+ PushRoot { id: ElementId(4,) },
|
|
|
+ InsertBefore { id: ElementId(3,), m: 2 },
|
|
|
+ ]
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/// Should result in moves onl
|
|
|
#[test]
|
|
|
fn keyed_diffing_out_of_order_adds_5() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order = match cx.generation() % 2 {
|
|
|
+ 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
|
|
|
+ 1 => &[/**/ 4, 5, 6, 8, 7 /**/],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 8, 7 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
- [InsertBefore { root: Some(4), nodes: vec![5] }]
|
|
|
+ dom.render_immediate().edits,
|
|
|
+ [
|
|
|
+ PushRoot { id: ElementId(5,) },
|
|
|
+ InsertBefore { id: ElementId(4,), m: 1 },
|
|
|
+ ]
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+/// Should result in moves onl
|
|
|
#[test]
|
|
|
fn keyed_diffing_additions() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order: &[_] = match cx.generation() % 2 {
|
|
|
+ 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
|
|
|
+ 1 => &[/**/ 4, 5, 6, 7, 8, 9, 10 /**/],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7, 8, 9, 10 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
+ dom.render_immediate().santize().edits,
|
|
|
[
|
|
|
- CreateElement { root: Some(6,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(7,), tag: "div", children: 0 },
|
|
|
- InsertAfter { root: Some(5,), nodes: vec![6, 7,] },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(7) },
|
|
|
+ InsertAfter { id: ElementId(5), m: 2 }
|
|
|
]
|
|
|
);
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn keyed_diffing_additions_and_moves_on_ends() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 4, 5, 6, 7 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order: &[_] = match cx.generation() % 2 {
|
|
|
+ 0 => &[/**/ 4, 5, 6, 7 /**/],
|
|
|
+ 1 => &[/**/ 7, 4, 5, 6, 11, 12 /**/],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 7, 4, 5, 6, 11, 12 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
- println!("{:?}", change);
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
+ dom.render_immediate().santize().edits,
|
|
|
[
|
|
|
// create 11, 12
|
|
|
- CreateElement { root: Some(5), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(6), tag: "div", children: 0 },
|
|
|
- InsertAfter { root: Some(3), nodes: vec![5, 6] },
|
|
|
- // // move 7 to the front
|
|
|
- InsertBefore { root: Some(1), nodes: vec![4] }
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
|
|
+ InsertAfter { id: ElementId(3), m: 2 },
|
|
|
+ // move 7 to the front
|
|
|
+ PushRoot { id: ElementId(4) },
|
|
|
+ InsertBefore { id: ElementId(1), m: 1 }
|
|
|
]
|
|
|
);
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn keyed_diffing_additions_and_moves_in_middle() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [/**/ 1, 2, 3, 4 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order: &[_] = match cx.generation() % 2 {
|
|
|
+ 0 => &[/**/ 1, 2, 3, 4 /**/],
|
|
|
+ 1 => &[/**/ 4, 1, 7, 8, 2, 5, 6, 3 /**/],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [/**/ 4, 1, 7, 8, 2, 5, 6, 3 /**/].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
// LIS: 4, 5, 6
|
|
|
- let (_, change) = dom.diff_lazynodes(left, right);
|
|
|
- println!("{:#?}", change);
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
+ dom.render_immediate().santize().edits,
|
|
|
[
|
|
|
// create 5, 6
|
|
|
- CreateElement { root: Some(5,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(6,), tag: "div", children: 0 },
|
|
|
- InsertBefore { root: Some(3,), nodes: vec![5, 6,] },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
|
|
+ InsertBefore { id: ElementId(3), m: 2 },
|
|
|
// create 7, 8
|
|
|
- CreateElement { root: Some(7,), tag: "div", children: 0 },
|
|
|
- CreateElement { root: Some(8,), tag: "div", children: 0 },
|
|
|
- InsertBefore { root: Some(2,), nodes: vec![7, 8,] },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(7) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(8) },
|
|
|
+ InsertBefore { id: ElementId(2), m: 2 },
|
|
|
// move 7
|
|
|
- InsertBefore { root: Some(1,), nodes: vec![4,] },
|
|
|
+ PushRoot { id: ElementId(4) },
|
|
|
+ InsertBefore { id: ElementId(1), m: 1 }
|
|
|
]
|
|
|
);
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn controlled_keyed_diffing_out_of_order() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [4, 5, 6, 7].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order: &[_] = match cx.generation() % 2 {
|
|
|
+ 0 => &[4, 5, 6, 7],
|
|
|
+ 1 => &[0, 5, 9, 6, 4],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [0, 5, 9, 6, 4].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
// LIS: 5, 6
|
|
|
- let (_, changes) = dom.diff_lazynodes(left, right);
|
|
|
- println!("{:#?}", &changes);
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- changes.edits,
|
|
|
+ dom.render_immediate().santize().edits,
|
|
|
[
|
|
|
// remove 7
|
|
|
- Remove { root: Some(4,) },
|
|
|
+ Remove { id: ElementId(4,) },
|
|
|
// move 4 to after 6
|
|
|
- InsertAfter { root: Some(3,), nodes: vec![1,] },
|
|
|
+ PushRoot { id: ElementId(1) },
|
|
|
+ InsertAfter { id: ElementId(3,), m: 1 },
|
|
|
// create 9 and insert before 6
|
|
|
- CreateElement { root: Some(4,), tag: "div", children: 0 },
|
|
|
- InsertBefore { root: Some(3,), nodes: vec![4,] },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(4) },
|
|
|
+ InsertBefore { id: ElementId(3,), m: 1 },
|
|
|
// create 0 and insert before 5
|
|
|
- CreateElement { root: Some(5,), tag: "div", children: 0 },
|
|
|
- InsertBefore { root: Some(2,), nodes: vec![5,] },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
|
|
+ InsertBefore { id: ElementId(2,), m: 1 },
|
|
|
]
|
|
|
);
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn controlled_keyed_diffing_out_of_order_max_test() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- [0, 1, 2, 3, 4].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order: &[_] = match cx.generation() % 2 {
|
|
|
+ 0 => &[0, 1, 2, 3, 4],
|
|
|
+ 1 => &[3, 0, 1, 10, 2],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let right = rsx_without_templates!({
|
|
|
- [3, 0, 1, 10, 2].iter().map(|f| {
|
|
|
- rsx_without_templates! { div { key: "{f}" }}
|
|
|
- })
|
|
|
- });
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
- let (_, changes) = dom.diff_lazynodes(left, right);
|
|
|
- println!("{:#?}", &changes);
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- changes.edits,
|
|
|
+ dom.render_immediate().santize().edits,
|
|
|
[
|
|
|
- Remove { root: Some(5,) },
|
|
|
- CreateElement { root: Some(5,), tag: "div", children: 0 },
|
|
|
- InsertBefore { root: Some(3,), nodes: vec![5,] },
|
|
|
- InsertBefore { root: Some(1,), nodes: vec![4,] },
|
|
|
+ Remove { id: ElementId(5,) },
|
|
|
+ LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
|
|
+ InsertBefore { id: ElementId(3,), m: 1 },
|
|
|
+ PushRoot { id: ElementId(4) },
|
|
|
+ InsertBefore { id: ElementId(1,), m: 1 },
|
|
|
]
|
|
|
);
|
|
|
}
|
|
@@ -669,163 +306,25 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
|
|
|
// just making sure it doesnt happen in the core implementation
|
|
|
#[test]
|
|
|
fn remove_list() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- (0..10).rev().take(5).map(|i| {
|
|
|
- rsx_without_templates! { Fragment { key: "{i}", "{i}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let right = rsx_without_templates!({
|
|
|
- (0..10).rev().take(2).map(|i| {
|
|
|
- rsx_without_templates! { Fragment { key: "{i}", "{i}" }}
|
|
|
- })
|
|
|
+ let mut dom = VirtualDom::new(|cx| {
|
|
|
+ let order: &[_] = match cx.generation() % 2 {
|
|
|
+ 0 => &[9, 8, 7, 6, 5],
|
|
|
+ 1 => &[9, 8],
|
|
|
+ _ => unreachable!(),
|
|
|
+ };
|
|
|
+
|
|
|
+ cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
|
|
});
|
|
|
|
|
|
- let (create, changes) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- // dbg!(create);
|
|
|
- // dbg!(changes);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- changes.edits,
|
|
|
- // remove 5, 4, 3
|
|
|
- [
|
|
|
- Remove { root: Some(3) },
|
|
|
- Remove { root: Some(4) },
|
|
|
- Remove { root: Some(5) }
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-// noticed some weird behavior in the desktop interpreter
|
|
|
-// just making sure it doesnt happen in the core implementation
|
|
|
-#[test]
|
|
|
-fn remove_list_nokeyed() {
|
|
|
- let dom = new_dom();
|
|
|
-
|
|
|
- let left = rsx_without_templates!({
|
|
|
- (0..10).rev().take(5).map(|i| {
|
|
|
- rsx_without_templates! { Fragment { "{i}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let right = rsx_without_templates!({
|
|
|
- (0..10).rev().take(2).map(|i| {
|
|
|
- rsx_without_templates! { Fragment { "{i}" }}
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- let (create, changes) = dom.diff_lazynodes(left, right);
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- changes.edits,
|
|
|
- [
|
|
|
- // remove 5, 4, 3
|
|
|
- Remove { root: Some(3) },
|
|
|
- Remove { root: Some(4) },
|
|
|
- Remove { root: Some(5) },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-#[test]
|
|
|
-fn add_nested_elements() {
|
|
|
- let vdom = new_dom();
|
|
|
-
|
|
|
- let (_create, change) = vdom.diff_lazynodes(
|
|
|
- rsx_without_templates! {
|
|
|
- div{}
|
|
|
- },
|
|
|
- rsx_without_templates! {
|
|
|
- div{
|
|
|
- div{}
|
|
|
- }
|
|
|
- },
|
|
|
- );
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- CreateElement { root: Some(2), tag: "div", children: 0 },
|
|
|
- AppendChildren { root: Some(1), children: vec![2] },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-#[test]
|
|
|
-fn add_listeners() {
|
|
|
- let vdom = new_dom();
|
|
|
-
|
|
|
- let (_create, change) = vdom.diff_lazynodes(
|
|
|
- rsx_without_templates! {
|
|
|
- div{}
|
|
|
- },
|
|
|
- rsx_without_templates! {
|
|
|
- div{
|
|
|
- onkeyup: |_| {},
|
|
|
- onkeydown: |_| {},
|
|
|
- }
|
|
|
- },
|
|
|
- );
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- NewEventListener { event_name: "keyup", scope: ScopeId(0), root: Some(1) },
|
|
|
- NewEventListener { event_name: "keydown", scope: ScopeId(0), root: Some(1) },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-#[test]
|
|
|
-fn remove_listeners() {
|
|
|
- let vdom = new_dom();
|
|
|
-
|
|
|
- let (_create, change) = vdom.diff_lazynodes(
|
|
|
- rsx_without_templates! {
|
|
|
- div{
|
|
|
- onkeyup: |_| {},
|
|
|
- onkeydown: |_| {},
|
|
|
- }
|
|
|
- },
|
|
|
- rsx_without_templates! {
|
|
|
- div{}
|
|
|
- },
|
|
|
- );
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- change.edits,
|
|
|
- [
|
|
|
- RemoveEventListener { event: "keyup", root: Some(1) },
|
|
|
- RemoveEventListener { event: "keydown", root: Some(1) },
|
|
|
- ]
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-#[test]
|
|
|
-fn diff_listeners() {
|
|
|
- let vdom = new_dom();
|
|
|
-
|
|
|
- let (_create, change) = vdom.diff_lazynodes(
|
|
|
- rsx_without_templates! {
|
|
|
- div{
|
|
|
- onkeydown: |_| {},
|
|
|
- }
|
|
|
- },
|
|
|
- rsx_without_templates! {
|
|
|
- div{
|
|
|
- onkeyup: |_| {},
|
|
|
- }
|
|
|
- },
|
|
|
- );
|
|
|
+ _ = dom.rebuild();
|
|
|
|
|
|
+ dom.mark_dirty_scope(ScopeId(0));
|
|
|
assert_eq!(
|
|
|
- change.edits,
|
|
|
+ dom.render_immediate().santize().edits,
|
|
|
[
|
|
|
- RemoveEventListener { root: Some(1), event: "keydown" },
|
|
|
- NewEventListener { event_name: "keyup", scope: ScopeId(0), root: Some(1) }
|
|
|
+ Remove { id: ElementId(3) },
|
|
|
+ Remove { id: ElementId(4) },
|
|
|
+ Remove { id: ElementId(5) }
|
|
|
]
|
|
|
);
|
|
|
}
|