Merge branch 'master' into many_optional_attributes
This commit is contained in:
569 files changed
+8815
-21321
No files matched your search
@@ -5,11 +5,12 @@ use dioxus_core::ElementId;
|
||||
/// Should push the text node onto the stack and modify it
|
||||
#[test]
|
||||
fn nested_passthru_creates() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
pass_thru {
|
||||
pass_thru {
|
||||
pass_thru {
|
||||
PassThru {
|
||||
PassThru {
|
||||
PassThru {
|
||||
div { "hi" }
|
||||
}
|
||||
}
|
||||
@@ -17,12 +18,12 @@ fn nested_passthru_creates() {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn pass_thru<'a>(cx: Scope<'a>, children: Element<'a>) -> Element {
|
||||
#[component]
|
||||
fn PassThru<'a>(cx: Scope<'a>, children: Element<'a>) -> Element {
|
||||
cx.render(rsx!(children))
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
let edits = dom.rebuild().santize();
|
||||
|
||||
assert_eq!(
|
||||
@@ -39,13 +40,14 @@ fn nested_passthru_creates() {
|
||||
/// Take note on how we don't spit out the template for child_comp since it's entirely dynamic
|
||||
#[test]
|
||||
fn nested_passthru_creates_add() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
child_comp {
|
||||
ChildComp {
|
||||
"1"
|
||||
child_comp {
|
||||
ChildComp {
|
||||
"2"
|
||||
child_comp {
|
||||
ChildComp {
|
||||
"3"
|
||||
div {
|
||||
"hi"
|
||||
@@ -56,12 +58,12 @@ fn nested_passthru_creates_add() {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn child_comp<'a>(cx: Scope, children: Element<'a>) -> Element {
|
||||
#[component]
|
||||
fn ChildComp<'a>(cx: Scope, children: Element<'a>) -> Element {
|
||||
cx.render(rsx! { children })
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
assert_eq!(
|
||||
dom.rebuild().santize().edits,
|
||||
@@ -82,13 +84,14 @@ fn nested_passthru_creates_add() {
|
||||
/// note that the template is all dynamic roots - so it doesn't actually get cached as a template
|
||||
#[test]
|
||||
fn dynamic_node_as_root() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
let a = 123;
|
||||
let b = 456;
|
||||
cx.render(rsx! { "{a}" "{b}" })
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
let edits = dom.rebuild().santize();
|
||||
|
||||
// Since the roots were all dynamic, they should not cause any template muations
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core::ElementId;
|
||||
use std::{rc::Rc, sync::Mutex};
|
||||
|
||||
static CLICKS: Mutex<usize> = Mutex::new(0);
|
||||
|
||||
#[test]
|
||||
fn events_propagate() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
_ = dom.rebuild();
|
||||
|
||||
// Top-level click is registered
|
||||
dom.handle_event("click", Rc::new(MouseData::default()), ElementId(1), true);
|
||||
assert_eq!(*CLICKS.lock().unwrap(), 1);
|
||||
|
||||
// break reference....
|
||||
for _ in 0..5 {
|
||||
dom.mark_dirty(ScopeId(0));
|
||||
_ = dom.render_immediate();
|
||||
}
|
||||
|
||||
// Lower click is registered
|
||||
dom.handle_event("click", Rc::new(MouseData::default()), ElementId(2), true);
|
||||
assert_eq!(*CLICKS.lock().unwrap(), 3);
|
||||
|
||||
// break reference....
|
||||
for _ in 0..5 {
|
||||
dom.mark_dirty(ScopeId(0));
|
||||
_ = dom.render_immediate();
|
||||
}
|
||||
|
||||
// Stop propagation occurs
|
||||
dom.handle_event("click", Rc::new(MouseData::default()), ElementId(2), true);
|
||||
assert_eq!(*CLICKS.lock().unwrap(), 3);
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
render! {
|
||||
div {
|
||||
onclick: move |_| {
|
||||
println!("top clicked");
|
||||
*CLICKS.lock().unwrap() += 1;
|
||||
},
|
||||
|
||||
vec![
|
||||
render! {
|
||||
problematic_child {}
|
||||
}
|
||||
].into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn problematic_child(cx: Scope) -> Element {
|
||||
render! {
|
||||
button {
|
||||
onclick: move |evt| {
|
||||
println!("bottom clicked");
|
||||
let mut clicks = CLICKS.lock().unwrap();
|
||||
|
||||
if *clicks == 3 {
|
||||
evt.stop_propagation();
|
||||
} else {
|
||||
*clicks += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use dioxus::prelude::Props;
|
||||
use dioxus_core::*;
|
||||
use std::{cell::Cell, collections::HashSet};
|
||||
use std::{cfg, collections::HashSet};
|
||||
|
||||
fn random_ns() -> Option<&'static str> {
|
||||
let namespace = rand::random::<u8>() % 2;
|
||||
@@ -170,22 +170,23 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
|
||||
let range = if depth > 5 { 1 } else { 4 };
|
||||
match rand::random::<u8>() % range {
|
||||
0 => DynamicNode::Placeholder(Default::default()),
|
||||
1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| VNode {
|
||||
key: None,
|
||||
parent: Default::default(),
|
||||
template: Cell::new(Template {
|
||||
name: concat!(file!(), ":", line!(), ":", column!(), ":0"),
|
||||
roots: &[TemplateNode::Dynamic { id: 0 }],
|
||||
node_paths: &[&[0]],
|
||||
attr_paths: &[],
|
||||
}),
|
||||
root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(),
|
||||
dynamic_nodes: cx.bump().alloc([cx.component(
|
||||
create_random_element,
|
||||
DepthProps { depth, root: false },
|
||||
"create_random_element",
|
||||
)]),
|
||||
dynamic_attrs: &[],
|
||||
1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| {
|
||||
VNode::new(
|
||||
None,
|
||||
Template {
|
||||
name: concat!(file!(), ":", line!(), ":", column!(), ":0"),
|
||||
roots: &[TemplateNode::Dynamic { id: 0 }],
|
||||
node_paths: &[&[0]],
|
||||
attr_paths: &[],
|
||||
},
|
||||
bumpalo::collections::Vec::new_in(cx.bump()),
|
||||
cx.bump().alloc([cx.component(
|
||||
create_random_element,
|
||||
DepthProps { depth, root: false },
|
||||
"create_random_element",
|
||||
)]),
|
||||
&[],
|
||||
)
|
||||
})),
|
||||
2 => cx.component(
|
||||
create_random_element,
|
||||
@@ -271,13 +272,11 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
|
||||
)
|
||||
.into_boxed_str(),
|
||||
));
|
||||
// println!("{template:#?}");
|
||||
let node = VNode {
|
||||
key: None,
|
||||
parent: None,
|
||||
template: Cell::new(template),
|
||||
root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(),
|
||||
dynamic_nodes: {
|
||||
let node = VNode::new(
|
||||
None,
|
||||
template,
|
||||
bumpalo::collections::Vec::new_in(cx.bump()),
|
||||
{
|
||||
let dynamic_nodes: Vec<_> = dynamic_node_types
|
||||
.iter()
|
||||
.map(|ty| match ty {
|
||||
@@ -291,12 +290,12 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
|
||||
.collect();
|
||||
cx.bump().alloc(dynamic_nodes)
|
||||
},
|
||||
dynamic_attrs: cx.bump().alloc(
|
||||
cx.bump().alloc(
|
||||
(0..template.attr_paths.len())
|
||||
.map(|_| create_random_dynamic_attr(cx))
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
};
|
||||
);
|
||||
Some(node)
|
||||
}
|
||||
_ => None,
|
||||
@@ -306,10 +305,10 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
|
||||
}
|
||||
|
||||
// test for panics when creating random nodes and templates
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn create() {
|
||||
for _ in 0..1000 {
|
||||
let repeat_count = if cfg!(miri) { 100 } else { 1000 };
|
||||
for _ in 0..repeat_count {
|
||||
let mut vdom =
|
||||
VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true });
|
||||
let _ = vdom.rebuild();
|
||||
@@ -318,10 +317,10 @@ fn create() {
|
||||
|
||||
// test for panics when diffing random nodes
|
||||
// This test will change the template every render which is not very realistic, but it helps stress the system
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn diff() {
|
||||
for _ in 0..100000 {
|
||||
let repeat_count = if cfg!(miri) { 100 } else { 1000 };
|
||||
for _ in 0..repeat_count {
|
||||
let mut vdom =
|
||||
VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true });
|
||||
let _ = vdom.rebuild();
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn miri_rollover() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
_ = dom.rebuild();
|
||||
|
||||
@@ -15,7 +15,8 @@ fn miri_rollover() {
|
||||
}
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
let mut idx = use_state(cx, || 0);
|
||||
let onhover = |_| println!("go!");
|
||||
|
||||
@@ -31,15 +32,15 @@ fn app(cx: Scope) -> Element {
|
||||
button { onclick: move |_| idx -= 1, "-" }
|
||||
ul {
|
||||
(0..**idx).map(|i| rsx! {
|
||||
child_example { i: i, onhover: onhover }
|
||||
ChildExample { i: i, onhover: onhover }
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn child_example<'a>(cx: Scope<'a>, i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element {
|
||||
#[component]
|
||||
fn ChildExample<'a>(cx: Scope<'a>, i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element {
|
||||
cx.render(rsx! {
|
||||
li {
|
||||
onmouseover: move |e| onhover.call(e),
|
||||
|
||||
@@ -2,13 +2,14 @@ use dioxus::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn app_drops() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {}
|
||||
})
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
_ = dom.rebuild();
|
||||
dom.mark_dirty(ScopeId::ROOT);
|
||||
@@ -17,7 +18,8 @@ fn app_drops() {
|
||||
|
||||
#[test]
|
||||
fn hooks_drop() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.use_hook(|| String::from("asd"));
|
||||
cx.use_hook(|| String::from("asd"));
|
||||
cx.use_hook(|| String::from("asd"));
|
||||
@@ -28,7 +30,7 @@ fn hooks_drop() {
|
||||
})
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
_ = dom.rebuild();
|
||||
dom.mark_dirty(ScopeId::ROOT);
|
||||
@@ -37,17 +39,19 @@ fn hooks_drop() {
|
||||
|
||||
#[test]
|
||||
fn contexts_drop() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.provide_context(String::from("asd"));
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
child_comp {}
|
||||
ChildComp {}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn child_comp(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn ChildComp(cx: Scope) -> Element {
|
||||
let el = cx.consume_context::<String>().unwrap();
|
||||
|
||||
cx.render(rsx! {
|
||||
@@ -55,7 +59,7 @@ fn contexts_drop() {
|
||||
})
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
_ = dom.rebuild();
|
||||
dom.mark_dirty(ScopeId::ROOT);
|
||||
@@ -64,7 +68,8 @@ fn contexts_drop() {
|
||||
|
||||
#[test]
|
||||
fn tasks_drop() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.spawn(async {
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100000)).await;
|
||||
});
|
||||
@@ -74,7 +79,7 @@ fn tasks_drop() {
|
||||
})
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
_ = dom.rebuild();
|
||||
dom.mark_dirty(ScopeId::ROOT);
|
||||
@@ -97,29 +102,30 @@ fn root_props_drop() {
|
||||
|
||||
#[test]
|
||||
fn diffing_drops_old() {
|
||||
fn app(cx: Scope) -> Element {
|
||||
#[component]
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
match cx.generation() % 2 {
|
||||
0 => rsx!( child_comp1 { name: "asdasd".to_string() }),
|
||||
1 => rsx!( child_comp2 { name: "asdasd".to_string() }),
|
||||
0 => rsx!( ChildComp1 { name: "asdasd".to_string() }),
|
||||
1 => rsx!( ChildComp2 { name: "asdasd".to_string() }),
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn child_comp1(cx: Scope, name: String) -> Element {
|
||||
#[component]
|
||||
fn ChildComp1(cx: Scope, name: String) -> Element {
|
||||
cx.render(rsx! { "Hello {name}" })
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn child_comp2(cx: Scope, name: String) -> Element {
|
||||
#[component]
|
||||
fn ChildComp2(cx: Scope, name: String) -> Element {
|
||||
cx.render(rsx! { "Goodbye {name}" })
|
||||
}
|
||||
|
||||
let mut dom = VirtualDom::new(app);
|
||||
let mut dom = VirtualDom::new(App);
|
||||
_ = dom.rebuild();
|
||||
dom.mark_dirty(ScopeId::ROOT);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ fn suspended_child(cx: Scope) -> Element {
|
||||
cx.spawn(async move {
|
||||
val += 1;
|
||||
});
|
||||
return cx.suspend()?;
|
||||
cx.suspend()?;
|
||||
}
|
||||
|
||||
render!("child")
|
||||
|
||||
Reference in new issue
Block a user