Skip to content

Commit 49415d3

Browse files
committed
test(async_view): SSR render tests for the four UI states
Add a dioxus-ssr dev-dependency and render-level tests asserting AsyncView's markup per state: loading spinner, empty message, error message, and the Retry button gated on `retriable`. The rsx is built inside the rendered component so AsyncView's default EventHandler prop is constructed within the VirtualDom runtime. cargo nextest run: 42 passed (was 37).
1 parent 2f64888 commit 49415d3

4 files changed

Lines changed: 112 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
2525
# UI. The `router` feature re-exports the router through dioxus::prelude.
2626
# Desktop-only for the skeleton.
2727
dioxus = { version = "0.7", features = ["desktop", "router"] }
28+
# Test-only: render components to a string for render-level assertions.
29+
dioxus-ssr = "0.7"
2830

2931
# Serialization. Kept for derive on models/preferences; no runtime parsing
3032
# happens in the skeleton (mock data is hardcoded Rust).

nodedb-studio/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ sonic-rs = { workspace = true }
2222
thiserror = { workspace = true }
2323
async-trait = { workspace = true }
2424
tracing = { workspace = true }
25+
26+
[dev-dependencies]
27+
dioxus-ssr = { workspace = true }

nodedb-studio/src/components/async_view.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,91 @@ pub fn AsyncView(props: AsyncViewProps) -> Element {
7171
// Loaded: the caller renders its own markup; AsyncView renders nothing.
7272
rsx! {}
7373
}
74+
75+
#[cfg(test)]
76+
mod tests {
77+
use super::*;
78+
79+
// SSR the given root component to HTML. The rsx is built INSIDE the component
80+
// (i.e. within the VirtualDom runtime) because `AsyncView`'s default
81+
// `EventHandler` prop can only be constructed while a runtime is in scope.
82+
fn render(app: fn() -> Element) -> String {
83+
let mut dom = VirtualDom::new(app);
84+
dom.rebuild_in_place();
85+
dioxus_ssr::render(&dom)
86+
}
87+
88+
#[test]
89+
fn loading_renders_spinner() {
90+
fn app() -> Element {
91+
rsx! { AsyncView { loading: true, empty: false, error: None } }
92+
}
93+
let html = render(app);
94+
assert!(html.contains("async-loading"));
95+
assert!(html.contains("Loading"));
96+
}
97+
98+
#[test]
99+
fn empty_renders_message() {
100+
fn app() -> Element {
101+
rsx! {
102+
AsyncView {
103+
loading: false,
104+
empty: true,
105+
error: None,
106+
empty_message: "Nothing here".to_string(),
107+
}
108+
}
109+
}
110+
let html = render(app);
111+
assert!(html.contains("async-empty"));
112+
assert!(html.contains("Nothing here"));
113+
}
114+
115+
#[test]
116+
fn retriable_error_shows_retry() {
117+
fn app() -> Element {
118+
rsx! {
119+
AsyncView {
120+
loading: false,
121+
empty: false,
122+
error: Some("boom".to_string()),
123+
retriable: true,
124+
}
125+
}
126+
}
127+
let html = render(app);
128+
assert!(html.contains("async-error"));
129+
assert!(html.contains("boom"));
130+
assert!(html.contains("Retry"));
131+
}
132+
133+
#[test]
134+
fn non_retriable_error_hides_retry() {
135+
fn app() -> Element {
136+
rsx! {
137+
AsyncView {
138+
loading: false,
139+
empty: false,
140+
error: Some("boom".to_string()),
141+
retriable: false,
142+
}
143+
}
144+
}
145+
let html = render(app);
146+
assert!(html.contains("async-error"));
147+
assert!(html.contains("boom"));
148+
assert!(!html.contains("Retry"));
149+
}
150+
151+
#[test]
152+
fn loaded_renders_nothing() {
153+
fn app() -> Element {
154+
rsx! { AsyncView { loading: false, empty: false, error: None } }
155+
}
156+
let html = render(app);
157+
assert!(!html.contains("async-loading"));
158+
assert!(!html.contains("async-empty"));
159+
assert!(!html.contains("async-error"));
160+
}
161+
}

0 commit comments

Comments
 (0)