silkenweb_test/
lib.rs

1//! Utilities for writing tests for Silkenweb apps.
2use silkenweb::{document::Document, dom::DefaultDom, task::render_now};
3use silkenweb_base::document;
4use wasm_bindgen::{JsCast, UnwrapThrowExt};
5
6/// Setup a browser test.
7///
8/// This will cleanup the test when `drop`ed.
9#[must_use]
10pub struct BrowserTest;
11
12impl BrowserTest {
13    /// Setup a test.
14    ///
15    /// Actions:
16    ///
17    /// - Clear the render queue.
18    /// - Check this isn't a nested browser test.
19    /// - Unmount any mounted elements.
20    /// - Create a new mount point with `id` = `mount_point_id`.
21    pub async fn new(mount_point_id: &str) -> Self {
22        // Clear the render queue
23        render_now().await;
24
25        if try_html_element(APP_CONTAINER_ID).is_some() {
26            panic!("`Test` cannot be nested")
27        }
28
29        DefaultDom::unmount_all();
30
31        let app_container = document::create_element("div");
32        app_container.set_id(APP_CONTAINER_ID);
33
34        let mount_point = document::create_element("div");
35        mount_point.set_id(mount_point_id);
36        app_container
37            .append_child(&mount_point)
38            .expect_throw("Couldn't add mount point to app container");
39
40        let body = document::body().expect_throw("Couldn't get document body");
41        body.append_child(&app_container)
42            .expect_throw("Couldn't add app container to body");
43
44        Self
45    }
46
47    /// Get the HTML of a test.
48    pub fn html(&self) -> String {
49        html_element(APP_CONTAINER_ID).inner_html()
50    }
51}
52
53impl Drop for BrowserTest {
54    fn drop(&mut self) {
55        DefaultDom::unmount_all();
56        html_element(APP_CONTAINER_ID).remove();
57    }
58}
59
60/// Find an element by `id`
61///
62/// # Panics
63///
64/// This panics if the element is not found, or is not an [`HtmlElement`]
65///
66/// [`HtmlElement`]: web_sys::HtmlElement
67pub fn html_element(id: &str) -> web_sys::HtmlElement {
68    try_html_element(id).expect_throw("Element not found")
69}
70
71/// Find an element by `id`
72///
73/// This returns `None` if the element is not found.
74///
75/// # Panics
76///
77/// This panics if the element is found, and is not an [`HtmlElement`]
78///
79/// [`HtmlElement`]: web_sys::HtmlElement
80pub fn try_html_element(id: &str) -> Option<web_sys::HtmlElement> {
81    document::query_selector(&format!("#{id}"))
82        .expect_throw("Error searching for element")
83        .map(|elem| {
84            elem.dyn_into()
85                .expect_throw("Element was not an `HTMLElement")
86        })
87}
88
89const APP_CONTAINER_ID: &str = "silkenweb-test-mount-point";