use std::convert::TryFrom;
use mogwai::model::Model;
use mogwai_dom::{core::channel::broadcast, prelude::*};
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn expand_this_builder() {
let _ = html! {
};
}
#[test]
fn node_self_closing() {
futures_lite::future::block_on(async {
// not all nodes are void nodes
let div = SsrDom::try_from(html! {
})
.unwrap();
let div: String = div.html_string().await;
assert_eq!(&div, r#""#);
let div = SsrDom::try_from(html! {
})
.unwrap();
let div = div.html_string().await;
assert_eq!(&div, r#""#);
});
}
#[test]
fn node_self_closing_gt_1_att() {
futures_lite::future::block_on(async {
let bldr: ViewBuilder = html! {};
match &bldr.initial_values[0] {
Update::Attribute(HashPatch::Insert(k, v)) => {
assert_eq!("href", k.as_str());
assert_eq!("http://zyghost.com", v.as_str());
}
att => panic!("unmatched attribute: {:?}", att),
}
// not all nodes are void nodes
let div = SsrDom::try_from(html! {}).unwrap();
let div: String = div.html_string().await;
assert_eq!(&div, r#""#);
let div =
SsrDom::try_from(html! {})
.unwrap();
let div: String = div.html_string().await;
assert_eq!(
&div,
r#""#
);
});
}
#[test]
fn by_hand() {
futures_lite::future::block_on(async {
let builder: ViewBuilder = ViewBuilder::element("a")
.with_single_attrib_stream("href", "http://zyghost.com")
.with_single_attrib_stream("class", "a_link")
.append(ViewBuilder::text("a text node"));
assert_eq!(
r#"a text node"#,
SsrDom::try_from(builder).unwrap().html_string().await
);
});
}
#[test]
fn node() {
futures_lite::future::block_on(async {
let div: String = SsrDom::try_from(html! {
"a text node"
})
.unwrap()
.html_string()
.await;
assert_eq!(
&div,
r#"a text node"#
);
});
}
#[test]
fn block_in_text() {
futures_lite::future::block_on(async {
let x: u32 = 66;
let s: String = SsrDom::try_from(html! {
"just a string with the number" {format!("{}", x)} "<- blah blah"
})
.unwrap()
.html_string()
.await;
assert_eq!(
s,
format!("just a string with the number 66 <- blah blah
")
);
});
}
#[test]
fn block_at_end_of_text() {
futures_lite::future::block_on(async {
let x: u32 = 66;
let s: String = SsrDom::try_from(html! {
"just a string with the number" {format!("{}", x)}
})
.unwrap()
.html_string()
.await;
assert_eq!(&s, "just a string with the number 66
");
});
}
#[test]
fn lt_in_text() {
futures_lite::future::block_on(async {
let s: String = SsrDom::try_from(html! {
"this is text <- text"
})
.unwrap()
.html_string()
.await;
assert_eq!(s, "this is text <- text
");
});
}
#[test]
fn allow_attributes_on_next_line() {
futures_lite::future::block_on(async {
let _: String = SsrDom::try_from(html! {
"A string"
})
.unwrap()
.html_string()
.await;
});
}
#[test]
fn rsx_cookbook() {
let (_tx, rx) = broadcast::bounded::(1.try_into().unwrap());
let _ = signed_in_view_builder(
&User {
username: "oona".to_string(),
o_image: None,
},
rx.clone(),
rx.clone(),
rx.clone(),
rx,
);
}
struct User {
username: String,
o_image: Option,
}
fn signed_in_view_builder(
user: &User,
home_class: impl Stream- + Send + 'static,
editor_class: impl Stream
- + Send + 'static,
settings_class: impl Stream
- + Send + 'static,
profile_class: impl Stream
- + Send + 'static,
) -> ViewBuilder {
let o_image: Option = user
.o_image
.as_ref()
.map(|image| {
if image.is_empty() {
None
} else {
Some(html! { })
}
})
.flatten();
html! {
}
}
#[test]
pub fn function_style_rsx() {
fn _signed_in_view_builder(
user: &User,
home_class: impl Stream
- + Send + 'static,
editor_class: impl Stream
- + Send + 'static,
settings_class: impl Stream
- + Send + 'static,
profile_class: impl Stream
- + Send + 'static,
) -> ViewBuilder {
// ANCHOR: rsx_conditional_dom
let o_image: Option = user
.o_image
.as_ref()
.map(|image| {
if image.is_empty() {
None
} else {
Some(html! { })
}
})
.flatten();
rsx! {
ul(class="nav navbar-nav pull-xs-right") {
li(class="nav-item") {
a(class=home_class, href="#/"){ " Home" }
}
li(class="nav-item") {
a(class=editor_class, href="#/editor") {
i(class="ion-compose") {
" New Post"
}
}
}
li(class="nav-item") {
a(class=settings_class, href="#/settings") {
i(class="ion-gear-a"){
" Settings"
}
}
}
li(class="nav-item") {
a(class=profile_class, href=format!("#/profile/{}", user.username)) {
{o_image}
{format!(" {}", user.username)}
}
}
}
}
// ANCHOR_END: rsx_conditional_dom
}
}
#[test]
fn rsx_same_as_html() {
futures_lite::future::block_on(async {
let html = SsrDom::try_from(html! {
"Hello"
})
.unwrap();
let html_string = html.html_string().await;
let rsx = SsrDom::try_from(rsx! {
p{ div(class="my_class"){ "Hello" }}
})
.unwrap();
let rsx_string = rsx.html_string().await;
assert_eq!(html_string, rsx_string, "rsx and html to not agree");
});
}
#[derive(Clone)]
struct Row {
id: Model,
label: Model,
selected: Model,
}
impl Row {
fn new(id: usize, label: impl Into) -> Self {
Row {
id: Model::new(id),
label: Model::new(label),
selected: Model::new(false),
}
}
fn viewbuilder(self) -> ViewBuilder {
rsx! {
tr(
key = self.id.clone().map(|id| id.to_string()),
class = self.selected.map(|is_selected| if is_selected {
"danger"
} else {
""
}.to_string())
) {
td(class="col-md-1"){{ self.id.clone().map(|id| id.to_string()) }}
td(class="col-md-4"){
a() {{ self.label.clone() }}
}
td(class="col-md-1"){
a() {
span(class="glyphicon glyphicon-remove", aria_hidden="true") {}
}
}
td(class="col-md-6"){ }
}
}
}
}
impl TryFrom for JsDom {
type Error = anyhow::Error;
fn try_from(value: Row) -> Result {
value.viewbuilder().try_into()
}
}
#[wasm_bindgen_test]
async fn benchmark_row_clone() {
let row = Row::new(0, "hello");
let proto_node = JsDom::try_from(row.clone())
.unwrap()
.ossify();
fn compare_str(id: usize, label: &str) -> String {
format!(
r#"{id} | {label} | | |
"#
)
}
let html_string = proto_node.html_string().await;
assert_eq!(compare_str(0, "hello"), html_string);
let hydrated_node = proto_node.hydrate(row.clone().viewbuilder()).unwrap();
row.id.replace(1usize).await;
row.label.replace("kia ora").await;
mogwai::time::wait_millis(10).await;
let html_string = hydrated_node.html_string().await;
assert_eq!(compare_str(1, "kia ora"), html_string);
}