From bd341f5571580cdf5e495379b49ca988fd9211c3 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 5 Jan 2022 17:30:12 -0500 Subject: [PATCH] fix: tests --- .github/workflows/windows.yml | 83 +++++------ examples/framework_benchmark.rs | 4 +- examples/inputs.rs | 2 +- examples/manual_edits.rs | 2 +- examples/pattern_model.rs | 6 +- examples/router.rs | 91 +++++------- packages/core-macro/src/rsx/component.rs | 24 ++- packages/core/src/events.rs | 8 +- packages/desktop/src/lib.rs | 1 - packages/router/src/components/link.rs | 2 +- packages/router/src/hooks/use_route.rs | 4 +- packages/ssr/Cargo.toml | 2 +- packages/ssr/README.md | 18 +-- packages/ssr/index.html | 2 +- packages/ssr/src/lib.rs | 180 ++--------------------- packages/ssr/tests/renders.rs | 146 ++++++++++++++++++ src/lib.rs | 30 ++-- 17 files changed, 305 insertions(+), 300 deletions(-) create mode 100644 packages/ssr/tests/renders.rs diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d7d2715d..6a5a1480 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -19,52 +19,53 @@ jobs: max-parallel: 2 fail-fast: false matrix: - target: [ - i686-pc-windows-gnu, - i686-pc-windows-msvc, - x86_64-pc-windows-gnu, - x86_64-pc-windows-msvc, - ] + target: + [ + i686-pc-windows-gnu, + i686-pc-windows-msvc, + x86_64-pc-windows-gnu, + x86_64-pc-windows-msvc, + ] cfg_release_channel: [nightly, stable] steps: - # The Windows runners have autocrlf enabled by default - # which causes failures for some of rustfmt's line-ending sensitive tests - - name: disable git eol translation - run: git config --global core.autocrlf false - - name: checkout - uses: actions/checkout@v2 + # The Windows runners have autocrlf enabled by default + # which causes failures for some of rustfmt's line-ending sensitive tests + - name: disable git eol translation + run: git config --global core.autocrlf false + - name: checkout + uses: actions/checkout@v2 - # Run build - - name: Install Rustup using win.rustup.rs - run: | - # Disable the download progress bar which can cause perf issues - $ProgressPreference = "SilentlyContinue" - Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe - .\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --default-toolchain=none - del rustup-init.exe - rustup target add ${{ matrix.target }} - shell: powershell + # Run build + - name: Install Rustup using win.rustup.rs + run: | + # Disable the download progress bar which can cause perf issues + $ProgressPreference = "SilentlyContinue" + Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe + .\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --default-toolchain=none + del rustup-init.exe + rustup target add ${{ matrix.target }} + shell: powershell - - name: Add mingw32 to path for i686-gnu - run: | - echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH - if: matrix.target == 'i686-pc-windows-gnu' && matrix.channel == 'nightly' - shell: bash + - name: Add mingw32 to path for i686-gnu + run: | + echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH + if: matrix.target == 'i686-pc-windows-gnu' && matrix.channel == 'nightly' + shell: bash - - name: Add mingw64 to path for x86_64-gnu - run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH - if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly' - shell: bash + - name: Add mingw64 to path for x86_64-gnu + run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH + if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly' + shell: bash - - name: build - run: | - rustc -Vv - cargo -V - set RUST_BACKTRACE=1 - cargo build - shell: cmd + - name: build + run: | + rustc -Vv + cargo -V + set RUST_BACKTRACE=1 + cargo build --features "desktop, ssr, router" + shell: cmd - - name: test - run: cargo test - shell: cmd + - name: test + run: cargo test + shell: cmd diff --git a/examples/framework_benchmark.rs b/examples/framework_benchmark.rs index f43ac420..2f4496d8 100644 --- a/examples/framework_benchmark.rs +++ b/examples/framework_benchmark.rs @@ -89,8 +89,8 @@ fn app(cx: Scope) -> Element { #[derive(Props)] struct ActionButtonProps<'a> { - name: &'static str, - id: &'static str, + name: &'a str, + id: &'a str, onclick: &'a dyn Fn(), } diff --git a/examples/inputs.rs b/examples/inputs.rs index ed11b48d..11334b59 100644 --- a/examples/inputs.rs +++ b/examples/inputs.rs @@ -133,7 +133,7 @@ fn app(cx: Scope) -> Element { r#type: "{field}", value: "{value}", // checked: "false", - oninput: move |evt: Arc| { + oninput: move |evt: FormEvent| { println!("{:?}", evt); }, } diff --git a/examples/manual_edits.rs b/examples/manual_edits.rs index c98590c8..c6486919 100644 --- a/examples/manual_edits.rs +++ b/examples/manual_edits.rs @@ -35,5 +35,5 @@ fn main() { let app: Component = |cx| cx.render(rsx!(div { "some app" })); - dioxus_desktop::launch_core(app, (), |c| c.with_edits(edits)); + dioxus_desktop::launch_with_props(app, (), |c| c.with_edits(edits)); } diff --git a/examples/pattern_model.rs b/examples/pattern_model.rs index fc707437..550879c2 100644 --- a/examples/pattern_model.rs +++ b/examples/pattern_model.rs @@ -116,8 +116,8 @@ fn app(cx: Scope) -> Element { #[derive(Props)] struct CalculatorKeyProps<'a> { - name: &'static str, - onclick: &'a dyn Fn(Arc), + name: &'a str, + onclick: &'a dyn Fn(MouseEvent), children: Element<'a>, } @@ -211,7 +211,7 @@ impl Calculator { self.cur_val = self.display_value.parse::().unwrap(); self.waiting_for_operand = true; } - fn handle_keydown(&mut self, evt: Arc) { + fn handle_keydown(&mut self, evt: KeyboardEvent) { match evt.key_code { KeyCode::Backspace => self.backspace(), KeyCode::Num0 => self.input_digit(0), diff --git a/examples/router.rs b/examples/router.rs index 4f4b7b2c..bd6d5188 100644 --- a/examples/router.rs +++ b/examples/router.rs @@ -1,64 +1,53 @@ +#![allow(non_snake_case)] + use dioxus::prelude::*; -use dioxus_router::{use_router, Link}; +use dioxus::router::{Link, Route, Router}; -#[derive(PartialEq, Debug, Clone)] -pub enum Route { - // #[at("/")] - Home, - - // #[at("/:id")] - AllUsers { page: u32 }, - - // #[at("/:id")] - User { id: u32 }, - - // #[at("/:id")] - BlogList { page: u32 }, - - // #[at("/:id")] - BlogPost { post_id: u32 }, - - // #[at("/404")] - // #[not_found] - NotFound, +fn main() { + dioxus::desktop::launch(app); } fn app(cx: Scope) -> Element { - let route = use_router(&cx, Route::parse); - cx.render(rsx! { - nav { - Link { to: Route::Home, "Go home!" } - Link { to: Route::AllUsers { page: 0 }, "List all users" } - Link { to: Route::BlogList { page: 0 }, "Blog posts" } + Router { + ul { + Link { to: "/", li { "Go home!" } } + Link { to: "users", li { "List all users" } } + Link { to: "blog", li { "Blog posts" } } + } + Route { to: "/", "Home" } + Route { to: "users", + Route { to: "/", "User list" } + Route { to: ":name", BlogPost {} } + } + Route { to: "blog" + Route { to: "/", "Blog list" } + Route { to: ":post", BlogPost {} } + } + Route { to: "", "Err 404 Route Not Found" } } - match route { - Route::Home => rsx!("Home"), - Route::AllUsers { page } => rsx!("All users - page {page}"), - Route::User { id } => rsx!("User - id: {id}"), - Route::BlogList { page } => rsx!("Blog posts - page {page}"), - Route::BlogPost { post_id } => rsx!("Blog post - post {post_id}"), - Route::NotFound => rsx!("Not found"), - } - footer {} }) } -impl Route { - // Generate the appropriate route from the "tail" end of the URL - fn parse(url: &str) -> Self { - use Route::*; - match url { - "/" => Home, - "/users" => AllUsers { page: 1 }, - "/users/:page" => AllUsers { page: 1 }, - "/users/:page/:id" => User { id: 1 }, - "/blog" => BlogList { page: 1 }, - "/blog/:page" => BlogList { page: 1 }, - "/blog/:page/:id" => BlogPost { post_id: 1 }, - _ => NotFound, +fn BlogPost(cx: Scope) -> Element { + let post = dioxus::router::use_route(&cx).last_segment()?; + + cx.render(rsx! { + div { + h1 { "Reading blog post: {post}" } + p { "example blog post" } } - } + }) } -fn main() {} +fn User(cx: Scope) -> Element { + let post = dioxus::router::use_route(&cx).last_segment()?; + let bold = dioxus::router::use_route(&cx).param::("bold"); + + cx.render(rsx! { + div { + h1 { "Reading blog post: {post}" } + p { "example blog post" } + } + }) +} diff --git a/packages/core-macro/src/rsx/component.rs b/packages/core-macro/src/rsx/component.rs index 211539bb..50b731e3 100644 --- a/packages/core-macro/src/rsx/component.rs +++ b/packages/core-macro/src/rsx/component.rs @@ -187,8 +187,12 @@ impl Parse for ComponentField { } if input.peek(LitStr) && input.peek2(Token![,]) { - let content = ContentField::Formatted(input.parse()?); - return Ok(Self { name, content }); + let t: LitStr = input.fork().parse()?; + + if is_literal_foramtted(&t) { + let content = ContentField::Formatted(input.parse()?); + return Ok(Self { name, content }); + } } if input.peek(LitStr) && input.peek2(LitStr) { @@ -209,3 +213,19 @@ impl ToTokens for ComponentField { }) } } + +fn is_literal_foramtted(lit: &LitStr) -> bool { + let s = lit.value(); + let mut chars = s.chars(); + + while let Some(next) = chars.next() { + if next == '{' { + let nen = chars.next(); + if nen == Some('{') { + return true; + } + } + } + + false +} diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index c7295c56..c0dad0a4 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -4,7 +4,7 @@ //! This is all kinda WIP, but the bones are there. use crate::{ElementId, ScopeId}; -use std::{any::Any, cell::Cell, rc::Rc, sync::Arc}; +use std::{any::Any, cell::Cell, fmt::Debug, rc::Rc, sync::Arc}; pub(crate) struct BubbleState { pub canceled: Cell, @@ -143,6 +143,12 @@ pub struct UiEvent { bubble_state: Rc, } +impl std::fmt::Debug for UiEvent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("UiEvent").field("data", &self.data).finish() + } +} + impl std::ops::Deref for UiEvent { type Target = T; diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index a78e4aec..b06dda6c 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -66,7 +66,6 @@ use tao::{ event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget}, keyboard::{KeyCode, ModifiersState}, - menu::{MenuBar, MenuItem}, window::{Window, WindowId}, }; pub use wry; diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index a08eb288..5a97c657 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -38,7 +38,7 @@ pub struct LinkProps<'a> { } pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { - let service = cx.consume_context::().unwrap(); + let service = cx.consume_context::()?; cx.render(rsx! { a { href: "{cx.props.to}", diff --git a/packages/router/src/hooks/use_route.rs b/packages/router/src/hooks/use_route.rs index 66b0b4f1..8307ed1f 100644 --- a/packages/router/src/hooks/use_route.rs +++ b/packages/router/src/hooks/use_route.rs @@ -15,7 +15,7 @@ impl<'a> UseRoute<'a> { todo!() } - pub fn last_segment(&self) -> Option<&str> { + pub fn last_segment(&self) -> Option<&'a str> { todo!() } @@ -25,6 +25,6 @@ impl<'a> UseRoute<'a> { } } -pub fn use_route(cx: &ScopeState) -> UseRoute { +pub fn use_route<'a>(cx: &'a ScopeState) -> UseRoute<'a> { todo!() } diff --git a/packages/ssr/Cargo.toml b/packages/ssr/Cargo.toml index 1aa0c77e..c9b4ba42 100644 --- a/packages/ssr/Cargo.toml +++ b/packages/ssr/Cargo.toml @@ -19,6 +19,7 @@ dioxus-core = { path = "../core", version = "^0.1.6", features = ["serialize"] } [dev-dependencies] dioxus-hooks = { path = "../hooks" } dioxus-html = { path = "../html" } +dioxus-core-macro = { path = "../core-macro" } thiserror = "1.0.23" log = "0.4.13" fern = { version = "0.6.0", features = ["colored"] } @@ -27,4 +28,3 @@ argh = "0.1.4" serde = "1.0.120" serde_json = "1.0.61" fs_extra = "1.2.0" -dioxus-core-macro = { path = "../core-macro" } diff --git a/packages/ssr/README.md b/packages/ssr/README.md index 2ae2afff..d6c199fc 100644 --- a/packages/ssr/README.md +++ b/packages/ssr/README.md @@ -17,7 +17,7 @@ This crate is a part of the broader Dioxus ecosystem. For more resources about D Dioxus SSR provides utilities to render Dioxus components to valid HTML. Once rendered, the HTML can be rehydrated client side or served from your web-server of choice. -```rust +```rust, ignore let app: Component = |cx| cx.render(rsx!(div {"hello world!"})); let mut vdom = VirtualDom::new(app); @@ -32,7 +32,7 @@ assert_eq!(text, "
hello world!
") The simplest example is to simply render some `rsx!` nodes to html. This can be done with the [`render_lazy`] api. -```rust +```rust, ignore let content = dioxus::ssr::render(rsx!{ div { (0..5).map(|i| rsx!( @@ -44,7 +44,7 @@ let content = dioxus::ssr::render(rsx!{ ## Rendering a VirtualDom -```rust +```rust, ignore let mut dom = VirtualDom::new(app); let _ = dom.rebuild(); @@ -54,7 +54,7 @@ let content = dioxus::ssr::render_vdom(&dom); ## Configuring output It's possible to configure the output of the generated HTML. -```rust +```rust, ignore let content = dioxus::ssr::render_vdom(&dom, |config| config.pretty(true).prerender(true)); ``` @@ -62,7 +62,7 @@ let content = dioxus::ssr::render_vdom(&dom, |config| config.pretty(true).preren We provide the basic `SsrFormatter` object that implements `Display`, so you can integrate SSR into an existing string, or write directly to a file. -```rust +```rust, ignore use std::fmt::{Error, Write}; let mut buf = String::new(); @@ -92,7 +92,7 @@ With pre-rendering enabled, this crate will generate element nodes with Element To enable pre-rendering, simply configure the `SsrConfig` with pre-rendering enabled. -```rust +```rust, ignore let dom = VirtualDom::new(App); let text = dioxus::ssr::render_vdom(App, |cfg| cfg.pre_render(true)); @@ -102,7 +102,7 @@ let text = dioxus::ssr::render_vdom(App, |cfg| cfg.pre_render(true)); Dioxus SSR can also be to render on the server. Obviously, you can just render the VirtualDOM to a string and send that down. -```rust +```rust, ignore let text = dioxus::ssr::render_vdom(&vdom); assert_eq!(text, "
hello world!
") ``` @@ -113,7 +113,7 @@ The rest of the space - IE doing this more efficiently, caching the virtualdom, Dioxus SSR needs an arena to allocate from - whether it be the VirtualDom or a dedicated Bump allocator. To render `rsx!` directly to a string, you'll want to create an `SsrRenderer` and call `render_lazy`. -```rust +```rust, ignore let text = dioxus::ssr::SsrRenderer::new().render_lazy(rsx!{ div { "hello world" } }); @@ -122,7 +122,7 @@ assert_eq!(text, "
hello world!
") This can be automated with the `render_lazy!` macro: -```rust +```rust, ignore let text = render_lazy!(rsx!( div { "hello world" } )); ``` diff --git a/packages/ssr/index.html b/packages/ssr/index.html index 10500012..22129a89 100644 --- a/packages/ssr/index.html +++ b/packages/ssr/index.html @@ -1 +1 @@ -asd \ No newline at end of file +

Hello world!: 0

Hello world!: 1

Hello world!: 2

Hello world!: 3

Hello world!: 4

Hello world!: 5

Hello world!: 6

Hello world!: 7

Hello world!: 8

Hello world!: 9

Hello world!: 10

Hello world!: 11

Hello world!: 12

Hello world!: 13

Hello world!: 14

Hello world!: 15

Hello world!: 16

Hello world!: 17

Hello world!: 18

Hello world!: 19

\ No newline at end of file diff --git a/packages/ssr/src/lib.rs b/packages/ssr/src/lib.rs index 2ac4473b..1fefa939 100644 --- a/packages/ssr/src/lib.rs +++ b/packages/ssr/src/lib.rs @@ -2,13 +2,15 @@ use std::fmt::{Display, Formatter}; -use dioxus_core::exports::bumpalo; -use dioxus_core::exports::bumpalo::Bump; use dioxus_core::IntoVNode; use dioxus_core::*; +fn app(_cx: Scope) -> Element { + None +} + pub struct SsrRenderer { - inner: bumpalo::Bump, + vdom: VirtualDom, cfg: SsrConfig, } @@ -16,21 +18,14 @@ impl SsrRenderer { pub fn new(cfg: impl FnOnce(SsrConfig) -> SsrConfig) -> Self { Self { cfg: cfg(SsrConfig::default()), - inner: bumpalo::Bump::new(), + vdom: VirtualDom::new(app), } } pub fn render_lazy<'a>(&'a mut self, f: LazyNodes<'a, '_>) -> String { - let bump = &mut self.inner as *mut _; - let s = self.render_inner(f); + let scope = self.vdom.base_scope(); + let factory = NodeFactory::new(&scope); - // reuse the bump's memory - unsafe { (&mut *bump as &mut bumpalo::Bump).reset() }; - s - } - - fn render_inner<'a>(&'a self, f: LazyNodes<'a, '_>) -> String { - let factory = NodeFactory::new(&self.inner); let root = f.into_vnode(factory); format!( "{:}", @@ -44,8 +39,8 @@ impl SsrRenderer { } pub fn render_lazy<'a>(f: LazyNodes<'a, '_>) -> String { - let bump = bumpalo::Bump::new(); - let borrowed = ≎ + let vdom = VirtualDom::new(app); + let scope: *const ScopeState = vdom.base_scope(); // Safety // @@ -57,9 +52,9 @@ pub fn render_lazy<'a>(f: LazyNodes<'a, '_>) -> String { // // Therefore, we cast our local bump alloactor into right lifetime. This is okay because our usage of the bump arena // is *definitely* shorter than the <'a> lifetime, and we return *owned* data - not borrowed data. + let scope = unsafe { &*scope }; - let _b = unsafe { std::mem::transmute::<&Bump, &'a Bump>(borrowed) }; - let root = f.into_vnode(NodeFactory::new(_b)); + let root = f.into_vnode(NodeFactory::new(&scope)); format!( "{:}", @@ -282,154 +277,3 @@ impl SsrConfig { self } } - -#[cfg(test)] -mod tests { - use super::*; - - use dioxus_core::prelude::*; - use dioxus_core_macro::*; - use dioxus_html as dioxus_elements; - - static SIMPLE_APP: Component = |cx| { - cx.render(rsx!(div { - "hello world!" - })) - }; - - static SLIGHTLY_MORE_COMPLEX: Component = |cx| { - cx.render(rsx! { - div { title: "About W3Schools", - (0..20).map(|f| rsx!{ - div { - title: "About W3Schools", - style: "color:blue;text-align:center", - class: "About W3Schools", - p { - title: "About W3Schools", - "Hello world!: {f}" - } - } - }) - } - }) - }; - - static NESTED_APP: Component = |cx| { - cx.render(rsx!( - div { - SIMPLE_APP {} - } - )) - }; - static FRAGMENT_APP: Component = |cx| { - cx.render(rsx!( - div { "f1" } - div { "f2" } - div { "f3" } - div { "f4" } - )) - }; - - #[test] - fn to_string_works() { - let mut dom = VirtualDom::new(SIMPLE_APP); - dom.rebuild(); - dbg!(render_vdom(&dom)); - } - - #[test] - fn hydration() { - let mut dom = VirtualDom::new(NESTED_APP); - dom.rebuild(); - dbg!(render_vdom_cfg(&dom, |c| c.pre_render(true))); - } - - #[test] - fn nested() { - let mut dom = VirtualDom::new(NESTED_APP); - dom.rebuild(); - dbg!(render_vdom(&dom)); - } - - #[test] - fn fragment_app() { - let mut dom = VirtualDom::new(FRAGMENT_APP); - dom.rebuild(); - dbg!(render_vdom(&dom)); - } - - #[test] - fn write_to_file() { - use std::fs::File; - use std::io::Write; - - let mut file = File::create("index.html").unwrap(); - - let mut dom = VirtualDom::new(SLIGHTLY_MORE_COMPLEX); - dom.rebuild(); - - file.write_fmt(format_args!( - "{}", - TextRenderer::from_vdom(&dom, SsrConfig::default()) - )) - .unwrap(); - } - - #[test] - fn styles() { - static STLYE_APP: Component = |cx| { - cx.render(rsx! { - div { color: "blue", font_size: "46px" } - }) - }; - - let mut dom = VirtualDom::new(STLYE_APP); - dom.rebuild(); - dbg!(render_vdom(&dom)); - } - - #[test] - fn lazy() { - let p1 = SsrRenderer::new(|c| c).render_lazy(rsx! { - div { "ello" } - }); - - let p2 = render_lazy(rsx! { - div { - "ello" - } - }); - assert_eq!(p1, p2); - } - - #[test] - fn big_lazy() { - let s = render_lazy(rsx! { - div { - div { - div { - h1 { "ello world" } - h1 { "ello world" } - h1 { "ello world" } - h1 { "ello world" } - h1 { "ello world" } - } - } - } - }); - - dbg!(s); - } - - #[test] - fn inner_html() { - let s = render_lazy(rsx! { - div { - dangerous_inner_html: "
ack
" - } - }); - - dbg!(s); - } -} diff --git a/packages/ssr/tests/renders.rs b/packages/ssr/tests/renders.rs new file mode 100644 index 00000000..b948a560 --- /dev/null +++ b/packages/ssr/tests/renders.rs @@ -0,0 +1,146 @@ +use dioxus_core::prelude::*; +use dioxus_core_macro::*; +use dioxus_html as dioxus_elements; +use dioxus_ssr::{render_lazy, render_vdom, render_vdom_cfg, SsrConfig, SsrRenderer, TextRenderer}; + +static SIMPLE_APP: Component = |cx| { + cx.render(rsx!(div { + "hello world!" + })) +}; + +static SLIGHTLY_MORE_COMPLEX: Component = |cx| { + cx.render(rsx! { + div { title: "About W3Schools", + (0..20).map(|f| rsx!{ + div { + title: "About W3Schools", + style: "color:blue;text-align:center", + class: "About W3Schools", + p { + title: "About W3Schools", + "Hello world!: {f}" + } + } + }) + } + }) +}; + +static NESTED_APP: Component = |cx| { + cx.render(rsx!( + div { + SIMPLE_APP {} + } + )) +}; +static FRAGMENT_APP: Component = |cx| { + cx.render(rsx!( + div { "f1" } + div { "f2" } + div { "f3" } + div { "f4" } + )) +}; + +#[test] +fn to_string_works() { + let mut dom = VirtualDom::new(SIMPLE_APP); + dom.rebuild(); + dbg!(render_vdom(&dom)); +} + +#[test] +fn hydration() { + let mut dom = VirtualDom::new(NESTED_APP); + dom.rebuild(); + dbg!(render_vdom_cfg(&dom, |c| c.pre_render(true))); +} + +#[test] +fn nested() { + let mut dom = VirtualDom::new(NESTED_APP); + dom.rebuild(); + dbg!(render_vdom(&dom)); +} + +#[test] +fn fragment_app() { + let mut dom = VirtualDom::new(FRAGMENT_APP); + dom.rebuild(); + dbg!(render_vdom(&dom)); +} + +#[test] +fn write_to_file() { + use std::fs::File; + use std::io::Write; + + let mut file = File::create("index.html").unwrap(); + + let mut dom = VirtualDom::new(SLIGHTLY_MORE_COMPLEX); + dom.rebuild(); + + file.write_fmt(format_args!( + "{}", + TextRenderer::from_vdom(&dom, SsrConfig::default()) + )) + .unwrap(); +} + +#[test] +fn styles() { + static STLYE_APP: Component = |cx| { + cx.render(rsx! { + div { color: "blue", font_size: "46px" } + }) + }; + + let mut dom = VirtualDom::new(STLYE_APP); + dom.rebuild(); + dbg!(render_vdom(&dom)); +} + +#[test] +fn lazy() { + let p1 = SsrRenderer::new(|c| c).render_lazy(rsx! { + div { "ello" } + }); + + let p2 = render_lazy(rsx! { + div { + "ello" + } + }); + assert_eq!(p1, p2); +} + +#[test] +fn big_lazy() { + let s = render_lazy(rsx! { + div { + div { + div { + h1 { "ello world" } + h1 { "ello world" } + h1 { "ello world" } + h1 { "ello world" } + h1 { "ello world" } + } + } + } + }); + + dbg!(s); +} + +#[test] +fn inner_html() { + let s = render_lazy(rsx! { + div { + dangerous_inner_html: "
ack
" + } + }); + + dbg!(s); +} diff --git a/src/lib.rs b/src/lib.rs index ce523941..c0a984ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,7 +39,7 @@ //! //! To launch an app, we use the `launch` method for the specific renderer we want to use. In the launch function, we pass the app's `Component`. //! -//! ```rust +//! ```rust, ignore //! use dioxus::prelude::*; //! //! fn main() { @@ -62,7 +62,7 @@ //! consistency, we force all attributes and listeners to be listed *before* //! children. //! -//! ```rust +//! ```rust, ignore //! let value = "123"; //! //! rsx!( @@ -78,7 +78,7 @@ //! of the body as child elements and rust expressions. Any rust expression that //! implements `IntoIterator` will be parsed as a child. //! -//! ```rust +//! ```rust, ignore //! rsx!( //! div { //! (0..10).map(|_| rsx!(span { "hello world" })) @@ -94,7 +94,7 @@ //! `cx` as the first argument of rsx. This is sometimes useful when we need to //! render nodes in match statements. //! -//! ```rust +//! ```rust, ignore //! fn example(cx: Scope) -> Element { //! //! // both of these are equivalent @@ -107,7 +107,7 @@ //! Putting everything together, we can write a simple component that a list of //! elements: //! -//! ```rust +//! ```rust, ignore //! fn app(cx: Scope) -> Element { //! let name = "dave"; //! cx.render(rsx!( @@ -135,7 +135,7 @@ //! //! In Dioxus, all properties are memoized by default! //! -//! ```rust +//! ```rust, ignore //! fn App(cx: Scope) -> Element { //! cx.render(rsx!( //! Header { @@ -149,7 +149,7 @@ //! Our `Header` component takes in a `title` and a `color` property, which we //! delcare on an explicit `HeaderProps` struct. //! -//! ``` +//! ```rust, ignore //! // The `Props` derive macro lets us add additional functionality to how props are interpreted. //! #[derive(Props, PartialEq)] //! struct HeaderProps { @@ -170,7 +170,7 @@ //! Components may use the `inline_props` macro to completely inline the props //! definition into the function arguments. //! -//! ```rust +//! ```rust, ignore //! #[inline_props] //! fn Header(cx: Scope, title: String, color: String) -> Element { //! cx.render(rsx!( @@ -186,7 +186,7 @@ //! attach some lifetimes to the props struct. //! > Note: we don't need to derive `PartialEq` for borrowed props since they cannot be memoized. //! -//! ```rust +//! ```rust, ignore //! #[derive(Props)] //! struct HeaderProps<'a> { //! title: &'a str, @@ -206,7 +206,7 @@ //! Components that beging with an uppercase letter may be called through //! traditional curly-brace syntax like so: //! -//! ```rust +//! ```rust, ignore //! rsx!( //! Header { title: "My App" } //! ) @@ -215,7 +215,7 @@ //! Alternatively, if your components begin with a lowercase letter, you can use //! the function call syntax: //! -//! ```rust +//! ```rust, ignore //! rsx!( //! header( title: "My App" ) //! ) @@ -230,7 +230,7 @@ //! By convention, all hooks are functions that should start with `use_`. We can //! use hooks to define state and modify it from within listeners. //! -//! ```rust +//! ```rust, ignore //! fn app(cx: Scope) -> Element { //! let name = use_state(&cx, || "world"); //! @@ -250,7 +250,7 @@ //! //! Most hooks you'll write are simply composition of other hooks: //! -//! ```rust +//! ```rust, ignore //! fn use_username(cx: &ScopeState, id: Uuid) -> bool { //! let users = use_context::(cx); //! users.get(&id).map(|user| user.logged_in).ok_or(false) @@ -259,7 +259,7 @@ //! //! To create entirely new foundational hooks, we can use the `use_hook` method on ScopeState. //! -//! ```rust +//! ```rust, ignore //! fn use_mut_string(cx: &ScopeState) -> &mut String { //! cx.use_hook(|_| "Hello".to_string()) //! } @@ -271,7 +271,7 @@ //! //! Using components, templates, and hooks, we can build a simple app. //! -//! ```rust +//! ```rust, ignore //! use dioxus::prelude::*; //! //! fn main() {