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
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

#[cfg(test)]
use wasm_bindgen::prelude::*;

// Must use inline build because the test runner does not import itself in
// the browser with `type=module` which causes `import.meta` calls to fail,
// and `currentScript` does not resolve dynamic imports so the polyfill
// for `import.meta` does not work either.
#[cfg(test)]
#[wasm_bindgen(inline_js = "

    export async function worker() {
        await import('/dist/pkg/test/perspective.js');
        return window.perspective.worker();
    }

")]
extern "C" {
    fn worker() -> js_sys::Promise;
}

// /// Generate a test `Table`, but only create teh webworker once or the tests
// /// will figuratively literally run forever.
// #[cfg(test)]
// pub async fn get_mock_table() -> JsPerspectiveTable {
//     thread_local! {
//         static WORKER: RefCell<Option<JsPerspectiveWorker>> =
// RefCell::new(None);     }

//     let worker: JsPerspectiveWorker = match WORKER.with(|x|
// x.borrow().clone()) {         Some(x) => x,
//         None => JsFuture::from(worker()).await.unwrap().unchecked_into(),
//     };

//     WORKER.with(|x| {
//         *x.borrow_mut() = Some(worker.clone());
//     });

//     worker
//         .table(
//             json!({
//                 "A": [1, 2, 3]
//             })
//             .unchecked_into(),
//         )
//         .await
//         .unwrap()
// }

/// A macro which set a property called `weak_link` on the container
/// `Properties` when `cfg(test)`, such that unit tests may send messages to a
/// component.
///
/// This macro needs to be called in `create()` on any Component which needs to
/// receive messages in a test.
#[macro_export]
macro_rules! enable_weak_link_test {
    ($props:expr, $link:expr) => {
        #[cfg(test)]
        {
            *$props.weak_link.borrow_mut() = Some($link.clone());
        }
    };
}

/// A macro which derives a `yew::Component` for an arbitrary HTML snippet and
/// mounts it, for testing.
#[macro_export]
macro_rules! test_html {
    ($($html:tt)*) => {{
        use wasm_bindgen::JsCast;
        use yew::prelude::*;

        struct TestElement {}

        #[derive(Properties, PartialEq)]
        struct TestElementProps {
            html: Html,
            root: NodeRef,
        }

        impl Component for TestElement {
            type Message = ();
            type Properties = TestElementProps;

            fn create(_ctx: &Context<Self>) -> Self {
                TestElement {}
            }

            fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
                false
            }

            fn changed(&mut self, _ctx: &Context<Self>, _old: &Self::Properties) -> bool {
                true
            }

            fn view(&self, ctx: &Context<Self>) -> Html {
                html! {
                    <>
                        <style>
                            { "#test{position:absolute;top:0;bottom:0;left:0;right:0;}" }
                        </style>
                        <div ref={ ctx.props().root.clone() }>
                            { ctx.props().html.clone() }
                        </div>
                    </>
                }
            }
        }

        let document = ::perspective_js::utils::global::document();
        let body = document.body().unwrap();
        let div = document.create_element("div").unwrap();
        body.append_child(&div).unwrap();

        let init = web_sys::ShadowRootInit::new(web_sys::ShadowRootMode::Open);
        let shadow_root = div
            .attach_shadow(&init)
            .unwrap()
            .unchecked_into::<web_sys::Element>();

        let root = NodeRef::default();
        let props = TestElementProps {
            html: html!{ $($html)* },
            root: root.clone(),
        };

        yew::Renderer::<TestElement>::with_root_and_props(shadow_root, props).render();
        request_animation_frame().await;
        root.cast::<web_sys::HtmlElement>()
            .unwrap()
            .children()
            .get_with_index(0)
            .unwrap()
            .unchecked_into::<web_sys::HtmlElement>()
    }}
}