diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 6d28078418..8a0ef7e89c 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -44,9 +44,10 @@ impl ScopeId { /// use dioxus::prelude::*; /// let my_persistent_state = Signal::new_in_scope(String::new(), ScopeId::APP); /// ``` + // Refer to `RootScopeWrapper` (root_wrapper.rs) to see where these constants come from. // ScopeId(0) is the root scope wrapper - // ScopeId(1) is the default error boundary - // ScopeId(2) is the default suspense boundary + // ScopeId(1) is the default suspense boundary + // ScopeId(2) is the default error boundary // ScopeId(3) is the users root scope pub const APP: ScopeId = ScopeId(3); diff --git a/packages/core/tests/bubble_error.rs b/packages/core/tests/bubble_error.rs index 814c293f61..791e569bee 100644 --- a/packages/core/tests/bubble_error.rs +++ b/packages/core/tests/bubble_error.rs @@ -16,6 +16,7 @@ fn app() -> Element { } #[test] +#[ignore] // Test doesn't do anything. fn bubbles_error() { let mut dom = VirtualDom::new(app); diff --git a/packages/core/tests/conditional_formatted_attributes.rs b/packages/core/tests/conditional_formatted_attributes.rs index cd0e860ec8..2d17abefee 100644 --- a/packages/core/tests/conditional_formatted_attributes.rs +++ b/packages/core/tests/conditional_formatted_attributes.rs @@ -1,7 +1,8 @@ use dioxus::prelude::*; /// Make sure that rsx! handles conditional attributes with one formatted branch correctly -/// Regression test for https://github.com/DioxusLabs/dioxus/issues/2997 +/// Regression test for https://github.com/DioxusLabs/dioxus/issues/2997. There are no assertions in +/// this test as it primarily checks that the RSX can be compiled correctly. #[test] fn partially_formatted_conditional_attribute() { let width = "1px"; diff --git a/packages/core/tests/diff_keyed_list.rs b/packages/core/tests/diff_keyed_list.rs index b2b46f4d14..8f73f40aa3 100644 --- a/packages/core/tests/diff_keyed_list.rs +++ b/packages/core/tests/diff_keyed_list.rs @@ -2,7 +2,7 @@ //! //! These tests only verify that the diffing algorithm works properly for single components. //! -//! It does not validated that component lifecycles work properly. This is done in another test file. +//! It does not validate that component lifecycles work properly. This is done in another test file. use dioxus::dioxus_core::{ElementId, Mutation::*}; use dioxus::prelude::*; diff --git a/packages/core/tests/diff_unkeyed_list.rs b/packages/core/tests/diff_unkeyed_list.rs index fb32461182..9792c1fbf4 100644 --- a/packages/core/tests/diff_unkeyed_list.rs +++ b/packages/core/tests/diff_unkeyed_list.rs @@ -464,7 +464,7 @@ fn replace_and_add_items() { ); } - // Rerendering adds an a static template + // Rerendering adds a static template { dom.mark_dirty(ScopeId::APP); let edits = dom.render_immediate_to_vec(); diff --git a/packages/core/tests/error_boundary.rs b/packages/core/tests/error_boundary.rs index ed19de72e8..ce3486d5ea 100644 --- a/packages/core/tests/error_boundary.rs +++ b/packages/core/tests/error_boundary.rs @@ -44,7 +44,7 @@ fn clear_error_boundary() { #[component] pub fn ThrowsError() -> Element { - if THREW_ERROR.load(std::sync::atomic::Ordering::SeqCst) { + if !THREW_ERROR.load(std::sync::atomic::Ordering::SeqCst) { THREW_ERROR.store(true, std::sync::atomic::Ordering::SeqCst); Err(CapturedError::from_display("This is an error").into()) } else { @@ -73,7 +73,22 @@ fn clear_error_boundary() { let mut dom = VirtualDom::new(App); dom.rebuild(&mut dioxus_core::NoOpMutations); - let out = dioxus_ssr::render(&dom); + // The DOM will now contain no text - the error was thrown by ThrowsError and caught by the + // ErrorBoundary. This calls `needs_update()`, but the update hasn't been processed yet. + + dom.render_immediate(&mut dioxus_core::NoOpMutations); + // The ErrorBoundary has now called its `handle_error` handler. The DOM contains the string + // "We cleared it", and `needs_update()` has been called again (by `error.clear_errors()`) + + dom.render_immediate(&mut dioxus_core::NoOpMutations); + // `ThrowsError` is re-rendered, but this time does not throw an error, so at the end the DOM + // contains "We should see this" + let out = dioxus_ssr::render(&dom); assert_eq!(out, "We should see this"); + + // There should be no errors left in the error boundary + dom.in_runtime(|| { + ScopeId::APP.in_runtime(|| assert!(consume_context::().errors().is_empty())) + }) } diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index a26bc08ccd..e3e340ef64 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -287,6 +287,11 @@ fn create() { let mut vdom = VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true }); vdom.rebuild(&mut NoOpMutations); + + vdom.in_runtime(|| { + ScopeId::APP + .in_runtime(|| assert!(consume_context::().errors().is_empty())) + }) } } @@ -317,6 +322,11 @@ fn diff() { )); } } + + vdom.in_runtime(|| { + ScopeId::APP + .in_runtime(|| assert!(consume_context::().errors().is_empty())) + }) } } diff --git a/packages/core/tests/miri_full_app.rs b/packages/core/tests/miri_full_app.rs index 1196b4263e..883a7bedde 100644 --- a/packages/core/tests/miri_full_app.rs +++ b/packages/core/tests/miri_full_app.rs @@ -3,6 +3,8 @@ use dioxus_core::ElementId; use dioxus_elements::SerializedHtmlEventConverter; use std::{any::Any, rc::Rc}; +// This test is intended to be run with Miri, and contains no assertions. If it completes under +// Miri, it has passed. #[test] fn miri_rollover() { set_event_converter(Box::new(SerializedHtmlEventConverter)); diff --git a/packages/core/tests/miri_simple.rs b/packages/core/tests/miri_simple.rs index 8d7f6f3431..aa5c6216bb 100644 --- a/packages/core/tests/miri_simple.rs +++ b/packages/core/tests/miri_simple.rs @@ -1,6 +1,9 @@ use dioxus::prelude::*; use dioxus_core::generation; +// The tests in this file are intended to be run with Miri, and contain no assertions. If they +// complete under Miri, they have passed. + #[test] fn app_drops() { fn app() -> Element { diff --git a/packages/core/tests/miri_stress.rs b/packages/core/tests/miri_stress.rs index 5659395ac6..e2a7d27623 100644 --- a/packages/core/tests/miri_stress.rs +++ b/packages/core/tests/miri_stress.rs @@ -5,6 +5,9 @@ use std::rc::Rc; use dioxus::prelude::*; use dioxus_core::{generation, NoOpMutations}; +// The tests in this file are intended to be run with Miri, so not all of them contain assertions. +// If the tests complete under Miri, they have passed. + /// This test checks that we should release all memory used by the virtualdom when it exits. /// /// When miri runs, it'll let us know if we leaked or aliased. diff --git a/packages/core/tests/suspense.rs b/packages/core/tests/suspense.rs index ecf3035df3..72fa70336b 100644 --- a/packages/core/tests/suspense.rs +++ b/packages/core/tests/suspense.rs @@ -217,22 +217,6 @@ fn suspended_nodes_dont_trigger_effects() { } } - #[component] - fn RerendersFrequently() -> Element { - let mut count = use_signal(|| 0); - - use_future(move || async move { - for _ in 0..100 { - tokio::time::sleep(std::time::Duration::from_millis(10)).await; - count.set(count() + 1); - } - }); - - rsx! { - div { "rerenders frequently" } - } - } - #[component] fn Child() -> Element { let mut future_resolved = use_signal(|| false); @@ -474,22 +458,6 @@ fn toggle_suspense() { fn nested_suspense_resolves_client() { use Mutation::*; - async fn poll_three_times() { - // Poll each task 3 times - let mut count = 0; - poll_fn(|cx| { - println!("polling... {}", count); - if count < 3 { - count += 1; - cx.waker().wake_by_ref(); - Poll::Pending - } else { - Poll::Ready(()) - } - }) - .await; - } - fn app() -> Element { rsx! { SuspenseBoundary { diff --git a/packages/signals/tests/create.rs b/packages/signals/tests/create.rs index c322a78e24..d765bffbd6 100644 --- a/packages/signals/tests/create.rs +++ b/packages/signals/tests/create.rs @@ -1,7 +1,7 @@ #![allow(unused, non_upper_case_globals, non_snake_case)] use dioxus::prelude::*; -use dioxus_core::{generation, ElementId, NoOpMutations}; +use dioxus_core::{generation, ElementId, Mutation, NoOpMutations}; use dioxus_signals::*; #[test] @@ -22,35 +22,57 @@ fn create_signals_global() { } } - dom.rebuild_in_place(); - fn create_without_cx() -> Signal { Signal::new("hello world".to_string()) } + + let muts = dom.rebuild_to_vec(); + + // 11 edits: 10x CreateTextNode and 1x AppendChildren. These assertions rely on the VirtualDOM's + // logic, but doing this means not introducing a dependency on a renderer. + assert_eq!(11, muts.edits.len()); + for i in 0..10 { + assert_eq!( + &muts.edits[i], + &Mutation::CreateTextNode { + value: ("hello world".to_string()), + id: ElementId(i + 1) + } + ); + } + assert_eq!( + &muts.edits[10], + &Mutation::AppendChildren { + id: ElementId(0), + m: 10 + } + ) } #[test] fn deref_signal() { + use std::sync::atomic::{AtomicBool, Ordering}; + static STRINGS_MATCH: AtomicBool = AtomicBool::new(false); + let mut dom = VirtualDom::new(|| { - rsx! { - for _ in 0..10 { - Child {} - } - } + rsx! { Child {} } }); fn Child() -> Element { let signal = Signal::new("hello world".to_string()); // You can call signals like functions to get a Ref of their value. - assert_eq!(&*signal(), "hello world"); + let result = &*signal(); + STRINGS_MATCH.store(result.eq("hello world"), Ordering::Relaxed); rsx! { - "hello world" + "arbitrary text" } } dom.rebuild_in_place(); + + assert!(STRINGS_MATCH.load(Ordering::Relaxed)); } #[test] diff --git a/packages/signals/tests/memo.rs b/packages/signals/tests/memo.rs index 9601a9f669..5ee212eace 100644 --- a/packages/signals/tests/memo.rs +++ b/packages/signals/tests/memo.rs @@ -1,8 +1,8 @@ #![allow(unused, non_upper_case_globals, non_snake_case)] use dioxus::html::p; use dioxus::prelude::*; -use dioxus_core::NoOpMutations; use dioxus_core::{generation, ElementId}; +use dioxus_core::{NoOpMutations, ScopeState}; use dioxus_signals::*; use std::cell::RefCell; use std::collections::HashMap; @@ -141,6 +141,10 @@ fn memos_prevents_component_rerun() { assert_eq!(current_counter.component, 2); assert_eq!(current_counter.memo, 3); } + + dom.in_runtime(|| { + ScopeId(3).in_runtime(|| assert!(consume_context::().errors().is_empty())) + }); } // Regression test for https://github.com/DioxusLabs/dioxus/issues/2990