Minor fixes for tests (#4686)

* Suggested method for correcting integration tests

* Use static atomics for simplicity

This is consistent with the test immediately below.

* Add assertions to some tests, comments to others

This should fix a handful of tests that didn't correctly do their test.

In other places, comments should make it clearer *why* tests are how
they are.

* Be consistent with existing imports

* remove bad test

* nit

* fix compile errrs

---------

Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
MartinandJonathan Kelley authored and GitHub committed 2026-04-14 15:37:30 -07:00
1 parent 679ba83652
commit 79693f8cff
12 files changed
+74 -77

No files matched your search

-29
View File
@@ -1,29 +0,0 @@
//! we should properly bubble up errors from components
use dioxus::prelude::*;
use dioxus_core::generation;
fn app() -> Element {
let raw = match generation() % 2 {
0 => "123.123",
1 => "123.123.123",
_ => unreachable!(),
};
let value = raw.parse::<f32>().unwrap_or(123.123);
rsx! { div { "hello {value}" } }
}
#[test]
fn bubbles_error() {
let mut dom = VirtualDom::new(app);
{
let _edits = dom.rebuild_to_vec();
}
dom.mark_dirty(ScopeId::APP);
_ = dom.render_immediate_to_vec();
}
@@ -1,7 +1,8 @@
use dioxus::prelude::*; use dioxus::prelude::*;
/// Make sure that rsx! handles conditional attributes with one formatted branch correctly /// 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] #[test]
fn partially_formatted_conditional_attribute() { fn partially_formatted_conditional_attribute() {
let width = "1px"; let width = "1px";
+1 -1
View File
@@ -2,7 +2,7 @@
//! //!
//! These tests only verify that the diffing algorithm works properly for single components. //! 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::dioxus_core::{ElementId, Mutation::*};
use dioxus::prelude::*; use dioxus::prelude::*;
+1 -1
View File
@@ -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); dom.mark_dirty(ScopeId::APP);
let edits = dom.render_immediate_to_vec(); let edits = dom.render_immediate_to_vec();
+17 -2
View File
@@ -44,7 +44,7 @@ fn clear_error_boundary() {
#[component] #[component]
pub fn ThrowsError() -> Element { 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); THREW_ERROR.store(true, std::sync::atomic::Ordering::SeqCst);
Err(CapturedError::from_display("This is an error").into()) Err(CapturedError::from_display("This is an error").into())
} else { } else {
@@ -71,7 +71,22 @@ fn clear_error_boundary() {
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
dom.rebuild(&mut dioxus_core::NoOpMutations); 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"); assert_eq!(out, "We should see this");
// There should be no errors left in the error boundary
dom.in_scope(ScopeId::APP, || {
assert!(consume_context::<ErrorContext>().error().is_none())
})
} }
+8
View File
@@ -287,6 +287,10 @@ fn create() {
let mut vdom = let mut vdom =
VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true }); VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true });
vdom.rebuild(&mut NoOpMutations); vdom.rebuild(&mut NoOpMutations);
vdom.in_scope(ScopeId::APP, || {
assert!(consume_context::<ErrorContext>().error().is_none())
})
} }
} }
@@ -317,6 +321,10 @@ fn diff() {
)); ));
} }
} }
vdom.in_scope(ScopeId::APP, || {
assert!(consume_context::<ErrorContext>().error().is_none())
})
} }
} }
+2
View File
@@ -3,6 +3,8 @@ use dioxus_core::ElementId;
use dioxus_elements::SerializedHtmlEventConverter; use dioxus_elements::SerializedHtmlEventConverter;
use std::{any::Any, rc::Rc}; 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] #[test]
fn miri_rollover() { fn miri_rollover() {
set_event_converter(Box::new(SerializedHtmlEventConverter)); set_event_converter(Box::new(SerializedHtmlEventConverter));
+3
View File
@@ -1,6 +1,9 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::generation; 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] #[test]
fn app_drops() { fn app_drops() {
fn app() -> Element { fn app() -> Element {
+3
View File
@@ -5,6 +5,9 @@ use std::rc::Rc;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::{generation, NoOpMutations}; 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. /// 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. /// When miri runs, it'll let us know if we leaked or aliased.
-32
View File
@@ -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] #[component]
fn Child() -> Element { fn Child() -> Element {
let mut future_resolved = use_signal(|| false); let mut future_resolved = use_signal(|| false);
@@ -474,22 +458,6 @@ fn toggle_suspense() {
fn nested_suspense_resolves_client() { fn nested_suspense_resolves_client() {
use Mutation::*; 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 { fn app() -> Element {
rsx! { rsx! {
SuspenseBoundary { SuspenseBoundary {
+32 -10
View File
@@ -1,7 +1,7 @@
#![allow(unused, non_upper_case_globals, non_snake_case)] #![allow(unused, non_upper_case_globals, non_snake_case)]
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::{generation, ElementId, NoOpMutations}; use dioxus_core::{generation, ElementId, Mutation, NoOpMutations};
use dioxus_signals::*; use dioxus_signals::*;
#[test] #[test]
@@ -22,35 +22,57 @@ fn create_signals_global() {
} }
} }
dom.rebuild_in_place();
fn create_without_cx() -> Signal<String> { fn create_without_cx() -> Signal<String> {
Signal::new("hello world".to_string()) 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] #[test]
fn deref_signal() { fn deref_signal() {
use std::sync::atomic::{AtomicBool, Ordering};
static STRINGS_MATCH: AtomicBool = AtomicBool::new(false);
let mut dom = VirtualDom::new(|| { let mut dom = VirtualDom::new(|| {
rsx! { rsx! { Child {} }
for _ in 0..10 {
Child {}
}
}
}); });
fn Child() -> Element { fn Child() -> Element {
let signal = Signal::new("hello world".to_string()); let signal = Signal::new("hello world".to_string());
// You can call signals like functions to get a Ref of their value. // 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! { rsx! {
"hello world" "arbitrary text"
} }
} }
dom.rebuild_in_place(); dom.rebuild_in_place();
assert!(STRINGS_MATCH.load(Ordering::Relaxed));
} }
#[test] #[test]
+5 -1
View File
@@ -1,8 +1,8 @@
#![allow(unused, non_upper_case_globals, non_snake_case)] #![allow(unused, non_upper_case_globals, non_snake_case)]
use dioxus::html::p; use dioxus::html::p;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::NoOpMutations;
use dioxus_core::{generation, ElementId}; use dioxus_core::{generation, ElementId};
use dioxus_core::{NoOpMutations, ScopeState};
use dioxus_signals::*; use dioxus_signals::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
@@ -141,6 +141,10 @@ fn memos_prevents_component_rerun() {
assert_eq!(current_counter.component, 2); assert_eq!(current_counter.component, 2);
assert_eq!(current_counter.memo, 3); assert_eq!(current_counter.memo, 3);
} }
dom.in_scope(ScopeId(3), || {
assert!(consume_context::<ErrorContext>().error().is_none())
});
} }
// Regression test for https://github.com/DioxusLabs/dioxus/issues/2990 // Regression test for https://github.com/DioxusLabs/dioxus/issues/2990