From 65940cbefa238970a319ade8d8e3ea2b43771722 Mon Sep 17 00:00:00 2001
From: Greg Johnston
Date: Fri, 19 Dec 2025 10:42:44 -0500
Subject: [PATCH] fix: do not show Transition fallback on 2nd change if 1st
change resolved synchronously (closes #4492, closes #3868) (#4495)
---
examples/regression/Cargo.toml | 2 +-
.../e2e/features/issue_4492.feature | 38 ++++++
.../regression/e2e/tests/fixtures/action.rs | 6 +
.../regression/e2e/tests/fixtures/check.rs | 10 +-
.../e2e/tests/fixtures/world/action_steps.rs | 15 +++
.../e2e/tests/fixtures/world/check_steps.rs | 11 ++
examples/regression/src/app.rs | 4 +-
examples/regression/src/issue_4492.rs | 114 ++++++++++++++++++
examples/regression/src/lib.rs | 1 +
leptos/src/suspense_component.rs | 42 +++++--
leptos/src/transition.rs | 21 ++--
leptos_server/src/once_resource.rs | 18 ++-
.../async_derived/arc_async_derived.rs | 27 ++++-
13 files changed, 280 insertions(+), 29 deletions(-)
create mode 100644 examples/regression/e2e/features/issue_4492.feature
create mode 100644 examples/regression/src/issue_4492.rs
diff --git a/examples/regression/Cargo.toml b/examples/regression/Cargo.toml
index fb5a79b6c..39b160d7c 100644
--- a/examples/regression/Cargo.toml
+++ b/examples/regression/Cargo.toml
@@ -17,7 +17,7 @@ leptos_router = { path = "../../router" }
serde = { version = "1.0", features = ["derive"] }
thiserror = "2.0.12"
tokio = { version = "1.39", features = [ "rt-multi-thread", "macros", "time" ], optional = true }
-wasm-bindgen = "0.2.92"
+wasm-bindgen = "0.2.106"
[features]
hydrate = [
diff --git a/examples/regression/e2e/features/issue_4492.feature b/examples/regression/e2e/features/issue_4492.feature
new file mode 100644
index 000000000..dd651d17d
--- /dev/null
+++ b/examples/regression/e2e/features/issue_4492.feature
@@ -0,0 +1,38 @@
+@check_issue_4492
+Feature: Regression test for issue #4492
+
+ Scenario: Scenario A should show Loading once on first load.
+ Given I see the app
+ And I can access regression test 4492
+ When I click the button a-toggle
+ Then I see a-result has the text Loading...
+ When I wait 100ms
+ Then I see a-result has the text 0
+ When I click the button a-button
+ Then I see a-result has the text 0
+ When I wait 100ms
+ Then I see a-result has the text 1
+
+ Scenario: Scenario B should never show Loading
+ Given I see the app
+ And I can access regression test 4492
+ When I click the button b-toggle
+ Then I see b-result has the text 0
+ When I click the button b-button
+ Then I see b-result has the text 0
+ When I wait 100ms
+ Then I see b-result has the text 1
+ When I click the button b-button
+ Then I see b-result has the text 1
+ When I wait 100ms
+ Then I see b-result has the text 2
+
+ Scenario: Scenario C should never show Loading
+ Given I see the app
+ And I can access regression test 4492
+ When I click the button c-toggle
+ Then I see c-result has the text 0
+ When I click the button c-button
+ Then I see c-result has the text 42
+ When I wait 100ms
+ Then I see c-result has the text 1
diff --git a/examples/regression/e2e/tests/fixtures/action.rs b/examples/regression/e2e/tests/fixtures/action.rs
index 7f4c75adf..fb9f2d869 100644
--- a/examples/regression/e2e/tests/fixtures/action.rs
+++ b/examples/regression/e2e/tests/fixtures/action.rs
@@ -15,3 +15,9 @@ pub async fn click_link(client: &Client, text: &str) -> Result<()> {
link.click().await?;
Ok(())
}
+
+pub async fn click_button(client: &Client, id: &str) -> Result<()> {
+ let btn = find::element_by_id(&client, &id).await?;
+ btn.click().await?;
+ Ok(())
+}
diff --git a/examples/regression/e2e/tests/fixtures/check.rs b/examples/regression/e2e/tests/fixtures/check.rs
index e021171f4..aecdf324d 100644
--- a/examples/regression/e2e/tests/fixtures/check.rs
+++ b/examples/regression/e2e/tests/fixtures/check.rs
@@ -7,7 +7,15 @@ pub async fn result_text_is(
client: &Client,
expected_text: &str,
) -> Result<()> {
- let actual = find::text_at_id(client, "result").await?;
+ element_text_is(client, "result", expected_text).await
+}
+
+pub async fn element_text_is(
+ client: &Client,
+ id: &str,
+ expected_text: &str,
+) -> Result<()> {
+ let actual = find::text_at_id(client, id).await?;
assert_eq!(&actual, expected_text);
Ok(())
}
diff --git a/examples/regression/e2e/tests/fixtures/world/action_steps.rs b/examples/regression/e2e/tests/fixtures/world/action_steps.rs
index c0f160dc3..4c908fe94 100644
--- a/examples/regression/e2e/tests/fixtures/world/action_steps.rs
+++ b/examples/regression/e2e/tests/fixtures/world/action_steps.rs
@@ -20,6 +20,14 @@ async fn i_select_the_link(world: &mut AppWorld, text: String) -> Result<()> {
Ok(())
}
+#[when(regex = "^I click the button (.*)$")]
+async fn i_click_the_button(world: &mut AppWorld, id: String) -> Result<()> {
+ let client = &world.client;
+ action::click_button(client, &id).await?;
+
+ Ok(())
+}
+
#[given(expr = "I select the following links")]
#[when(expr = "I select the following links")]
async fn i_select_the_following_links(
@@ -54,3 +62,10 @@ async fn i_go_back(world: &mut AppWorld) -> Result<()> {
Ok(())
}
+
+#[when(regex = r"^I wait (\d+)ms$")]
+async fn i_wait_ms(_world: &mut AppWorld, ms: u64) -> Result<()> {
+ tokio::time::sleep(std::time::Duration::from_millis(ms)).await;
+
+ Ok(())
+}
diff --git a/examples/regression/e2e/tests/fixtures/world/check_steps.rs b/examples/regression/e2e/tests/fixtures/world/check_steps.rs
index 51255fedc..c5b6236a0 100644
--- a/examples/regression/e2e/tests/fixtures/world/check_steps.rs
+++ b/examples/regression/e2e/tests/fixtures/world/check_steps.rs
@@ -19,6 +19,17 @@ async fn i_see_the_result_is_the_string(
Ok(())
}
+#[then(regex = r"^I see ([\w-]+) has the text (.*)$")]
+async fn i_see_element_has_text(
+ world: &mut AppWorld,
+ id: String,
+ text: String,
+) -> Result<()> {
+ let client = &world.client;
+ check::element_text_is(client, &id, &text).await?;
+ Ok(())
+}
+
#[then(regex = r"^I see the navbar$")]
async fn i_see_the_navbar(world: &mut AppWorld) -> Result<()> {
let client = &world.client;
diff --git a/examples/regression/src/app.rs b/examples/regression/src/app.rs
index c2a3f85ba..a44f05b04 100644
--- a/examples/regression/src/app.rs
+++ b/examples/regression/src/app.rs
@@ -1,7 +1,7 @@
use crate::{
issue_4005::Routes4005, issue_4088::Routes4088, issue_4217::Routes4217,
issue_4285::Routes4285, issue_4296::Routes4296, issue_4324::Routes4324,
- pr_4015::Routes4015, pr_4091::Routes4091,
+ issue_4492::Routes4492, pr_4015::Routes4015, pr_4091::Routes4091,
};
use leptos::prelude::*;
use leptos_meta::{MetaTags, *};
@@ -48,6 +48,7 @@ pub fn App() -> impl IntoView {
+
@@ -75,6 +76,7 @@ fn HomePage() -> impl IntoView {