Explorar el Código

add rendering tests

Evan Almloff hace 2 años
padre
commit
1b199977d1

+ 10 - 3
packages/desktop/Cargo.toml

@@ -59,8 +59,15 @@ dioxus-core-macro = { path = "../core-macro" }
 dioxus-hooks = { path = "../hooks" }
 dioxus = { path = "../dioxus" }
 exitcode = "1.1.2"
+scraper = "0.16.0"
 
+# These tests need to be run on the main thread, so they cannot use rust's test harness.
 [[test]]
-name = "headless_tests"
-path = "headless_tests/main.rs"
-harness = false
+name = "check_events"
+path = "headless_tests/events.rs"
+harness = false
+
+[[test]]
+name = "check_rendering"
+path = "headless_tests/rendering.rs"
+harness = false

+ 19 - 2
packages/desktop/headless_tests/events.rs

@@ -1,9 +1,25 @@
-use crate::check_app_exits;
+
 use dioxus::prelude::*;
 use dioxus_desktop::DesktopContext;
 use dioxus::html::geometry::euclid::Vector3D;
 
-pub fn test_events() {
+pub(crate) fn check_app_exits(app: Component) {
+    // This is a deadman's switch to ensure that the app exits
+    let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
+    let should_panic_clone = should_panic.clone();
+    std::thread::spawn(move || {
+        std::thread::sleep(std::time::Duration::from_secs(100));
+        if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) {
+            std::process::exit(exitcode::SOFTWARE);
+        }
+    });
+
+    dioxus_desktop::launch(app);
+
+    should_panic.store(false, std::sync::atomic::Ordering::SeqCst);
+}
+
+pub fn main() {
     check_app_exits(app);
 }
 
@@ -194,6 +210,7 @@ fn app(cx: Scope) -> Element {
     
 
     if **recieved_events == 12 {
+        println!("all events recieved");
         desktop_context.close();
     }
 

+ 0 - 28
packages/desktop/headless_tests/main.rs

@@ -1,28 +0,0 @@
-// Check that all events are being forwarded to the mock.
-//! This example roughly shows how events are serialized into Rust from JavaScript.
-//!
-//! There is some conversion happening when input types are checkbox/radio/select/textarea etc.
-
-use dioxus::prelude::*;
-
-mod events;
-
-fn main() {
-    events::test_events();
-}
-
-pub(crate) fn check_app_exits(app: Component) {
-    // This is a deadman's switch to ensure that the app exits
-    let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
-    let should_panic_clone = should_panic.clone();
-    std::thread::spawn(move || {
-        std::thread::sleep(std::time::Duration::from_secs(100));
-        if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) {
-            std::process::exit(exitcode::SOFTWARE);
-        }
-    });
-
-    dioxus_desktop::launch(app);
-
-    should_panic.store(false, std::sync::atomic::Ordering::SeqCst);
-}

+ 89 - 0
packages/desktop/headless_tests/rendering.rs

@@ -0,0 +1,89 @@
+use dioxus::prelude::*;
+use dioxus_desktop::DesktopContext;
+
+pub(crate) fn check_app_exits(app: Component) {
+    // This is a deadman's switch to ensure that the app exits
+    let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
+    let should_panic_clone = should_panic.clone();
+    std::thread::spawn(move || {
+        std::thread::sleep(std::time::Duration::from_secs(100));
+        if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) {
+            std::process::exit(exitcode::SOFTWARE);
+        }
+    });
+
+    dioxus_desktop::launch(app);
+
+    should_panic.store(false, std::sync::atomic::Ordering::SeqCst);
+}
+
+fn main() {
+    check_app_exits(check_html_renders);
+}
+
+fn use_inner_html(cx: &ScopeState, id: &'static str) -> Option<String> {
+    let value: &UseRef<Option<String>> = use_ref(cx, || None);
+    use_effect(cx, (), |_| {
+        to_owned![value];
+        let desktop_context: DesktopContext = cx.consume_context().unwrap();
+        async move {
+            tokio::time::sleep(std::time::Duration::from_millis(100)).await;
+            let html = desktop_context
+                .eval(&format!(
+                    r#"let element = document.getElementById('{}');
+                return element.innerHTML;"#,
+                    id
+                ))
+                .await;
+            if let Ok(serde_json::Value::String(html)) = html {
+                println!("html: {}", html);
+                value.set(Some(html));
+            }
+        }
+    });
+    value.read().clone()
+}
+
+const EXPECTED_HTML: &str = r#"<div id="5" style="width: 100px; height: 100px; color: rgb(0, 0, 0);"><input type="checkbox"><h1>text</h1><div><p>hello world</p></div></div>"#;
+
+fn check_html_renders(cx: Scope) -> Element {
+    let inner_html = use_inner_html(cx, "main_div");
+    let desktop_context: DesktopContext = cx.consume_context().unwrap();
+
+    if let Some(raw_html) = inner_html.as_deref() {
+        let fragment = scraper::Html::parse_fragment(raw_html);
+        println!("fragment: {:?}", fragment.html());
+        let expected = scraper::Html::parse_fragment(EXPECTED_HTML);
+        println!("fragment: {:?}", expected.html());
+        if fragment == expected {
+            println!("html matches");
+            desktop_context.close();
+        }
+    }
+
+    let dyn_value = 0;
+    let dyn_element = rsx! {
+        div {
+            dangerous_inner_html: "<p>hello world</p>",
+        }
+    };
+
+    render! {
+        div {
+            id: "main_div",
+            div {
+                width: "100px",
+                height: "100px",
+                color: "rgb({dyn_value}, {dyn_value}, {dyn_value})",
+                id: 5,
+                input {
+                    "type": "checkbox",
+                },
+                h1 {
+                    "text"
+                }
+                dyn_element
+            }
+        }
+    }
+}