use wasm_bindgen_test::*; use maomi::prelude::*; use maomi_dom::{async_task, element::*, prelude::*}; use super::*; #[wasm_bindgen_test] async fn template_if_else() { #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
if self.text.len() > 10 {
"(too long)"
} else if self.text.len() == 0 {
"(empty)"
} else {
{ &self.text }
}
}, text: String, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), text: "".into(), } } fn created(&self) { let this = self.rc(); async_task(async move { this.update(|this| { assert_eq!(first_dom!(this, div).inner_html(), r#"
(empty)
"#,); this.text = "hello".into(); }) .await .unwrap(); this.update_with(|this, ctx| { assert_eq!(first_dom!(this, div).inner_html(), r#"
hello
"#,); this.text = "long........".into(); ctx.need_update(); }) .await .unwrap(); this.update_with(|this, _| { assert_eq!( first_dom!(this, div).inner_html(), r#"
(too long)
"#, ); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn template_lonely_if() { #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
if self.text.len() > 0 {
{ &self.text }
}
}, text: String, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), text: "".into(), } } fn created(&self) { let this = self.rc(); async_task(async move { this.update(|this| { assert_eq!(first_dom!(this, div).inner_html(), r#""#,); this.text = "hello".into(); }) .await .unwrap(); this.update(|this| { assert_eq!(first_dom!(this, div).inner_html(), r#"
hello
"#,); this.text = "".into(); }) .await .unwrap(); this.update_with(|this, _| { assert_eq!(first_dom!(this, div).inner_html(), r#""#,); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn template_match() { #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
match self.text.len() { 11.. => {
"(too long)"
}, 0 => {
"(empty)"
} _ => {
{ &self.text }
} }
}, text: String, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), text: "".into(), } } fn created(&self) { let this = self.rc(); async_task(async move { this.update(|this| { assert_eq!(first_dom!(this, div).inner_html(), r#"
(empty)
"#,); this.text = "hello".into(); }) .await .unwrap(); this.update_with(|this, ctx| { assert_eq!(first_dom!(this, div).inner_html(), r#"
hello
"#,); this.text = "long........".into(); ctx.need_update(); }) .await .unwrap(); this.update_with(|this, _| { assert_eq!( first_dom!(this, div).inner_html(), r#"
(too long)
"#, ); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn template_for_keyless() { #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
for (index, _) in self.list.iter().enumerate() {
{ &index.to_string() }
} for item in self.list.iter() {
{ &item.to_string() }
}
}, list: Vec, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), list: vec![123, 456], } } fn created(&self) { let this = self.rc(); async_task(async move { this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
1
123
456
"#, ); this.list.push(789); }) .await .unwrap(); this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
1
2
123
456
789
"#, ); this.list.pop(); this.list.pop(); }).await.unwrap(); this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
123
"#, ); this.list.pop(); this.list.pop(); }) .await .unwrap(); this.update_with(|this, _| { assert_eq!(first_dom!(this, div).inner_html(), r#""#,); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn template_for() { use std::cell::RefCell; struct MyList(usize); impl AsListKey for MyList { type ListKey = usize; fn as_list_key(&self) -> &usize { &self.0 } } thread_local! { static EV_LIST: RefCell> = RefCell::new(vec![]); } #[component(Backend = DomBackend)] struct Child { template: template! { { &self.num.to_string() } }, num: Prop, } impl Component for Child { fn new() -> Self { Self { template: Default::default(), num: Prop::new(0), } } fn created(&self) { EV_LIST.with(|ev_list| ev_list.borrow_mut().push(*self.num)); } } #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
for (index, item) in self.list.iter().enumerate() use (item) usize {
{ &index.to_string() }
} for item in self.list.iter() use usize { }
}, list: Vec, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), list: vec![MyList(12), MyList(34)], } } fn created(&self) { let this = self.rc(); async_task(async move { this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
1
1234"#, ); assert_eq!( EV_LIST.with(|ev_list| ev_list.borrow_mut().drain(..).collect::>()), vec![12, 34], ); this.list = vec![MyList(78), MyList(12), MyList(56), MyList(34), MyList(90)]; }) .await .unwrap(); this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
1
2
3
4
7812563490"#, ); assert_eq!( EV_LIST.with(|ev_list| ev_list.borrow_mut().drain(..).collect::>()), vec![78, 56, 90], ); this.list = vec![MyList(12), MyList(90), MyList(56), MyList(78), MyList(34)]; }) .await .unwrap(); this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
1
2
3
4
1290567834"#, ); assert_eq!( EV_LIST.with(|ev_list| ev_list.borrow_mut().drain(..).collect::>()), Vec::::new(), ); this.list = vec![MyList(78), MyList(12), MyList(56), MyList(34), MyList(90)]; }) .await .unwrap(); this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
1
2
3
4
7812563490"#, ); assert_eq!( EV_LIST.with(|ev_list| ev_list.borrow_mut().drain(..).collect::>()), Vec::::new(), ); this.list = vec![MyList(12), MyList(67), MyList(34)]; }) .await .unwrap(); this.update(|this| { assert_eq!( first_dom!(this, div).inner_html(), r#"
0
1
2
126734"#, ); assert_eq!( EV_LIST.with(|ev_list| ev_list.borrow_mut().drain(..).collect::>()), vec![67], ); this.list = vec![]; }) .await .unwrap(); this.update_with(|this, _| { assert_eq!(first_dom!(this, div).inner_html(), r#""#,); assert_eq!( EV_LIST.with(|ev_list| ev_list.borrow_mut().drain(..).collect::>()), Vec::::new(), ); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn class_attr() { stylesheet! { #[css_name("static-class")] class static_class { color = red; } #[css_name("dyn-class")] class dyn_class { color = blue; } } #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
}, v: bool, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), v: false, } } fn created(&self) { let this = self.rc(); async_task(async move { this.update(|this| { assert_eq!( first_dom!(this, div).outer_html(), r#"
"#, ); this.v = true; }) .await .unwrap(); this.update(|this| { assert_eq!( first_dom!(this, div).outer_html(), r#"
"#, ); this.v = false; }) .await .unwrap(); this.update_with(|this, _| { assert_eq!( first_dom!(this, div).outer_html(), r#"
"#, ); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn style_attr() { stylesheet! { style color(rgb: f32) { color = rgb(rgb, rgb, rgb); } } #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
}, color: i32, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), color: 64, } } fn created(&self) { let this = self.rc(); async_task(async move { this.update(|this| { assert_eq!( first_dom!(this, div).outer_html(), r#"
"#, ); this.color = 128; }) .await .unwrap(); this.update_with(|this, _| { assert_eq!( first_dom!(this, div).outer_html(), r#"
"#, ); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn event_handler() { struct MyEventDetail { num: Option, } #[component(Backend = DomBackend)] struct Child { template: template! { { &self.my_prop } }, my_prop: Prop, my_event: Event, } impl Component for Child { fn new() -> Self { Self { template: Default::default(), my_prop: Prop::new("".into()), my_event: Event::new(), } } fn before_template_apply(&mut self) { self.my_event.trigger(&mut MyEventDetail { num: self.my_prop.parse().ok(), }); } } #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
for item in &self.list { }
}, list: Vec, } impl Parent { fn my_event_handler(this: ComponentEvent, item: &str) { let num = this.detail().num.unwrap_or(0); assert_eq!(num.to_string().as_str(), item); let this = this.rc(); async_task(async move { this.update(move |this| { if num <= 300 { this.list = vec![(num + 100).to_string()]; } else { assert_eq!(first_dom!(this, div).outer_html(), r#"
400
"#,); (this.callback.take().unwrap())(); } }) .await .unwrap(); }); } } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), list: vec![100.to_string()], } } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn binding_prop() { use maomi::prop::{BindingProp, BindingValue}; use maomi_dom::event::*; #[component(Backend = DomBackend)] struct Child { template: template! { }, input_value: BindingValue, has_input_value: BindingProp, change: Event<()>, } impl Component for Child { fn new() -> Self { Self { template: Default::default(), input_value: BindingValue::new(String::with_capacity(0)), has_input_value: BindingProp::new(false), change: Event::new(), } } fn before_template_apply(&mut self) { self.update_has_input_value(); } fn created(&self) { let this = self.rc(); this.task_with(|this, _| { let dom_elem = first_dom!(this, input).clone(); dom_elem .dyn_ref::() .unwrap() .set_value("abc"); simulate_event(&dom_elem, "input", false, []); simulate_event(&dom_elem, "change", false, []); }); } } impl Child { fn update_has_input_value(&mut self) { self.has_input_value.set(self.input_value.get().len() > 0); } fn input_change(this: ComponentEvent) { this.task(|this| { this.change.trigger(&mut ()); }); } } #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
}, has_input_value: BindingValue, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), has_input_value: BindingValue::new(false), } } } impl Parent { fn child_change(this: ComponentEvent) { this.task_with(|this, _| { assert_eq!(this.has_input_value.get(), true); (this.callback.take().unwrap())(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn list_prop() { use maomi::prop::ListProp; #[component(Backend = DomBackend)] struct Child { template: template! { for item in &self.my_list_prop {
{ item }
} }, my_list_prop: ListProp, } impl Component for Child { fn new() -> Self { Self { template: Default::default(), my_list_prop: ListProp::new(), } } } #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
}, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), } } fn created(&self) { let this = self.rc(); this.task_with(|this, _| { assert_eq!( first_dom!(this, div).inner_html(), r#"
abc
def
ghi
"#, ); (this.callback.take().unwrap())(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; } #[wasm_bindgen_test] async fn dom_custom_attribute() { use maomi_dom::dom_define_attribute; dom_define_attribute!(role); #[component(Backend = DomBackend)] struct Parent { callback: Option, template: template! {
}, } impl Component for Parent { fn new() -> Self { Self { callback: None, template: Default::default(), } } fn created(&self) { let this = self.rc(); async_task(async move { this.update_with(|this, _| { assert_eq!( first_dom!(this, div).outer_html(), r#"
"#, ); (this.callback.take().unwrap())(); }) .await .unwrap(); }); } } impl ComponentTest for Parent { fn set_callback(&mut self, callback: ComponentTestCb) { self.callback = Some(callback); } } test_component::().await; }