mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 14:44:12 +00:00
Tests: add tests for hotreload and recurse into children
This commit is contained in:
parent
982b96074a
commit
e4f65b7260
9 changed files with 109 additions and 31 deletions
|
@ -2,20 +2,19 @@
|
||||||
//!
|
//!
|
||||||
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
|
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
|
||||||
|
|
||||||
use crate::innerlude::{DirtyTasks, ScopeOrder};
|
|
||||||
use crate::Task;
|
use crate::Task;
|
||||||
use crate::{
|
use crate::{
|
||||||
any_props::AnyProps,
|
any_props::AnyProps,
|
||||||
arena::ElementId,
|
arena::ElementId,
|
||||||
innerlude::{
|
innerlude::{
|
||||||
ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount, VProps,
|
DirtyTasks, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeOrder, ScopeState,
|
||||||
WriteMutations,
|
VNodeMount, VProps, WriteMutations,
|
||||||
},
|
},
|
||||||
nodes::RenderReturn,
|
nodes::RenderReturn,
|
||||||
nodes::{Template, TemplateId},
|
nodes::{Template, TemplateId},
|
||||||
runtime::{Runtime, RuntimeGuard},
|
runtime::{Runtime, RuntimeGuard},
|
||||||
scopes::ScopeId,
|
scopes::ScopeId,
|
||||||
AttributeValue, ComponentFunction, Element, Event, Mutations,
|
AttributeValue, ComponentFunction, Element, Event, Mutations, VNode,
|
||||||
};
|
};
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
@ -538,10 +537,29 @@ impl VirtualDom {
|
||||||
// iterating a slab is very inefficient, but this is a rare operation that will only happen during development so it's fine
|
// iterating a slab is very inefficient, but this is a rare operation that will only happen during development so it's fine
|
||||||
let mut dirty = Vec::new();
|
let mut dirty = Vec::new();
|
||||||
for (id, scope) in self.scopes.iter() {
|
for (id, scope) in self.scopes.iter() {
|
||||||
|
// Recurse into the dynamic nodes of the existing mounted node to see if the template is alive in the tree
|
||||||
|
fn check_node_for_templates(node: &VNode, template: Template) -> bool {
|
||||||
|
let this_template_name = node.template.get().name.rsplit_once(':').unwrap().0;
|
||||||
|
|
||||||
|
if this_template_name == template.name.rsplit_once(':').unwrap().0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for dynamic in node.dynamic_nodes.iter() {
|
||||||
|
if let crate::DynamicNode::Fragment(nodes) = dynamic {
|
||||||
|
for node in nodes {
|
||||||
|
if check_node_for_templates(node, template) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(RenderReturn::Ready(sync)) = scope.try_root_node() {
|
if let Some(RenderReturn::Ready(sync)) = scope.try_root_node() {
|
||||||
if sync.template.get().name.rsplit_once(':').unwrap().0
|
if check_node_for_templates(&sync, template) {
|
||||||
== template.name.rsplit_once(':').unwrap().0
|
|
||||||
{
|
|
||||||
dirty.push(ScopeId(id));
|
dirty.push(ScopeId(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::{Expr, File, Item, Macro};
|
use syn::{Expr, File, Item, Macro, Stmt, TraitItem};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DiffResult {
|
pub enum DiffResult {
|
||||||
|
@ -218,7 +218,7 @@ fn find_rsx_trait(
|
||||||
}
|
}
|
||||||
for (new_item, old_item) in new_item.items.iter().zip(old_item.items.iter()) {
|
for (new_item, old_item) in new_item.items.iter().zip(old_item.items.iter()) {
|
||||||
if match (new_item, old_item) {
|
if match (new_item, old_item) {
|
||||||
(syn::TraitItem::Const(new_item), syn::TraitItem::Const(old_item)) => {
|
(TraitItem::Const(new_item), TraitItem::Const(old_item)) => {
|
||||||
if let (Some((_, new_expr)), Some((_, old_expr))) =
|
if let (Some((_, new_expr)), Some((_, old_expr))) =
|
||||||
(&new_item.default, &old_item.default)
|
(&new_item.default, &old_item.default)
|
||||||
{
|
{
|
||||||
|
@ -227,7 +227,7 @@ fn find_rsx_trait(
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(syn::TraitItem::Fn(new_item), syn::TraitItem::Fn(old_item)) => {
|
(TraitItem::Fn(new_item), TraitItem::Fn(old_item)) => {
|
||||||
match (&new_item.default, &old_item.default) {
|
match (&new_item.default, &old_item.default) {
|
||||||
(Some(new_block), Some(old_block)) => {
|
(Some(new_block), Some(old_block)) => {
|
||||||
find_rsx_block(new_block, old_block, rsx_calls)
|
find_rsx_block(new_block, old_block, rsx_calls)
|
||||||
|
@ -236,13 +236,9 @@ fn find_rsx_trait(
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(syn::TraitItem::Type(new_item), syn::TraitItem::Type(old_item)) => {
|
(TraitItem::Type(new_item), TraitItem::Type(old_item)) => old_item != new_item,
|
||||||
old_item != new_item
|
(TraitItem::Macro(new_item), TraitItem::Macro(old_item)) => old_item != new_item,
|
||||||
}
|
(TraitItem::Verbatim(stream), TraitItem::Verbatim(stream2)) => {
|
||||||
(syn::TraitItem::Macro(new_item), syn::TraitItem::Macro(old_item)) => {
|
|
||||||
old_item != new_item
|
|
||||||
}
|
|
||||||
(syn::TraitItem::Verbatim(stream), syn::TraitItem::Verbatim(stream2)) => {
|
|
||||||
stream.to_string() != stream2.to_string()
|
stream.to_string() != stream2.to_string()
|
||||||
}
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
|
@ -280,17 +276,13 @@ fn find_rsx_block(
|
||||||
new_block.brace_token != old_block.brace_token
|
new_block.brace_token != old_block.brace_token
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_rsx_stmt(
|
fn find_rsx_stmt(new_stmt: &Stmt, old_stmt: &Stmt, rsx_calls: &mut Vec<ChangedRsx>) -> bool {
|
||||||
new_stmt: &syn::Stmt,
|
|
||||||
old_stmt: &syn::Stmt,
|
|
||||||
rsx_calls: &mut Vec<ChangedRsx>,
|
|
||||||
) -> bool {
|
|
||||||
match (new_stmt, old_stmt) {
|
match (new_stmt, old_stmt) {
|
||||||
(syn::Stmt::Local(new_local), syn::Stmt::Local(old_local)) => {
|
(Stmt::Local(new_local), Stmt::Local(old_local)) => {
|
||||||
(match (&new_local.init, &old_local.init) {
|
(match (&new_local.init, &old_local.init) {
|
||||||
(Some(new_local), Some(old_local)) => {
|
(Some(new_local), Some(old_local)) => {
|
||||||
find_rsx_expr(&new_local.expr, &old_local.expr, rsx_calls)
|
find_rsx_expr(&new_local.expr, &old_local.expr, rsx_calls)
|
||||||
|| new_local != old_local
|
|| new_local.diverge != old_local.diverge
|
||||||
}
|
}
|
||||||
(None, None) => false,
|
(None, None) => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
|
@ -299,13 +291,13 @@ fn find_rsx_stmt(
|
||||||
|| new_local.pat != old_local.pat
|
|| new_local.pat != old_local.pat
|
||||||
|| new_local.semi_token != old_local.semi_token)
|
|| new_local.semi_token != old_local.semi_token)
|
||||||
}
|
}
|
||||||
(syn::Stmt::Item(new_item), syn::Stmt::Item(old_item)) => {
|
(Stmt::Item(new_item), Stmt::Item(old_item)) => {
|
||||||
find_rsx_item(new_item, old_item, rsx_calls)
|
find_rsx_item(new_item, old_item, rsx_calls)
|
||||||
}
|
}
|
||||||
(syn::Stmt::Expr(new_expr, _), syn::Stmt::Expr(old_expr, _)) => {
|
(Stmt::Expr(new_expr, _), Stmt::Expr(old_expr, _)) => {
|
||||||
find_rsx_expr(new_expr, old_expr, rsx_calls)
|
find_rsx_expr(new_expr, old_expr, rsx_calls)
|
||||||
}
|
}
|
||||||
(syn::Stmt::Macro(new_macro), syn::Stmt::Macro(old_macro)) => {
|
(Stmt::Macro(new_macro), Stmt::Macro(old_macro)) => {
|
||||||
find_rsx_macro(&new_macro.mac, &old_macro.mac, rsx_calls)
|
find_rsx_macro(&new_macro.mac, &old_macro.mac, rsx_calls)
|
||||||
|| new_macro.attrs != old_macro.attrs
|
|| new_macro.attrs != old_macro.attrs
|
||||||
|| new_macro.semi_token != old_macro.semi_token
|
|| new_macro.semi_token != old_macro.semi_token
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use dioxus_rsx::hot_reload::diff_rsx;
|
use dioxus_rsx::hot_reload::{diff_rsx, DiffResult};
|
||||||
use syn::File;
|
use syn::File;
|
||||||
|
|
||||||
fn load_files(old: &str, new: &str) -> (File, File) {
|
fn load_files(old: &str, new: &str) -> (File, File) {
|
||||||
|
@ -10,10 +10,34 @@ fn load_files(old: &str, new: &str) -> (File, File) {
|
||||||
#[test]
|
#[test]
|
||||||
fn hotreloads() {
|
fn hotreloads() {
|
||||||
let (old, new) = load_files(
|
let (old, new) = load_files(
|
||||||
include_str!("./valid_samples/old.expr.rsx"),
|
include_str!("./valid/expr.old.rsx"),
|
||||||
include_str!("./valid_samples/new.expr.rsx"),
|
include_str!("./valid/expr.new.rsx"),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
diff_rsx(&new, &old),
|
||||||
|
DiffResult::RsxChanged { .. }
|
||||||
|
));
|
||||||
|
|
||||||
|
let (old, new) = load_files(
|
||||||
|
include_str!("./valid/let.old.rsx"),
|
||||||
|
include_str!("./valid/let.new.rsx"),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
diff_rsx(&new, &old),
|
||||||
|
DiffResult::RsxChanged { .. }
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doesnt_hotreload() {
|
||||||
|
let (old, new) = load_files(
|
||||||
|
include_str!("./invalid/changedexpr.old.rsx"),
|
||||||
|
include_str!("./invalid/changedexpr.new.rsx"),
|
||||||
);
|
);
|
||||||
|
|
||||||
let res = diff_rsx(&new, &old);
|
let res = diff_rsx(&new, &old);
|
||||||
dbg!(res);
|
dbg!(&res);
|
||||||
|
assert!(matches!(res, DiffResult::CodeChanged(_)));
|
||||||
}
|
}
|
||||||
|
|
9
packages/rsx/tests/invalid/changedexpr.new.rsx
Normal file
9
packages/rsx/tests/invalid/changedexpr.new.rsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
pub fn CoolChild() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
{some_expr()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
packages/rsx/tests/invalid/changedexpr.old.rsx
Normal file
11
packages/rsx/tests/invalid/changedexpr.old.rsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
pub fn CoolChild() -> Element {
|
||||||
|
let a = 123;
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
{some_expr()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
packages/rsx/tests/valid/let.new.rsx
Normal file
12
packages/rsx/tests/valid/let.new.rsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
pub fn CoolChild() -> Element {
|
||||||
|
let head_ = rsx! {
|
||||||
|
div {
|
||||||
|
div { "asasddasdasd" }
|
||||||
|
div { "asasdd1asaassdd23asasddasd" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
head_
|
||||||
|
}
|
12
packages/rsx/tests/valid/let.old.rsx
Normal file
12
packages/rsx/tests/valid/let.old.rsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
pub fn CoolChild() -> Element {
|
||||||
|
let head_ = rsx! {
|
||||||
|
div {
|
||||||
|
div { "asasddasdasd" }
|
||||||
|
div { "asasdd1asaassdd23asasddasdasd" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
head_
|
||||||
|
}
|
Loading…
Reference in a new issue