1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Provide structs and functions to help testing simi apps.
//! Maybe move into its own crate?
use simi::prelude::{Application, RcMain};
use wasm_bindgen::JsCast;
use web_sys::Node;

pub fn start_app<A: Application<Parent = ()>>() -> RcMain<A> {
    let test_element_id = "div-element-use-for-testing-a-simi-app";
    let doc = simi::interop::document();
    if doc.get_element_by_id(test_element_id).is_none() {
        let div = doc
            .create_element("div")
            .expect("Create div element for testing");
        div.set_id(test_element_id);
        let body = doc.body().expect("Get body of the Document");
        (body.as_ref() as &Node)
            .append_child(div.as_ref())
            .expect("Add div element to the body element");
    }
    RcMain::start_in_element_id(test_element_id, ())
}

/// A wrapper helps access real DOM element for testing
pub struct Element {
    /// The element in real dom to test
    element: web_sys::Element,
}

impl Element {
    /// Return true if there is no element with id=element_id
    pub fn no_id(element_id: &str) -> bool {
        simi::interop::document()
            .get_element_by_id(element_id)
            .map_or(true, |_| false)
    }

    /// Create a new TestHelper
    pub fn element(element: web_sys::Element) -> Self {
        Self { element }
    }

    /// Create a new TestHelper from element_id
    pub fn id(element_id: &str) -> Self {
        Self {
            element: simi::interop::document()
                .get_element_by_id(element_id)
                .unwrap_or_else(|| panic!("No element with id = '{}'", element_id)),
        }
    }

    /// Query an element by a selector string, panic if none
    pub fn selector(s: &str) -> Self {
        Self {
            element: simi::interop::document()
                .query_selector(s)
                .expect(s)
                .expect(s),
        }
    }

    /// As a reference to web_sys::EventTarget
    pub fn as_event_target(&self) -> &web_sys::EventTarget {
        self.element.as_ref()
    }

    /// As a reference to web_sys::Node
    pub fn as_node(&self) -> &web_sys::Node {
        self.element.as_ref()
    }

    /// Reference to the element
    pub fn as_element(&self) -> &web_sys::Element {
        &self.element
    }

    /// As a reference to web_sys::HtmlInputElement
    pub fn as_input(&self) -> &web_sys::HtmlInputElement {
        self.element.unchecked_ref()
    }

    /// As a reference to web_sys::HtmlSelectElement
    pub fn as_select(&self) -> &web_sys::HtmlSelectElement {
        self.element.unchecked_ref()
    }

    /// As a reference to web_sys::HtmlOptionElement
    pub fn as_option(&self) -> &web_sys::HtmlOptionElement {
        self.element.unchecked_ref()
    }

    /// As a reference to web_sys::HtmlTextAreaElement
    pub fn as_textarea(&self) -> &web_sys::HtmlTextAreaElement {
        self.element.unchecked_ref()
    }

    /// Simulate a click on the element
    pub fn click(&self) {
        let clickable: &web_sys::HtmlElement = self.element.unchecked_ref();
        clickable.click();
    }

    /// Set input element value then trigger an input event
    pub fn input_input(&self, value: &str) {
        self.as_input().set_value(value);
        self.as_event_target()
            .dispatch_event(
                web_sys::InputEvent::new("input")
                    .expect("Create input event must succeed")
                    .as_ref(),
            )
            .expect("Dispatch input event");
    }

    /// Set input element value then trigger a change event
    pub fn change_input(&self, value: &str) {
        self.as_input().set_value(value);
        self.as_event_target()
            .dispatch_event(
                web_sys::InputEvent::new("change")
                    .expect("Create change event must succeed")
                    .as_ref(),
            )
            .expect("Dispatch change event");
    }

    /// Set select element value then trigger a change event
    pub fn change_select(&self, value: &str) {
        self.as_select().set_value(value);
        self.as_event_target()
            .dispatch_event(
                &web_sys::Event::new("change").expect("Create change event must succeed"),
            )
            .expect("Dispatch change event");
    }

    /// Set select element index then trigger a change event
    pub fn change_index(&self, index: usize) {
        self.as_select().set_selected_index(index as i32);
        self.as_event_target()
            .dispatch_event(
                &web_sys::Event::new("change").expect("Create change event must succeed"),
            )
            .expect("Dispatch change event");
    }

    /// Set textarea element value then trigger a change event
    pub fn change_textarea(&self, value: &str) {
        self.as_textarea().set_value(value);
        self.as_event_target()
            .dispatch_event(
                &web_sys::Event::new("change").expect("Create change event must succeed"),
            )
            .expect("Dispatch change event");
    }
}