lib.rs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // This test is used by playwright configured in the root of the repo
  2. // Tests:
  3. // - SEO without JS
  4. // - Streaming hydration
  5. // - Suspense
  6. // - Server functions
  7. //
  8. // Without Javascript, content may not load into the right location, but it should still be somewhere in the html even if it is invisible
  9. use dioxus::prelude::*;
  10. use serde::{Deserialize, Serialize};
  11. pub fn app() -> Element {
  12. // Start streaming immediately
  13. use_hook(commit_initial_chunk);
  14. rsx! {
  15. SuspenseBoundary {
  16. fallback: move |_| rsx! {},
  17. document::Style {
  18. href: asset!("/assets/style.css")
  19. }
  20. LoadTitle {}
  21. }
  22. MessageWithLoader { id: 0 }
  23. }
  24. }
  25. #[component]
  26. fn MessageWithLoader(id: usize) -> Element {
  27. rsx! {
  28. SuspenseBoundary {
  29. fallback: move |_| rsx! {
  30. "Loading {id}..."
  31. },
  32. Message { id }
  33. }
  34. }
  35. }
  36. #[component]
  37. fn LoadTitle() -> Element {
  38. let title = use_server_future(move || server_content(0))?()
  39. .unwrap()
  40. .unwrap();
  41. rsx! {
  42. "title loaded"
  43. document::Title { "{title.title}" }
  44. }
  45. }
  46. #[component]
  47. fn Message(id: usize) -> Element {
  48. let message = use_server_future(move || server_content(id))?()
  49. .unwrap()
  50. .unwrap();
  51. rsx! {
  52. h2 {
  53. id: "title-{id}",
  54. "{message.title}"
  55. }
  56. p {
  57. id: "body-{id}",
  58. "{message.body}"
  59. }
  60. div {
  61. id: "children-{id}",
  62. padding: "10px",
  63. for child in message.children {
  64. MessageWithLoader { id: child }
  65. }
  66. }
  67. }
  68. }
  69. #[derive(Clone, Serialize, Deserialize)]
  70. pub struct Content {
  71. title: String,
  72. body: String,
  73. children: Vec<usize>,
  74. }
  75. #[server]
  76. async fn server_content(id: usize) -> ServerFnResult<Content> {
  77. let content_tree = [
  78. Content {
  79. title: "The robot says hello world".to_string(),
  80. body: "The robot becomes sentient and says hello world".to_string(),
  81. children: vec![1, 2, 3],
  82. },
  83. Content {
  84. title: "The world says hello back".to_string(),
  85. body: "In a stunning turn of events, the world collectively unites and says hello back"
  86. .to_string(),
  87. children: vec![4],
  88. },
  89. Content {
  90. title: "Goodbye Robot".to_string(),
  91. body: "The robot says goodbye".to_string(),
  92. children: vec![],
  93. },
  94. Content {
  95. title: "Goodbye World".to_string(),
  96. body: "The world says goodbye".to_string(),
  97. children: vec![],
  98. },
  99. Content {
  100. title: "Hello World".to_string(),
  101. body: "The world says hello again".to_string(),
  102. children: vec![],
  103. },
  104. ];
  105. tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
  106. Ok(content_tree[id].clone())
  107. }