update tests
This commit is contained in:
1 parent
58b74c1155
commit
35befa1784
12 files changed
+334
-236
No files matched your search
@@ -132,7 +132,7 @@ enum Route {
|
||||
// UserFrame is a layout component that will receive the `user_id: String` parameter
|
||||
#[layout(UserFrame)]
|
||||
// Route1 is a non-layout component that will receive the `user_id: String` and `dynamic: String` parameters
|
||||
#[route("/:dynamic?:query", Route1)]
|
||||
#[route("/:dynamic?:query")]
|
||||
Route1 {
|
||||
// The type is taken from the first instance of the dynamic parameter
|
||||
user_id: usize,
|
||||
@@ -141,13 +141,13 @@ enum Route {
|
||||
extra: String,
|
||||
},
|
||||
// Route2 is a non-layout component that will receive the `user_id: String` parameter
|
||||
#[route("/hello_world", Route2)]
|
||||
#[route("/hello_world")]
|
||||
// You can opt out of the layout by using the `!` prefix
|
||||
#[layout(!UserFrame)]
|
||||
Route2 { user_id: usize },
|
||||
#[end_layout]
|
||||
#[end_nest]
|
||||
#[redirect("/:id/user", |id: usize| Route::Route3 { dynamic: id.to_string()})]
|
||||
#[route("/:dynamic", Route3)]
|
||||
#[route("/:dynamic")]
|
||||
Route3 { dynamic: String },
|
||||
}
|
||||
@@ -152,18 +152,10 @@ pub fn GenericLink<'a, R: Routable + Clone>(cx: Scope<'a, GenericLinkProps<'a, R
|
||||
};
|
||||
|
||||
let current_route = router.current();
|
||||
let href = current_route.to_string();
|
||||
let current_url = current_route.to_string();
|
||||
let href = target.to_string();
|
||||
let ac = active_class
|
||||
.and_then(|active_class| match target {
|
||||
NavigationTarget::Internal(target) => {
|
||||
if href == target.to_string() {
|
||||
Some(format!(" {active_class}"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.and_then(|active_class| (href == current_url).then(|| format!(" {active_class}")))
|
||||
.unwrap_or_default();
|
||||
|
||||
let id = id.unwrap_or_default();
|
||||
|
||||
@@ -38,8 +38,6 @@ pub struct GenericRouterProps<R: Routable>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
#[props(into)]
|
||||
initial_url: Option<String>,
|
||||
#[props(default, into)]
|
||||
config: RouterCfg<R>,
|
||||
}
|
||||
@@ -71,13 +69,6 @@ where
|
||||
cx.props.config.config.take().unwrap_or_default(),
|
||||
cx.schedule_update_any(),
|
||||
);
|
||||
if let Some(initial) = cx.props.initial_url.as_ref() {
|
||||
router.replace(
|
||||
initial
|
||||
.parse()
|
||||
.unwrap_or_else(|_| panic!("failed to parse initial url")),
|
||||
);
|
||||
}
|
||||
router
|
||||
});
|
||||
|
||||
|
||||
@@ -51,6 +51,17 @@ pub mod prelude {
|
||||
pub use crate::routable::*;
|
||||
pub use crate::router_cfg::RouterConfiguration;
|
||||
pub use dioxus_router_macro::Routable;
|
||||
|
||||
#[doc(hidden)]
|
||||
/// A component with props used in the macro
|
||||
pub trait HasProps {
|
||||
/// The props type of the component.
|
||||
type Props;
|
||||
}
|
||||
|
||||
impl<P> HasProps for dioxus::prelude::Component<P> {
|
||||
type Props = P;
|
||||
}
|
||||
}
|
||||
|
||||
mod utils {
|
||||
|
||||
@@ -29,6 +29,22 @@ pub enum NavigationTarget<R: Routable> {
|
||||
External(String),
|
||||
}
|
||||
|
||||
impl<R: Routable> From<&str> for NavigationTarget<R>
|
||||
where
|
||||
<R as FromStr>::Err: Display,
|
||||
{
|
||||
fn from(value: &str) -> Self {
|
||||
Self::from_str(value).unwrap_or_else(|err| match err {
|
||||
NavigationTargetParseError::InvalidUrl(e) => {
|
||||
panic!("Failed to parse `{}` as a URL: {}", value, e)
|
||||
}
|
||||
NavigationTargetParseError::InvalidInternalURL(e) => {
|
||||
panic!("Failed to parse `{}` as a `Routable`: {}", value, e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Routable> From<R> for NavigationTarget<R> {
|
||||
fn from(value: R) -> Self {
|
||||
Self::Internal(value)
|
||||
|
||||
@@ -1,47 +1,69 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::prelude::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn prepare(link: Component) -> String {
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
let mut vdom = VirtualDom::new_with_props(App, AppProps { link });
|
||||
fn prepare<R: Routable>() -> String
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
let mut vdom = VirtualDom::new_with_props(
|
||||
App,
|
||||
AppProps::<R> {
|
||||
phantom: std::marker::PhantomData,
|
||||
},
|
||||
);
|
||||
let _ = vdom.rebuild();
|
||||
return dioxus_ssr::render(&vdom);
|
||||
|
||||
#[derive(Props)]
|
||||
struct AppProps {
|
||||
link: Component,
|
||||
struct AppProps<R: Routable> {
|
||||
phantom: std::marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
impl PartialEq for AppProps {
|
||||
impl<R: Routable> PartialEq for AppProps<R> {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn App(cx: Scope<AppProps>) -> Element {
|
||||
use_router(
|
||||
cx,
|
||||
&|| RouterConfiguration {
|
||||
synchronous: true,
|
||||
..Default::default()
|
||||
},
|
||||
&|| Segment::content(comp(cx.props.link)),
|
||||
);
|
||||
|
||||
fn App<R: Routable>(cx: Scope<AppProps<R>>) -> Element
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
render! {
|
||||
h1 { "App" }
|
||||
Outlet { }
|
||||
GenericRouter::<R> {
|
||||
config: RouterConfiguration {
|
||||
history: Box::<MemoryHistory::<R>>::default(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn href_internal() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
#[route("/test")]
|
||||
Test {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Test(cx: Scope) -> Element {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "/test",
|
||||
target: Route::Test {},
|
||||
"Link"
|
||||
}
|
||||
}
|
||||
@@ -57,36 +79,26 @@ fn href_internal() {
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn href_named() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: named::<RootIndex>(),
|
||||
"Link"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let expected = format!(
|
||||
"<h1>App</h1><a {href} {default} {class} {id} {rel} {target}>Link</a>",
|
||||
href = r#"href="/""#,
|
||||
default = r#"dioxus-prevent-default="onclick""#,
|
||||
class = r#"class="""#,
|
||||
id = r#"id="""#,
|
||||
rel = r#"rel="""#,
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn href_external() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
#[route("/test")]
|
||||
Test {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Test(cx: Scope) -> Element {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "https://dioxuslabs.com/",
|
||||
@@ -105,15 +117,29 @@ fn href_external() {
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_class() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
#[route("/test")]
|
||||
Test {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Test(cx: Scope) -> Element {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "/test",
|
||||
target: Route::Test {},
|
||||
class: "test_class",
|
||||
"Link"
|
||||
}
|
||||
@@ -130,12 +156,19 @@ fn with_class() {
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_active_class_active() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "/",
|
||||
@@ -156,15 +189,29 @@ fn with_active_class_active() {
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_active_class_inactive() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
#[route("/test")]
|
||||
Test {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Test(cx: Scope) -> Element {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "/test",
|
||||
target: Route::Test {},
|
||||
active_class: "active_class",
|
||||
class: "test_class",
|
||||
"Link"
|
||||
@@ -182,15 +229,29 @@ fn with_active_class_inactive() {
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_id() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
#[route("/test")]
|
||||
Test {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Test(cx: Scope) -> Element {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "/test",
|
||||
target: Route::Test {},
|
||||
id: "test_id",
|
||||
"Link"
|
||||
}
|
||||
@@ -207,15 +268,29 @@ fn with_id() {
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_new_tab() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
#[route("/test")]
|
||||
Test {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Test(cx: Scope) -> Element {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "/test",
|
||||
target: Route::Test {},
|
||||
new_tab: true,
|
||||
"Link"
|
||||
}
|
||||
@@ -232,12 +307,19 @@ fn with_new_tab() {
|
||||
target = r#"target="_blank""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_new_tab_external() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "https://dioxuslabs.com/",
|
||||
@@ -257,15 +339,29 @@ fn with_new_tab_external() {
|
||||
target = r#"target="_blank""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_rel() {
|
||||
fn content(cx: Scope) -> Element {
|
||||
#[derive(Routable, Clone)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Root {},
|
||||
#[route("/test")]
|
||||
Test {},
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Test(cx: Scope) -> Element {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Link {
|
||||
target: "/test",
|
||||
target: Route::Test {},
|
||||
rel: "test_rel",
|
||||
"Link"
|
||||
}
|
||||
@@ -282,5 +378,5 @@ fn with_rel() {
|
||||
target = r#"target="""#
|
||||
);
|
||||
|
||||
assert_eq!(prepare(content), expected);
|
||||
assert_eq!(prepare::<Route>(), expected);
|
||||
}
|
||||
@@ -1,52 +1,61 @@
|
||||
#![allow(non_snake_case, unused)]
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::{history::MemoryHistory, prelude::*};
|
||||
|
||||
fn prepare(path: impl Into<String>) -> VirtualDom {
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
let mut vdom = VirtualDom::new_with_props(App, AppProps { path: path.into() });
|
||||
let _ = vdom.rebuild();
|
||||
return vdom;
|
||||
|
||||
#[derive(Routable, Clone)]
|
||||
#[rustfmt::skip]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
RootIndex {},
|
||||
#[nest("/fixed")]
|
||||
#[layout(Fixed)]
|
||||
#[route("/")]
|
||||
FixedIndex {},
|
||||
#[route("/fixed")]
|
||||
FixedFixed {},
|
||||
#[end_layout]
|
||||
#[end_nest]
|
||||
#[nest("/:id")]
|
||||
#[layout(Parameter)]
|
||||
#[route("/")]
|
||||
ParameterIndex { id: u8 },
|
||||
#[route("/fixed")]
|
||||
ParameterFixed { id: u8 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Props, PartialEq)]
|
||||
struct AppProps {
|
||||
path: String,
|
||||
}
|
||||
|
||||
fn App(cx: Scope<AppProps>) -> Element {
|
||||
use_router(
|
||||
cx,
|
||||
&|| RouterConfiguration {
|
||||
synchronous: true,
|
||||
history: Box::new(MemoryHistory::with_initial_path(cx.props.path.clone()).unwrap()),
|
||||
..Default::default()
|
||||
},
|
||||
&|| {
|
||||
Segment::content(comp(RootIndex))
|
||||
.fixed(
|
||||
"fixed",
|
||||
Route::content(comp(Fixed)).nested(
|
||||
Segment::content(comp(FixedIndex)).fixed("fixed", comp(FixedFixed)),
|
||||
),
|
||||
)
|
||||
.catch_all(ParameterRoute::content::<u8>(comp(Parameter)).nested(
|
||||
Segment::content(comp(ParameterIndex)).fixed("fixed", comp(ParameterFixed)),
|
||||
))
|
||||
},
|
||||
);
|
||||
let cfg = RouterConfiguration {
|
||||
history: Box::new(MemoryHistory::with_initial_path(cx.props.path.clone()).unwrap()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
render! {
|
||||
h1 { "App" }
|
||||
Outlet { }
|
||||
Router {
|
||||
config: cfg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn RootIndex(cx: Scope) -> Element {
|
||||
render! {
|
||||
h2 { "Root Index" }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Fixed(cx: Scope) -> Element {
|
||||
render! {
|
||||
h2 { "Fixed" }
|
||||
@@ -54,34 +63,37 @@ fn prepare(path: impl Into<String>) -> VirtualDom {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn FixedIndex(cx: Scope) -> Element {
|
||||
render! {
|
||||
h3 { "Fixed - Index" }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn FixedFixed(cx: Scope) -> Element {
|
||||
render! {
|
||||
h3 { "Fixed - Fixed"}
|
||||
}
|
||||
}
|
||||
|
||||
fn Parameter(cx: Scope) -> Element {
|
||||
let val = use_route(cx)?.parameter::<u8>().unwrap();
|
||||
|
||||
#[inline_props]
|
||||
fn Parameter(cx: Scope, id: u8) -> Element {
|
||||
render! {
|
||||
h2 { "Parameter {val}" }
|
||||
h2 { "Parameter {id}" }
|
||||
Outlet { }
|
||||
}
|
||||
}
|
||||
|
||||
fn ParameterIndex(cx: Scope) -> Element {
|
||||
#[inline_props]
|
||||
fn ParameterIndex(cx: Scope, id: u8) -> Element {
|
||||
render! {
|
||||
h3 { "Parameter - Index" }
|
||||
}
|
||||
}
|
||||
|
||||
fn ParameterFixed(cx: Scope) -> Element {
|
||||
#[inline_props]
|
||||
fn ParameterFixed(cx: Scope, id: u8) -> Element {
|
||||
render! {
|
||||
h3 { "Parameter - Fixed" }
|
||||
}
|
||||
|
||||
@@ -6,10 +6,58 @@ use std::sync::Arc;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::prelude::*;
|
||||
use gloo::utils::document;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Routable)]
|
||||
enum Route {
|
||||
#[route("/")]
|
||||
Home {},
|
||||
#[nest("/blog")]
|
||||
#[route("/")]
|
||||
BlogList {},
|
||||
#[route("/:id")]
|
||||
BlogPost { id: usize },
|
||||
}
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
render!(Router {
|
||||
config: RouterConfiguration {
|
||||
history: Box::<WebHistory<Route>>::default(),
|
||||
..Default::default()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn Home(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "Home" }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn BlogList(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline_props]
|
||||
fn BlogPost(cx: Scope, id: usize) -> Element {
|
||||
cx.render(rsx! {
|
||||
div { }
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn simple_test() {
|
||||
fn main() {
|
||||
@@ -18,51 +66,6 @@ fn simple_test() {
|
||||
dioxus_web::launch(App);
|
||||
}
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
use_router(
|
||||
cx,
|
||||
&|| RouterConfiguration {
|
||||
on_update: Some(Arc::new(|_| None)),
|
||||
..Default::default()
|
||||
},
|
||||
&|| {
|
||||
Segment::content(comp(Home)).fixed(
|
||||
"blog",
|
||||
Route::empty().nested(
|
||||
Segment::content(comp(BlogList)).catch_all((comp(BlogPost), PostId {})),
|
||||
),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
render!(Outlet {})
|
||||
}
|
||||
|
||||
fn Home(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "Home" }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn BlogList(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
struct PostId;
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let _id = use_route(cx)?.parameter::<PostId>().unwrap();
|
||||
|
||||
cx.render(rsx! {
|
||||
div { }
|
||||
})
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
let _ = document();
|
||||
|
||||
Reference in new issue
Block a user