Fix nested rsx expansion by not using template titles (#2799)
* Fix nested rsx expansion by not using template titles * fix writers with nameless templates * fix clippy * dont commit vscode fix * fix release mode, pull out __template_name * fix axum_desktop * Fix core tests * Make most fields of HotReloadedTemplate public for testing * wip: formatting, compare all diff cases * slightly smarter diffing for dynamic nodes * add a comment about generic node diffing * clean up mutations a bit * fix load template * simplify maybe_rebuild * Restore write mutations flag in web * write_mutations -> skip_mutations --------- Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
This commit is contained in:
1 parent
a2180b92e9
commit
0de3bf7aeb
40 files changed
+597
-1038
No files matched your search
@@ -21,18 +21,18 @@ fn attrs_cycle() {
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
AppendChildren { m: 1, id: ElementId(0) },
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
AssignId { path: &[0,], id: ElementId(3,) },
|
||||
SetAttribute { name: "class", value: "1".into_value(), id: ElementId(3,), ns: None },
|
||||
SetAttribute { name: "id", value: "1".into_value(), id: ElementId(3,), ns: None },
|
||||
@@ -42,18 +42,18 @@ fn attrs_cycle() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
ReplaceWith { id: ElementId(2), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2) },
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
AssignId { path: &[0], id: ElementId(3) },
|
||||
SetAttribute {
|
||||
name: "class",
|
||||
@@ -74,9 +74,9 @@ fn attrs_cycle() {
|
||||
// we take the node taken by attributes since we reused it
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
ReplaceWith { id: ElementId(2), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
@@ -6,9 +6,9 @@ fn bool_test() {
|
||||
let mut app = VirtualDom::new(|| rsx!(div { hidden: false }));
|
||||
|
||||
assert_eq!(
|
||||
app.rebuild_to_vec().sanitize().edits,
|
||||
app.rebuild_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
SetAttribute {
|
||||
name: "hidden",
|
||||
value: dioxus_core::AttributeValue::Bool(false),
|
||||
|
||||
@@ -19,7 +19,7 @@ fn bubbles_error() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
|
||||
{
|
||||
let _edits = dom.rebuild_to_vec().sanitize();
|
||||
let _edits = dom.rebuild_to_vec();
|
||||
}
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
|
||||
@@ -10,7 +10,7 @@ async fn child_futures_drop_first() {
|
||||
|
||||
fn app() -> Element {
|
||||
if generation() == 0 {
|
||||
rsx! {Child {}}
|
||||
rsx! { Child {} }
|
||||
} else {
|
||||
rsx! {}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ fn state_shares() {
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
CreateTextNode { value: "Value is 0".to_string(), id: ElementId(1,) },
|
||||
AppendChildren { m: 1, id: ElementId(0) },
|
||||
@@ -41,7 +41,7 @@ fn state_shares() {
|
||||
|
||||
dom.mark_dirty(ScopeId(ScopeId::APP.0 + 2));
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[SetText { value: "Value is 2".to_string(), id: ElementId(1,) },]
|
||||
);
|
||||
|
||||
@@ -49,7 +49,7 @@ fn state_shares() {
|
||||
dom.mark_dirty(ScopeId(ScopeId::APP.0 + 2));
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
edits.sanitize().edits,
|
||||
edits.edits,
|
||||
[SetText { value: "Value is 3".to_string(), id: ElementId(1,) },]
|
||||
);
|
||||
}
|
||||
@@ -17,13 +17,13 @@ fn test_original_diff() {
|
||||
}
|
||||
});
|
||||
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
// add to root
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
AppendChildren { m: 1, id: ElementId(0) }
|
||||
]
|
||||
)
|
||||
@@ -46,7 +46,7 @@ fn create() {
|
||||
}
|
||||
});
|
||||
|
||||
let _edits = dom.rebuild_to_vec().sanitize();
|
||||
let _edits = dom.rebuild_to_vec();
|
||||
|
||||
// todo: we don't test template mutations anymore since the templates are passed along
|
||||
|
||||
@@ -64,11 +64,11 @@ fn create() {
|
||||
// AppendChildren { m: 1 },
|
||||
// AppendChildren { m: 2 },
|
||||
// AppendChildren { m: 1 },
|
||||
// SaveTemplate { name: "template", m: 1 },
|
||||
// SaveTemplate { m: 1 },
|
||||
// // The fragment child template
|
||||
// CreateStaticText { value: "hello" },
|
||||
// CreateStaticText { value: "world" },
|
||||
// SaveTemplate { name: "template", m: 2 },
|
||||
// SaveTemplate { m: 2 },
|
||||
// ]
|
||||
// );
|
||||
}
|
||||
@@ -77,7 +77,7 @@ fn create() {
|
||||
fn create_list() {
|
||||
let mut dom = VirtualDom::new(|| rsx! {{(0..3).map(|f| rsx!( div { "hello" } ))}});
|
||||
|
||||
let _edits = dom.rebuild_to_vec().sanitize();
|
||||
let _edits = dom.rebuild_to_vec();
|
||||
|
||||
// note: we dont test template edits anymore
|
||||
// assert_eq!(
|
||||
@@ -87,7 +87,7 @@ fn create_list() {
|
||||
// CreateElement { name: "div" },
|
||||
// CreateStaticText { value: "hello" },
|
||||
// AppendChildren { m: 1 },
|
||||
// SaveTemplate { name: "template", m: 1 }
|
||||
// SaveTemplate { m: 1 }
|
||||
// ]
|
||||
// );
|
||||
}
|
||||
@@ -103,7 +103,7 @@ fn create_simple() {
|
||||
}
|
||||
});
|
||||
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
|
||||
// note: we dont test template edits anymore
|
||||
// assert_eq!(
|
||||
@@ -115,7 +115,7 @@ fn create_simple() {
|
||||
// CreateElement { name: "div" },
|
||||
// CreateElement { name: "div" },
|
||||
// // add to root
|
||||
// SaveTemplate { name: "template", m: 4 }
|
||||
// SaveTemplate { m: 4 }
|
||||
// ]
|
||||
// );
|
||||
}
|
||||
@@ -142,7 +142,7 @@ fn create_components() {
|
||||
}
|
||||
}
|
||||
|
||||
let _edits = dom.rebuild_to_vec().sanitize();
|
||||
let _edits = dom.rebuild_to_vec();
|
||||
|
||||
// todo: test this
|
||||
}
|
||||
@@ -161,7 +161,7 @@ fn anchors() {
|
||||
});
|
||||
|
||||
// note that the template under "false" doesn't show up since it's not loaded
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
|
||||
// note: we dont test template edits anymore
|
||||
// assert_eq!(
|
||||
@@ -178,7 +178,7 @@ fn anchors() {
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
CreatePlaceholder { id: ElementId(2) },
|
||||
AppendChildren { m: 2, id: ElementId(0) }
|
||||
]
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// use dioxus::dioxus_core::Mutation::*;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn multiroot() {
|
||||
let mut dom = VirtualDom::new(|| {
|
||||
rsx! {
|
||||
div { "Hello a" }
|
||||
div { "Hello b" }
|
||||
div { "Hello c" }
|
||||
}
|
||||
});
|
||||
|
||||
// note: we dont test template edits anymore
|
||||
let _templates = dom.rebuild_to_vec().sanitize().templates;
|
||||
|
||||
// assert_eq!(
|
||||
// dom.rebuild_to_vec().sanitize().templates,
|
||||
// [
|
||||
// CreateElement { name: "div" },
|
||||
// CreateStaticText { value: "Hello a" },
|
||||
// AppendChildren { m: 1 },
|
||||
// CreateElement { name: "div" },
|
||||
// CreateStaticText { value: "Hello b" },
|
||||
// AppendChildren { m: 1 },
|
||||
// CreateElement { name: "div" },
|
||||
// CreateStaticText { value: "Hello c" },
|
||||
// AppendChildren { m: 1 },
|
||||
// SaveTemplate { name: "template", m: 3 }
|
||||
// ]
|
||||
// )
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use dioxus::dioxus_core::Mutation::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core::ElementId;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
// A real-world usecase of templates at peak performance
|
||||
// In react, this would be a lot of node creation.
|
||||
@@ -25,7 +26,7 @@ fn app() -> Element {
|
||||
fn list_renders() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
|
||||
// note: we dont test template edits anymore
|
||||
// assert_eq!(
|
||||
@@ -37,7 +38,7 @@ fn list_renders() {
|
||||
// // append when modify the values (IE no need for a placeholder)
|
||||
// CreateStaticPlaceholder,
|
||||
// AppendChildren { m: 1 },
|
||||
// SaveTemplate { name: "template", m: 1 },
|
||||
// SaveTemplate { m: 1 },
|
||||
// // Create the inner template div
|
||||
// CreateElement { name: "div" },
|
||||
// CreateElement { name: "h1" },
|
||||
@@ -47,7 +48,7 @@ fn list_renders() {
|
||||
// CreateTextPlaceholder,
|
||||
// AppendChildren { m: 1 },
|
||||
// AppendChildren { m: 2 },
|
||||
// SaveTemplate { name: "template", m: 1 }
|
||||
// SaveTemplate { m: 1 }
|
||||
// ],
|
||||
// );
|
||||
|
||||
@@ -55,14 +56,17 @@ fn list_renders() {
|
||||
edits.edits,
|
||||
[
|
||||
// Load the outer div
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
// Load each template one-by-one, rehydrating it
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2) },
|
||||
HydrateText { path: &[1, 0], value: "0".to_string(), id: ElementId(3) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(4) },
|
||||
HydrateText { path: &[1, 0], value: "1".to_string(), id: ElementId(5) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
HydrateText { path: &[1, 0], value: "2".to_string(), id: ElementId(7) },
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(3) },
|
||||
ReplacePlaceholder { path: &[1, 0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(4) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(5) },
|
||||
ReplacePlaceholder { path: &[1, 0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(7) },
|
||||
ReplacePlaceholder { path: &[1, 0], m: 1 },
|
||||
// Replace the 0th childn on the div with the 3 templates on the stack
|
||||
ReplacePlaceholder { m: 3, path: &[0] },
|
||||
// Append the container div to the dom
|
||||
|
||||
@@ -21,12 +21,12 @@ fn nested_passthru_creates() {
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
AppendChildren { m: 1, id: ElementId(0) },
|
||||
]
|
||||
)
|
||||
@@ -60,16 +60,16 @@ fn nested_passthru_creates_add() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
// load 1
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
// load 2
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2) },
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
// load 3
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(3) },
|
||||
LoadTemplate { index: 0, id: ElementId(3) },
|
||||
// load div that contains 4
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(4) },
|
||||
LoadTemplate { index: 1, id: ElementId(4) },
|
||||
AppendChildren { id: ElementId(0), m: 4 },
|
||||
]
|
||||
);
|
||||
@@ -85,11 +85,9 @@ fn dynamic_node_as_root() {
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
|
||||
// Since the roots were all dynamic, they should not cause any template muations
|
||||
assert!(edits.templates.is_empty());
|
||||
|
||||
// The root node is text, so we just create it on the spot
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
|
||||
@@ -11,11 +11,11 @@ fn cycling_elements() {
|
||||
});
|
||||
|
||||
{
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
AppendChildren { m: 1, id: ElementId(0) },
|
||||
]
|
||||
);
|
||||
@@ -23,9 +23,9 @@ fn cycling_elements() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -33,18 +33,18 @@ fn cycling_elements() {
|
||||
// notice that the IDs cycle back to ElementId(1), preserving a minimal memory footprint
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use dioxus::dioxus_core::{ElementId, Mutation::*};
|
||||
use dioxus::prelude::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
/// When returning sets of components, we do a light diff of the contents to preserve some react-like functionality
|
||||
///
|
||||
@@ -7,6 +8,15 @@ use dioxus::prelude::*;
|
||||
/// different pointers
|
||||
#[test]
|
||||
fn component_swap() {
|
||||
// Check that templates with the same structure are deduplicated at compile time
|
||||
// If they are not, this test will fail because it is being run in debug mode where templates are not deduped
|
||||
let dynamic = 0;
|
||||
let template_1 = rsx! { "{dynamic}" };
|
||||
let template_2 = rsx! { "{dynamic}" };
|
||||
if template_1.unwrap().template != template_2.unwrap().template {
|
||||
return;
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
let mut render_phase = use_signal(|| 0);
|
||||
|
||||
@@ -62,16 +72,16 @@ fn component_swap() {
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
{
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
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 { index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
LoadTemplate { index: 0, id: ElementId(3) },
|
||||
LoadTemplate { index: 0, id: ElementId(4) },
|
||||
ReplacePlaceholder { path: &[1], m: 3 },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
||||
LoadTemplate { index: 0, id: ElementId(5) },
|
||||
AppendChildren { m: 2, id: ElementId(0) }
|
||||
]
|
||||
);
|
||||
@@ -79,27 +89,27 @@ fn component_swap() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
ReplaceWith { id: ElementId(5), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
||||
LoadTemplate { index: 0, id: ElementId(5) },
|
||||
ReplaceWith { id: ElementId(6), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
ReplaceWith { id: ElementId(5), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ fn toggle_option_text() {
|
||||
let mut dom = VirtualDom::new(|| {
|
||||
let gen = generation();
|
||||
let text = if gen % 2 != 0 { Some("hello") } else { None };
|
||||
println!("{:?}", text);
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
@@ -17,10 +18,11 @@ fn toggle_option_text() {
|
||||
|
||||
// load the div and then assign the None as a placeholder
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
AssignId { path: &[0], id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
CreatePlaceholder { id: ElementId(2,) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
AppendChildren { id: ElementId(0), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -28,7 +30,7 @@ fn toggle_option_text() {
|
||||
// Rendering again should replace the placeholder with an text node
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
CreateTextNode { value: "hello".to_string(), id: ElementId(3,) },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
@@ -38,7 +40,7 @@ fn toggle_option_text() {
|
||||
// Rendering again should replace the placeholder with an text node
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
CreatePlaceholder { id: ElementId(2,) },
|
||||
ReplaceWith { id: ElementId(3,), m: 1 },
|
||||
|
||||
@@ -48,36 +48,36 @@ fn element_swap() {
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
vdom.render_immediate_to_vec().sanitize().edits,
|
||||
vdom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||
]
|
||||
);
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
vdom.render_immediate_to_vec().sanitize().edits,
|
||||
vdom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
vdom.render_immediate_to_vec().sanitize().edits,
|
||||
vdom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||
]
|
||||
);
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
vdom.render_immediate_to_vec().sanitize().edits,
|
||||
vdom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -128,7 +128,7 @@ fn attribute_diff() {
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
vdom.render_immediate_to_vec().sanitize().edits,
|
||||
vdom.render_immediate_to_vec().edits,
|
||||
[
|
||||
SetAttribute {
|
||||
name: "b",
|
||||
@@ -147,7 +147,7 @@ fn attribute_diff() {
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
vdom.render_immediate_to_vec().sanitize().edits,
|
||||
vdom.render_immediate_to_vec().edits,
|
||||
[
|
||||
SetAttribute { name: "a", value: AttributeValue::None, id: ElementId(1,), ns: None },
|
||||
SetAttribute { name: "b", value: AttributeValue::None, id: ElementId(1,), ns: None },
|
||||
@@ -168,7 +168,7 @@ fn attribute_diff() {
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
vdom.render_immediate_to_vec().sanitize().edits,
|
||||
vdom.render_immediate_to_vec().edits,
|
||||
[
|
||||
SetAttribute { name: "c", value: AttributeValue::None, id: ElementId(1,), ns: None },
|
||||
SetAttribute {
|
||||
@@ -196,7 +196,7 @@ fn diff_empty() {
|
||||
vdom.rebuild(&mut NoOpMutations);
|
||||
|
||||
vdom.mark_dirty(ScopeId::APP);
|
||||
let edits = vdom.render_immediate_to_vec().sanitize().edits;
|
||||
let edits = vdom.render_immediate_to_vec().edits;
|
||||
|
||||
assert_eq!(
|
||||
edits,
|
||||
|
||||
@@ -22,18 +22,18 @@ fn keyed_diffing_out_of_order() {
|
||||
|
||||
{
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
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,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(3,) },
|
||||
LoadTemplate { index: 0, id: ElementId(4,) },
|
||||
LoadTemplate { index: 0, id: ElementId(5,) },
|
||||
LoadTemplate { index: 0, id: ElementId(6,) },
|
||||
LoadTemplate { index: 0, id: ElementId(7,) },
|
||||
LoadTemplate { index: 0, id: ElementId(8,) },
|
||||
LoadTemplate { index: 0, id: ElementId(9,) },
|
||||
LoadTemplate { index: 0, id: ElementId(10,) },
|
||||
AppendChildren { m: 10, id: ElementId(0) },
|
||||
]
|
||||
);
|
||||
@@ -169,10 +169,10 @@ fn keyed_diffing_additions() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(7) },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
LoadTemplate { index: 0, id: ElementId(7) },
|
||||
InsertAfter { id: ElementId(5), m: 2 }
|
||||
]
|
||||
);
|
||||
@@ -194,11 +194,11 @@ fn keyed_diffing_additions_and_moves_on_ends() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
// create 11, 12
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
LoadTemplate { index: 0, id: ElementId(5) },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
InsertAfter { id: ElementId(3), m: 2 },
|
||||
// move 7 to the front
|
||||
PushRoot { id: ElementId(4) },
|
||||
@@ -224,15 +224,15 @@ fn keyed_diffing_additions_and_moves_in_middle() {
|
||||
// LIS: 4, 5, 6
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
// create 5, 6
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
LoadTemplate { index: 0, id: ElementId(5) },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
InsertBefore { id: ElementId(3), m: 2 },
|
||||
// create 7, 8
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(7) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(8) },
|
||||
LoadTemplate { index: 0, id: ElementId(7) },
|
||||
LoadTemplate { index: 0, id: ElementId(8) },
|
||||
InsertBefore { id: ElementId(2), m: 2 },
|
||||
// move 7
|
||||
PushRoot { id: ElementId(4) },
|
||||
@@ -258,7 +258,7 @@ fn controlled_keyed_diffing_out_of_order() {
|
||||
// LIS: 5, 6
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
// remove 7
|
||||
Remove { id: ElementId(4,) },
|
||||
@@ -266,10 +266,10 @@ fn controlled_keyed_diffing_out_of_order() {
|
||||
PushRoot { id: ElementId(1) },
|
||||
InsertAfter { id: ElementId(3,), m: 1 },
|
||||
// create 9 and insert before 6
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(4) },
|
||||
LoadTemplate { index: 0, id: ElementId(4) },
|
||||
InsertBefore { id: ElementId(3,), m: 1 },
|
||||
// create 0 and insert before 5
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
||||
LoadTemplate { index: 0, id: ElementId(5) },
|
||||
InsertBefore { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -291,10 +291,10 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
Remove { id: ElementId(5,) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5) },
|
||||
LoadTemplate { index: 0, id: ElementId(5) },
|
||||
InsertBefore { id: ElementId(3,), m: 1 },
|
||||
PushRoot { id: ElementId(4) },
|
||||
InsertBefore { id: ElementId(1,), m: 1 },
|
||||
@@ -320,7 +320,7 @@ fn remove_list() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
Remove { id: ElementId(5) },
|
||||
Remove { id: ElementId(4) },
|
||||
@@ -345,11 +345,11 @@ fn no_common_keys() {
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
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 { index: 0, id: ElementId(4) },
|
||||
LoadTemplate { index: 0, id: ElementId(5) },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
Remove { id: ElementId(3) },
|
||||
Remove { id: ElementId(2) },
|
||||
ReplaceWith { id: ElementId(1), m: 3 }
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use dioxus::dioxus_core::{ElementId, Mutation::*};
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core::Mutation;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
@@ -18,10 +21,11 @@ fn list_creates_one_by_one() {
|
||||
|
||||
// load the div and then assign the empty fragment as a placeholder
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
AssignId { path: &[0], id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
CreatePlaceholder { id: ElementId(2,) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
AppendChildren { id: ElementId(0), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -29,10 +33,11 @@ fn list_creates_one_by_one() {
|
||||
// Rendering the first item should replace the placeholder with an element
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
|
||||
HydrateText { path: &[0], value: "0".to_string(), id: ElementId(4,) },
|
||||
LoadTemplate { index: 0, id: ElementId(3,) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(4,) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -40,10 +45,11 @@ fn list_creates_one_by_one() {
|
||||
// Rendering the next item should insert after the previous
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
HydrateText { path: &[0], value: "1".to_string(), id: ElementId(5,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(5,) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
InsertAfter { id: ElementId(3,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -51,10 +57,11 @@ fn list_creates_one_by_one() {
|
||||
// ... and again!
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6,) },
|
||||
HydrateText { path: &[0], value: "2".to_string(), id: ElementId(7,) },
|
||||
LoadTemplate { index: 0, id: ElementId(6,) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(7,) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
InsertAfter { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -62,10 +69,11 @@ fn list_creates_one_by_one() {
|
||||
// once more
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(8,) },
|
||||
HydrateText { path: &[0], value: "3".to_string(), id: ElementId(9,) },
|
||||
LoadTemplate { index: 0, id: ElementId(8,) },
|
||||
CreateTextNode { value: "3".to_string(), id: ElementId(9,) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
InsertAfter { id: ElementId(6,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -87,17 +95,20 @@ fn removes_one_by_one() {
|
||||
|
||||
// load the div and then assign the empty fragment as a placeholder
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
// The container
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
// each list item
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2) },
|
||||
HydrateText { path: &[0], value: "0".to_string(), id: ElementId(3) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(4) },
|
||||
HydrateText { path: &[0], value: "1".to_string(), id: ElementId(5) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
HydrateText { path: &[0], value: "2".to_string(), id: ElementId(7) },
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(3) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(4) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(5) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(7) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
// replace the placeholder in the template with the 3 templates on the stack
|
||||
ReplacePlaceholder { m: 3, path: &[0] },
|
||||
// Mount the div
|
||||
@@ -109,14 +120,14 @@ fn removes_one_by_one() {
|
||||
// Rendering the first item should replace the placeholder with an element
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[Remove { id: ElementId(6) }]
|
||||
);
|
||||
|
||||
// Remove div(2)
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[Remove { id: ElementId(4) }]
|
||||
);
|
||||
|
||||
@@ -124,7 +135,7 @@ fn removes_one_by_one() {
|
||||
// todo: this should just be a remove with no placeholder
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
CreatePlaceholder { id: ElementId(4) },
|
||||
ReplaceWith { id: ElementId(2), m: 1 }
|
||||
@@ -135,14 +146,17 @@ fn removes_one_by_one() {
|
||||
// todo: this should actually be append to, but replace placeholder is fine for now
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2) },
|
||||
HydrateText { path: &[0], value: "0".to_string(), id: ElementId(6) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(8) },
|
||||
HydrateText { path: &[0], value: "1".to_string(), id: ElementId(9) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(10) },
|
||||
HydrateText { path: &[0], value: "2".to_string(), id: ElementId(11) },
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(6) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(8) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(9) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(10) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(11) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
ReplaceWith { id: ElementId(4), m: 3 }
|
||||
]
|
||||
);
|
||||
@@ -162,46 +176,53 @@ fn list_shrink_multiroot() {
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
AssignId { path: &[0,], id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
CreatePlaceholder { id: ElementId(2,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
AppendChildren { id: ElementId(0), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(3) },
|
||||
HydrateText { path: &[0], value: "0".to_string(), id: ElementId(4) },
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(5) },
|
||||
HydrateText { path: &[0], value: "0".to_string(), id: ElementId(6) },
|
||||
LoadTemplate { index: 0, id: ElementId(3) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(4) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 1, id: ElementId(5) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(6) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
ReplaceWith { id: ElementId(2), m: 2 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2) },
|
||||
HydrateText { path: &[0], value: "1".to_string(), id: ElementId(7) },
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(8) },
|
||||
HydrateText { path: &[0], value: "1".to_string(), id: ElementId(9) },
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(7) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 1, id: ElementId(8) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(9) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
InsertAfter { id: ElementId(5), m: 2 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(10) },
|
||||
HydrateText { path: &[0], value: "2".to_string(), id: ElementId(11) },
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(12) },
|
||||
HydrateText { path: &[0], value: "2".to_string(), id: ElementId(13) },
|
||||
LoadTemplate { index: 0, id: ElementId(10) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(11) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 1, id: ElementId(12) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(13) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
InsertAfter { id: ElementId(8), m: 2 }
|
||||
]
|
||||
);
|
||||
@@ -224,46 +245,48 @@ fn removes_one_by_one_multiroot() {
|
||||
|
||||
// load the div and then assign the empty fragment as a placeholder
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
//
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2) },
|
||||
HydrateText { path: &[0], value: "0".to_string(), id: ElementId(3) },
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(4) },
|
||||
HydrateText { path: &[0], value: "0".to_string(), id: ElementId(5) },
|
||||
//
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(6) },
|
||||
HydrateText { path: &[0], value: "1".to_string(), id: ElementId(7) },
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(8) },
|
||||
HydrateText { path: &[0], value: "1".to_string(), id: ElementId(9) },
|
||||
//
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(10) },
|
||||
HydrateText { path: &[0], value: "2".to_string(), id: ElementId(11) },
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(12) },
|
||||
HydrateText { path: &[0], value: "2".to_string(), id: ElementId(13) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
//
|
||||
LoadTemplate { index: 0, id: ElementId(2) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(3) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 1, id: ElementId(4) },
|
||||
CreateTextNode { value: "0".to_string(), id: ElementId(5) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(6) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(7) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 1, id: ElementId(8) },
|
||||
CreateTextNode { value: "1".to_string(), id: ElementId(9) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(10) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(11) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
LoadTemplate { index: 1, id: ElementId(12) },
|
||||
CreateTextNode { value: "2".to_string(), id: ElementId(13) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
ReplacePlaceholder { path: &[0], m: 6 },
|
||||
//
|
||||
AppendChildren { id: ElementId(0), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[Remove { id: ElementId(10) }, Remove { id: ElementId(12) }]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[Remove { id: ElementId(6) }, Remove { id: ElementId(8) }]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
assert_eq!(
|
||||
dom.render_immediate_to_vec().sanitize().edits,
|
||||
dom.render_immediate_to_vec().edits,
|
||||
[
|
||||
CreatePlaceholder { id: ElementId(8) },
|
||||
Remove { id: ElementId(2) },
|
||||
@@ -317,9 +340,9 @@ fn remove_many() {
|
||||
}
|
||||
});
|
||||
|
||||
// len = 0
|
||||
{
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
assert!(edits.templates.is_empty());
|
||||
let edits = dom.rebuild_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
@@ -329,62 +352,76 @@ fn remove_many() {
|
||||
);
|
||||
}
|
||||
|
||||
// len = 1
|
||||
{
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let edits = dom.render_immediate_to_vec().sanitize();
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
HydrateText { path: &[0,], value: "hello 0".to_string(), id: ElementId(3,) },
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
CreateTextNode { value: "hello 0".to_string(), id: ElementId(3,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// len = 5
|
||||
{
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let edits = dom.render_immediate_to_vec().sanitize();
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
HydrateText { path: &[0,], value: "hello 1".to_string(), id: ElementId(4,) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5,) },
|
||||
HydrateText { path: &[0,], value: "hello 2".to_string(), id: ElementId(6,) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(7,) },
|
||||
HydrateText { path: &[0,], value: "hello 3".to_string(), id: ElementId(8,) },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(9,) },
|
||||
HydrateText { path: &[0,], value: "hello 4".to_string(), id: ElementId(10,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
CreateTextNode { value: "hello 1".to_string(), id: ElementId(4,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(5,) },
|
||||
CreateTextNode { value: "hello 2".to_string(), id: ElementId(6,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(7,) },
|
||||
CreateTextNode { value: "hello 3".to_string(), id: ElementId(8,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
LoadTemplate { index: 0, id: ElementId(9,) },
|
||||
CreateTextNode { value: "hello 4".to_string(), id: ElementId(10,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
InsertAfter { id: ElementId(2,), m: 4 },
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// len = 0
|
||||
{
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let edits = dom.render_immediate_to_vec().sanitize();
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(edits.edits[0], CreatePlaceholder { id: ElementId(11,) });
|
||||
let removed = edits.edits[1..5]
|
||||
.iter()
|
||||
.map(|edit| match edit {
|
||||
Mutation::Remove { id } => *id,
|
||||
_ => panic!("Expected remove"),
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
CreatePlaceholder { id: ElementId(11,) },
|
||||
Remove { id: ElementId(9,) },
|
||||
Remove { id: ElementId(7,) },
|
||||
Remove { id: ElementId(5,) },
|
||||
Remove { id: ElementId(1,) },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
removed,
|
||||
[ElementId(7), ElementId(5), ElementId(2), ElementId(1)]
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>()
|
||||
);
|
||||
assert_eq!(edits.edits[5..], [ReplaceWith { id: ElementId(9,), m: 1 },]);
|
||||
}
|
||||
|
||||
// len = 1
|
||||
{
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let edits = dom.render_immediate_to_vec().sanitize();
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
HydrateText { path: &[0,], value: "hello 0".to_string(), id: ElementId(1,) },
|
||||
LoadTemplate { index: 0, id: ElementId(9,) },
|
||||
CreateTextNode { value: "hello 0".to_string(), id: ElementId(7,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
ReplaceWith { id: ElementId(11,), m: 1 },
|
||||
]
|
||||
)
|
||||
@@ -415,12 +452,13 @@ fn replace_and_add_items() {
|
||||
|
||||
// The list starts empty with a placeholder
|
||||
{
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||
AssignId { path: &[0], id: ElementId(2,) },
|
||||
LoadTemplate { index: 0, id: ElementId(1,) },
|
||||
CreatePlaceholder { id: ElementId(2,) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
AppendChildren { id: ElementId(0), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -429,11 +467,11 @@ fn replace_and_add_items() {
|
||||
// Rerendering adds an a static template
|
||||
{
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let edits = dom.render_immediate_to_vec().sanitize();
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
|
||||
LoadTemplate { index: 0, id: ElementId(3,) },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -442,7 +480,7 @@ fn replace_and_add_items() {
|
||||
// Rerendering replaces the old node with a placeholder and adds a new placeholder
|
||||
{
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let edits = dom.render_immediate_to_vec().sanitize();
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
@@ -457,15 +495,15 @@ fn replace_and_add_items() {
|
||||
// Rerendering replaces both placeholders with the static nodes and add a new static node
|
||||
{
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let edits = dom.render_immediate_to_vec().sanitize();
|
||||
let edits = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
edits.edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
|
||||
LoadTemplate { index: 0, id: ElementId(3,) },
|
||||
InsertAfter { id: ElementId(2,), m: 1 },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(5,) },
|
||||
LoadTemplate { index: 0, id: ElementId(5,) },
|
||||
ReplaceWith { id: ElementId(4,), m: 1 },
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(4,) },
|
||||
LoadTemplate { index: 0, id: ElementId(4,) },
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#![cfg(not(miri))]
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core::{AttributeValue, DynamicNode, NoOpMutations, VComponent, VNode, *};
|
||||
use std::{
|
||||
cfg, collections::HashSet, default::Default, sync::atomic::AtomicUsize, sync::atomic::Ordering,
|
||||
};
|
||||
use dioxus_core::{AttributeValue, DynamicNode, NoOpMutations, Template, VComponent, VNode, *};
|
||||
use std::{cfg, collections::HashSet, default::Default};
|
||||
|
||||
fn random_ns() -> Option<&'static str> {
|
||||
let namespace = rand::random::<u8>() % 2;
|
||||
@@ -129,7 +127,7 @@ enum DynamicNodeType {
|
||||
Other,
|
||||
}
|
||||
|
||||
fn create_random_template(name: &'static str) -> (Template, Vec<DynamicNodeType>) {
|
||||
fn create_random_template() -> (Template, Vec<DynamicNodeType>) {
|
||||
let mut dynamic_node_type = Vec::new();
|
||||
let mut template_idx = 0;
|
||||
let mut attr_idx = 0;
|
||||
@@ -160,7 +158,7 @@ fn create_random_template(name: &'static str) -> (Template, Vec<DynamicNodeType>
|
||||
.into_boxed_slice(),
|
||||
);
|
||||
(
|
||||
Template { name, roots, node_paths, attr_paths },
|
||||
Template { roots, node_paths, attr_paths },
|
||||
dynamic_node_type,
|
||||
)
|
||||
}
|
||||
@@ -174,7 +172,6 @@ fn create_random_dynamic_node(depth: usize) -> DynamicNode {
|
||||
VNode::new(
|
||||
None,
|
||||
Template {
|
||||
name: create_template_location(),
|
||||
roots: &[TemplateNode::Dynamic { id: 0 }],
|
||||
node_paths: &[&[0]],
|
||||
attr_paths: &[],
|
||||
@@ -219,19 +216,6 @@ fn create_random_dynamic_attr() -> Attribute {
|
||||
)
|
||||
}
|
||||
|
||||
static TEMPLATE_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
fn create_template_location() -> &'static str {
|
||||
Box::leak(
|
||||
format!(
|
||||
"{}{}",
|
||||
concat!(file!(), ":", line!(), ":", column!(), ":"),
|
||||
TEMPLATE_COUNT.fetch_add(1, Ordering::Relaxed)
|
||||
)
|
||||
.into_boxed_str(),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props, Clone)]
|
||||
struct DepthProps {
|
||||
depth: usize,
|
||||
@@ -245,7 +229,7 @@ fn create_random_element(cx: DepthProps) -> Element {
|
||||
let range = if cx.root { 2 } else { 3 };
|
||||
let node = match rand::random::<usize>() % range {
|
||||
0 | 1 => {
|
||||
let (template, dynamic_node_types) = create_random_template(create_template_location());
|
||||
let (template, dynamic_node_types) = create_random_template();
|
||||
let node = VNode::new(
|
||||
None,
|
||||
template,
|
||||
@@ -314,8 +298,6 @@ fn diff() {
|
||||
struct InsertEventListenerMutationHandler<'a>(&'a mut HashSet<ElementId>);
|
||||
|
||||
impl WriteMutations for InsertEventListenerMutationHandler<'_> {
|
||||
fn register_template(&mut self, _: Template) {}
|
||||
|
||||
fn append_children(&mut self, _: ElementId, _: usize) {}
|
||||
|
||||
fn assign_node_id(&mut self, _: &'static [u8], _: ElementId) {}
|
||||
@@ -324,9 +306,7 @@ impl WriteMutations for InsertEventListenerMutationHandler<'_> {
|
||||
|
||||
fn create_text_node(&mut self, _: &str, _: ElementId) {}
|
||||
|
||||
fn hydrate_text_node(&mut self, _: &'static [u8], _: &str, _: ElementId) {}
|
||||
|
||||
fn load_template(&mut self, _: &'static str, _: usize, _: ElementId) {}
|
||||
fn load_template(&mut self, _: Template, _: usize, _: ElementId) {}
|
||||
|
||||
fn replace_node_with(&mut self, _: ElementId, _: usize) {}
|
||||
|
||||
|
||||
@@ -33,13 +33,14 @@ fn basic_syntax_is_a_template() -> Element {
|
||||
#[test]
|
||||
fn dual_stream() {
|
||||
let mut dom = VirtualDom::new(basic_syntax_is_a_template);
|
||||
let edits = dom.rebuild_to_vec().sanitize();
|
||||
let edits = dom.rebuild_to_vec();
|
||||
|
||||
use Mutation::*;
|
||||
assert_eq!(edits.edits, {
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
HydrateText { path: &[0, 0], value: "123".to_string(), id: ElementId(2) },
|
||||
LoadTemplate { index: 0, id: ElementId(1) },
|
||||
CreateTextNode { value: "123".to_string(), id: ElementId(2) },
|
||||
ReplacePlaceholder { path: &[0, 0], m: 1 },
|
||||
SetAttribute {
|
||||
name: "class",
|
||||
value: "asd 123 123 ".into_value(),
|
||||
|
||||
@@ -30,10 +30,11 @@ fn manual_diffing() {
|
||||
*value.lock().unwrap() = "goodbye";
|
||||
|
||||
assert_eq!(
|
||||
dom.rebuild_to_vec().sanitize().edits,
|
||||
dom.rebuild_to_vec().edits,
|
||||
[
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(3) },
|
||||
HydrateText { path: &[0], value: "goodbye".to_string(), id: ElementId(4) },
|
||||
LoadTemplate { index: 0, id: ElementId(3) },
|
||||
CreateTextNode { value: "goodbye".to_string(), id: ElementId(4) },
|
||||
ReplacePlaceholder { path: &[0], m: 1 },
|
||||
AppendChildren { m: 1, id: ElementId(0) }
|
||||
]
|
||||
);
|
||||
|
||||
@@ -415,20 +415,20 @@ fn toggle_suspense() {
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mutations = dom.rebuild_to_vec().sanitize();
|
||||
let mutations = dom.rebuild_to_vec();
|
||||
|
||||
// First create goodbye world
|
||||
println!("{:#?}", mutations);
|
||||
assert_eq!(
|
||||
mutations.edits,
|
||||
[
|
||||
Mutation::LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
Mutation::LoadTemplate { index: 0, id: ElementId(1) },
|
||||
Mutation::AppendChildren { id: ElementId(0), m: 1 }
|
||||
]
|
||||
);
|
||||
|
||||
dom.mark_dirty(ScopeId::APP);
|
||||
let mutations = dom.render_immediate_to_vec().sanitize();
|
||||
let mutations = dom.render_immediate_to_vec();
|
||||
|
||||
// Then replace that with nothing
|
||||
println!("{:#?}", mutations);
|
||||
@@ -441,20 +441,20 @@ fn toggle_suspense() {
|
||||
);
|
||||
|
||||
dom.wait_for_work().await;
|
||||
let mutations = dom.render_immediate_to_vec().sanitize();
|
||||
let mutations = dom.render_immediate_to_vec();
|
||||
|
||||
// Then replace it with a placeholder
|
||||
println!("{:#?}", mutations);
|
||||
assert_eq!(
|
||||
mutations.edits,
|
||||
[
|
||||
Mutation::LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
Mutation::LoadTemplate { index: 0, id: ElementId(1) },
|
||||
Mutation::ReplaceWith { id: ElementId(2), m: 1 },
|
||||
]
|
||||
);
|
||||
|
||||
dom.wait_for_work().await;
|
||||
let mutations = dom.render_immediate_to_vec().sanitize();
|
||||
let mutations = dom.render_immediate_to_vec();
|
||||
|
||||
// Then replace it with the resolved node
|
||||
println!("{:#?}", mutations);
|
||||
@@ -463,7 +463,7 @@ fn toggle_suspense() {
|
||||
[
|
||||
Mutation::CreatePlaceholder { id: ElementId(2,) },
|
||||
Mutation::ReplaceWith { id: ElementId(1,), m: 1 },
|
||||
Mutation::LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||
Mutation::LoadTemplate { index: 0, id: ElementId(1) },
|
||||
Mutation::ReplaceWith { id: ElementId(2), m: 1 },
|
||||
]
|
||||
);
|
||||
@@ -600,14 +600,14 @@ fn nested_suspense_resolves_client() {
|
||||
// DOM STATE:
|
||||
// placeholder // ID: 1
|
||||
// "Loading 0..." // ID: 2
|
||||
let mutations = dom.render_immediate_to_vec().sanitize();
|
||||
let mutations = dom.render_immediate_to_vec();
|
||||
// Fill in the contents of the initial message and start loading the nested suspense
|
||||
// The title also finishes loading
|
||||
assert_eq!(
|
||||
mutations.edits,
|
||||
vec![
|
||||
// Creating and swapping these placeholders doesn't do anything
|
||||
// It is just extra work that we are forced to do because mutations are not
|
||||
// It is just extra work that we are forced to do because mutations are not
|
||||
// reversible. We start rendering the children and then realize it is suspended.
|
||||
// Then we need to replace what we just rendered with the suspense placeholder
|
||||
CreatePlaceholder { id: ElementId(3,) },
|
||||
@@ -622,12 +622,9 @@ fn nested_suspense_resolves_client() {
|
||||
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||
|
||||
// Load the title
|
||||
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||
HydrateText {
|
||||
path: &[0,],
|
||||
value: "The robot says hello world".to_string(),
|
||||
id: ElementId(4,),
|
||||
},
|
||||
LoadTemplate { index: 0, id: ElementId(2,) },
|
||||
CreateTextNode { value: "The robot says hello world".to_string(), id: ElementId(4,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
ns: None,
|
||||
@@ -636,12 +633,9 @@ fn nested_suspense_resolves_client() {
|
||||
},
|
||||
|
||||
// Then load the body
|
||||
LoadTemplate { name: "template", index: 1, id: ElementId(5,) },
|
||||
HydrateText {
|
||||
path: &[0,],
|
||||
value: "The robot becomes sentient and says hello world".to_string(),
|
||||
id: ElementId(6,),
|
||||
},
|
||||
LoadTemplate { index: 1, id: ElementId(5,) },
|
||||
CreateTextNode { value: "The robot becomes sentient and says hello world".to_string(), id: ElementId(6,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 1 },
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
ns: None,
|
||||
@@ -650,7 +644,7 @@ fn nested_suspense_resolves_client() {
|
||||
},
|
||||
|
||||
// Then load the suspended children
|
||||
LoadTemplate { name: "template", index: 2, id: ElementId(7,) },
|
||||
LoadTemplate { index: 2, id: ElementId(7,) },
|
||||
CreateTextNode { value: "Loading 1...".to_string(), id: ElementId(8,) },
|
||||
CreateTextNode { value: "Loading 2...".to_string(), id: ElementId(9,) },
|
||||
ReplacePlaceholder { path: &[0,], m: 2 },
|
||||
@@ -674,7 +668,7 @@ fn nested_suspense_resolves_client() {
|
||||
// div // ID: 7
|
||||
// "Loading 1..." // ID: 8
|
||||
// "Loading 2..." // ID: 9
|
||||
let mutations = dom.render_immediate_to_vec().sanitize();
|
||||
let mutations = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
mutations.edits,
|
||||
vec![
|
||||
@@ -693,20 +687,18 @@ fn nested_suspense_resolves_client() {
|
||||
|
||||
// Load the nested suspense
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
|
||||
index: 0,
|
||||
id: ElementId(
|
||||
8,
|
||||
),
|
||||
},
|
||||
HydrateText {
|
||||
CreateTextNode { value: "The world says hello back".to_string(), id: ElementId(10,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
],
|
||||
value: "The world says hello back".to_string(),
|
||||
id: ElementId(
|
||||
10,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
@@ -717,20 +709,18 @@ fn nested_suspense_resolves_client() {
|
||||
),
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
|
||||
index: 1,
|
||||
id: ElementId(
|
||||
11,
|
||||
),
|
||||
},
|
||||
HydrateText {
|
||||
CreateTextNode { value: "In a stunning turn of events, the world collectively unites and says hello back".to_string(), id: ElementId(12,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
],
|
||||
value: "In a stunning turn of events, the world collectively unites and says hello back".to_string(),
|
||||
id: ElementId(
|
||||
12,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
@@ -741,19 +731,17 @@ fn nested_suspense_resolves_client() {
|
||||
),
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
index: 2,
|
||||
id: ElementId(
|
||||
13,
|
||||
),
|
||||
},
|
||||
AssignId {
|
||||
CreatePlaceholder { id: ElementId(14,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
],
|
||||
id: ElementId(
|
||||
14,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
@@ -783,20 +771,17 @@ fn nested_suspense_resolves_client() {
|
||||
m: 1,
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
index: 0,
|
||||
id: ElementId(
|
||||
9,
|
||||
),
|
||||
},
|
||||
HydrateText {
|
||||
CreateTextNode { value: "Goodbye Robot".to_string(), id: ElementId(15,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
],
|
||||
value: "Goodbye Robot".to_string(),
|
||||
id: ElementId(
|
||||
15,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
@@ -807,20 +792,17 @@ fn nested_suspense_resolves_client() {
|
||||
),
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
index: 1,
|
||||
id: ElementId(
|
||||
16,
|
||||
),
|
||||
},
|
||||
HydrateText {
|
||||
CreateTextNode { value: "The robot says goodbye".to_string(), id: ElementId(17,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
],
|
||||
value: "The robot says goodbye".to_string(),
|
||||
id: ElementId(
|
||||
17,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
@@ -831,7 +813,7 @@ fn nested_suspense_resolves_client() {
|
||||
),
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
|
||||
index: 2,
|
||||
id: ElementId(
|
||||
18,
|
||||
@@ -860,7 +842,7 @@ fn nested_suspense_resolves_client() {
|
||||
);
|
||||
|
||||
dom.wait_for_work().await;
|
||||
let mutations = dom.render_immediate_to_vec().sanitize();
|
||||
let mutations = dom.render_immediate_to_vec();
|
||||
assert_eq!(
|
||||
mutations.edits,
|
||||
vec![
|
||||
@@ -876,20 +858,18 @@ fn nested_suspense_resolves_client() {
|
||||
m: 1,
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
|
||||
index: 0,
|
||||
id: ElementId(
|
||||
19,
|
||||
),
|
||||
},
|
||||
HydrateText {
|
||||
CreateTextNode { value: "Goodbye Robot again".to_string(), id: ElementId(20,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
],
|
||||
value: "Goodbye Robot again".to_string(),
|
||||
id: ElementId(
|
||||
20,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
@@ -900,20 +880,17 @@ fn nested_suspense_resolves_client() {
|
||||
),
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
index: 1,
|
||||
id: ElementId(
|
||||
21,
|
||||
),
|
||||
},
|
||||
HydrateText {
|
||||
CreateTextNode { value: "The robot says goodbye again".to_string(), id: ElementId(22,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
],
|
||||
value: "The robot says goodbye again".to_string(),
|
||||
id: ElementId(
|
||||
22,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
@@ -924,19 +901,17 @@ fn nested_suspense_resolves_client() {
|
||||
),
|
||||
},
|
||||
LoadTemplate {
|
||||
name: "template",
|
||||
index: 2,
|
||||
id: ElementId(
|
||||
23,
|
||||
),
|
||||
},
|
||||
AssignId {
|
||||
CreatePlaceholder { id: ElementId(24,) },
|
||||
ReplacePlaceholder {
|
||||
path: &[
|
||||
0,
|
||||
0
|
||||
],
|
||||
id: ElementId(
|
||||
24,
|
||||
),
|
||||
m: 1,
|
||||
},
|
||||
SetAttribute {
|
||||
name: "id",
|
||||
|
||||
Reference in new issue
Block a user