From e4f65b72600b0f4780bb108740ddad1e80799133 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 13 Mar 2024 14:15:34 -0700 Subject: [PATCH] Tests: add tests for hotreload and recurse into children --- packages/core/src/virtual_dom.rs | 32 +++++++++++++++---- .../rsx/src/hot_reload/hot_reload_diff.rs | 32 +++++++------------ packages/rsx/tests/hotreloads.rs | 32 ++++++++++++++++--- .../rsx/tests/invalid/changedexpr.new.rsx | 9 ++++++ .../rsx/tests/invalid/changedexpr.old.rsx | 11 +++++++ .../new.expr.rsx => valid/expr.new.rsx} | 0 .../old.expr.rsx => valid/expr.old.rsx} | 0 packages/rsx/tests/valid/let.new.rsx | 12 +++++++ packages/rsx/tests/valid/let.old.rsx | 12 +++++++ 9 files changed, 109 insertions(+), 31 deletions(-) create mode 100644 packages/rsx/tests/invalid/changedexpr.new.rsx create mode 100644 packages/rsx/tests/invalid/changedexpr.old.rsx rename packages/rsx/tests/{valid_samples/new.expr.rsx => valid/expr.new.rsx} (100%) rename packages/rsx/tests/{valid_samples/old.expr.rsx => valid/expr.old.rsx} (100%) create mode 100644 packages/rsx/tests/valid/let.new.rsx create mode 100644 packages/rsx/tests/valid/let.old.rsx diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 0d5f84e11..203efa41c 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -2,20 +2,19 @@ //! //! 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::{ any_props::AnyProps, arena::ElementId, innerlude::{ - ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount, VProps, - WriteMutations, + DirtyTasks, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeOrder, ScopeState, + VNodeMount, VProps, WriteMutations, }, nodes::RenderReturn, nodes::{Template, TemplateId}, runtime::{Runtime, RuntimeGuard}, scopes::ScopeId, - AttributeValue, ComponentFunction, Element, Event, Mutations, + AttributeValue, ComponentFunction, Element, Event, Mutations, VNode, }; use futures_util::StreamExt; 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 let mut dirty = Vec::new(); 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 sync.template.get().name.rsplit_once(':').unwrap().0 - == template.name.rsplit_once(':').unwrap().0 - { + if check_node_for_templates(&sync, template) { dirty.push(ScopeId(id)); } } diff --git a/packages/rsx/src/hot_reload/hot_reload_diff.rs b/packages/rsx/src/hot_reload/hot_reload_diff.rs index 58e681687..4c7a02db3 100644 --- a/packages/rsx/src/hot_reload/hot_reload_diff.rs +++ b/packages/rsx/src/hot_reload/hot_reload_diff.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::ToTokens; -use syn::{Expr, File, Item, Macro}; +use syn::{Expr, File, Item, Macro, Stmt, TraitItem}; #[derive(Debug)] 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()) { 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))) = (&new_item.default, &old_item.default) { @@ -227,7 +227,7 @@ fn find_rsx_trait( 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) { (Some(new_block), Some(old_block)) => { find_rsx_block(new_block, old_block, rsx_calls) @@ -236,13 +236,9 @@ fn find_rsx_trait( _ => true, } } - (syn::TraitItem::Type(new_item), syn::TraitItem::Type(old_item)) => { - old_item != new_item - } - (syn::TraitItem::Macro(new_item), syn::TraitItem::Macro(old_item)) => { - old_item != new_item - } - (syn::TraitItem::Verbatim(stream), syn::TraitItem::Verbatim(stream2)) => { + (TraitItem::Type(new_item), TraitItem::Type(old_item)) => old_item != new_item, + (TraitItem::Macro(new_item), TraitItem::Macro(old_item)) => old_item != new_item, + (TraitItem::Verbatim(stream), TraitItem::Verbatim(stream2)) => { stream.to_string() != stream2.to_string() } _ => true, @@ -280,17 +276,13 @@ fn find_rsx_block( new_block.brace_token != old_block.brace_token } -fn find_rsx_stmt( - new_stmt: &syn::Stmt, - old_stmt: &syn::Stmt, - rsx_calls: &mut Vec, -) -> bool { +fn find_rsx_stmt(new_stmt: &Stmt, old_stmt: &Stmt, rsx_calls: &mut Vec) -> bool { 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) { (Some(new_local), Some(old_local)) => { find_rsx_expr(&new_local.expr, &old_local.expr, rsx_calls) - || new_local != old_local + || new_local.diverge != old_local.diverge } (None, None) => false, _ => true, @@ -299,13 +291,13 @@ fn find_rsx_stmt( || new_local.pat != old_local.pat || 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) } - (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) } - (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) || new_macro.attrs != old_macro.attrs || new_macro.semi_token != old_macro.semi_token diff --git a/packages/rsx/tests/hotreloads.rs b/packages/rsx/tests/hotreloads.rs index 58e31606f..68dedb370 100644 --- a/packages/rsx/tests/hotreloads.rs +++ b/packages/rsx/tests/hotreloads.rs @@ -1,4 +1,4 @@ -use dioxus_rsx::hot_reload::diff_rsx; +use dioxus_rsx::hot_reload::{diff_rsx, DiffResult}; use syn::File; fn load_files(old: &str, new: &str) -> (File, File) { @@ -10,10 +10,34 @@ fn load_files(old: &str, new: &str) -> (File, File) { #[test] fn hotreloads() { let (old, new) = load_files( - include_str!("./valid_samples/old.expr.rsx"), - include_str!("./valid_samples/new.expr.rsx"), + include_str!("./valid/expr.old.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); - dbg!(res); + dbg!(&res); + assert!(matches!(res, DiffResult::CodeChanged(_))); } diff --git a/packages/rsx/tests/invalid/changedexpr.new.rsx b/packages/rsx/tests/invalid/changedexpr.new.rsx new file mode 100644 index 000000000..256d82c1f --- /dev/null +++ b/packages/rsx/tests/invalid/changedexpr.new.rsx @@ -0,0 +1,9 @@ +use dioxus::prelude::*; + +pub fn CoolChild() -> Element { + rsx! { + div { + {some_expr()} + } + } +} diff --git a/packages/rsx/tests/invalid/changedexpr.old.rsx b/packages/rsx/tests/invalid/changedexpr.old.rsx new file mode 100644 index 000000000..bbeeeacaf --- /dev/null +++ b/packages/rsx/tests/invalid/changedexpr.old.rsx @@ -0,0 +1,11 @@ +use dioxus::prelude::*; + +pub fn CoolChild() -> Element { + let a = 123; + + rsx! { + div { + {some_expr()} + } + } +} diff --git a/packages/rsx/tests/valid_samples/new.expr.rsx b/packages/rsx/tests/valid/expr.new.rsx similarity index 100% rename from packages/rsx/tests/valid_samples/new.expr.rsx rename to packages/rsx/tests/valid/expr.new.rsx diff --git a/packages/rsx/tests/valid_samples/old.expr.rsx b/packages/rsx/tests/valid/expr.old.rsx similarity index 100% rename from packages/rsx/tests/valid_samples/old.expr.rsx rename to packages/rsx/tests/valid/expr.old.rsx diff --git a/packages/rsx/tests/valid/let.new.rsx b/packages/rsx/tests/valid/let.new.rsx new file mode 100644 index 000000000..cfd147705 --- /dev/null +++ b/packages/rsx/tests/valid/let.new.rsx @@ -0,0 +1,12 @@ +use dioxus::prelude::*; + +pub fn CoolChild() -> Element { + let head_ = rsx! { + div { + div { "asasddasdasd" } + div { "asasdd1asaassdd23asasddasd" } + } + }; + + head_ +} diff --git a/packages/rsx/tests/valid/let.old.rsx b/packages/rsx/tests/valid/let.old.rsx new file mode 100644 index 000000000..5755fe107 --- /dev/null +++ b/packages/rsx/tests/valid/let.old.rsx @@ -0,0 +1,12 @@ +use dioxus::prelude::*; + +pub fn CoolChild() -> Element { + let head_ = rsx! { + div { + div { "asasddasdasd" } + div { "asasdd1asaassdd23asasddasdasd" } + } + }; + + head_ +}