Feat: docs, code frm percy

This commit is contained in:
Jonathan Kelley committed 2021-01-14 02:56:41 -05:00
commit 2b9c8d09d9
72 files changed
+5130

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
//! Tests for our html! procedural macro
//!
//! To run all tests in this library:
//!
//! cargo test --color=always --package html-macro-test --lib "" -- --nocapture
// #![feature(proc_macro_hygiene)]
// TODO: Deny warnings to ensure that the macro isn't creating any warnings.
// #![deny(warnings)]
#[cfg(test)]
mod tests;
+3
View File
@@ -0,0 +1,3 @@
mod all_tests;
mod text;
mod ui;
@@ -0,0 +1,377 @@
//! This is a catch-all module to place new tests as we go.
//!
//! Over time we'll pull tests out of here and organize them.
//!
//! For example - there is a `text_tests.rs` module where all of our text node related
//! tests live.
use html_macro::html;
use std::collections::HashMap;
use virtual_node::{IterableNodes, VElement, VText, View, VirtualNode};
struct HtmlMacroTest {
generated: VirtualNode,
expected: VirtualNode,
}
impl HtmlMacroTest {
/// Ensure that the generated and the expected virtual node are equal.
fn test(self) {
assert_eq!(self.expected, self.generated);
}
}
#[test]
fn empty_div() {
HtmlMacroTest {
generated: html! { <div></div> },
expected: VirtualNode::element("div"),
}
.test();
}
#[test]
fn one_attr() {
let mut attrs = HashMap::new();
attrs.insert("id".to_string(), "hello-world".to_string());
let mut expected = VElement::new("div");
expected.attrs = attrs;
HtmlMacroTest {
generated: html! { <div id="hello-world"></div> },
expected: expected.into(),
}
.test();
}
/// Events are ignored in non wasm-32 targets
#[test]
fn ignore_events_on_non_wasm32_targets() {
HtmlMacroTest {
generated: html! {
<div onclick=|_: u8|{}></div>
},
expected: html! {<div></div>},
}
.test();
}
#[test]
fn child_node() {
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("span")];
HtmlMacroTest {
generated: html! { <div><span></span></div> },
expected: expected.into(),
}
.test();
}
#[test]
fn sibling_child_nodes() {
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("span"), VirtualNode::element("b")];
HtmlMacroTest {
generated: html! { <div><span></span><b></b></div> },
expected: expected.into(),
}
.test();
}
/// Nested 3 nodes deep
#[test]
fn three_nodes_deep() {
let mut child = VElement::new("span");
child.children = vec![VirtualNode::element("b")];
let mut expected = VElement::new("div");
expected.children = vec![child.into()];
HtmlMacroTest {
generated: html! { <div><span><b></b></span></div> },
expected: expected.into(),
}
.test()
}
#[test]
fn sibling_text_nodes() {
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::text("This is a text node")];
HtmlMacroTest {
generated: html! { <div>This is a text node</div> },
expected: expected.into(),
}
.test();
}
#[test]
fn nested_macro() {
let child_2 = html! { <b></b> };
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("span"), VirtualNode::element("b")];
HtmlMacroTest {
generated: html! {
<div>
{ html! { <span></span> } }
{ child_2 }
</div>
},
expected: expected.into(),
}
.test();
}
/// If the first thing we see is a block then we grab whatever is inside it.
#[test]
fn block_root() {
let em = html! { <em></em> };
let expected = VirtualNode::element("em");
HtmlMacroTest {
generated: html! {
{ em }
},
expected,
}
.test();
}
/// Text followed by a block
#[test]
fn text_next_to_block() {
let child = html! { <ul></ul> };
let mut expected = VElement::new("div");
expected.children = vec![
VirtualNode::text(" A bit of text "),
VirtualNode::element("ul"),
];
HtmlMacroTest {
generated: html! {
<div>
A bit of text
{ child }
</div>
},
expected: expected.into(),
}
.test();
}
/// Ensure that we maintain the correct spacing around punctuation tokens, since
/// they resolve into a separate TokenStream during parsing.
#[test]
fn punctuation_token() {
let text = "Hello, World";
HtmlMacroTest {
generated: html! { Hello, World },
expected: VirtualNode::text(text),
}
.test()
}
#[test]
fn vec_of_nodes() {
let children = vec![html! { <div> </div>}, html! { <strong> </strong>}];
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("div"), VirtualNode::element("strong")];
HtmlMacroTest {
generated: html! { <div> { children } </div> },
expected: expected.into(),
}
.test();
}
/// Just make sure that this compiles since async, for, loop, and type are keywords
#[test]
fn keyword_attribute() {
html! { <script src="/app.js" async="async" /> };
html! { <label for="username">Username:</label> };
html! { <audio loop="loop"><source src="/beep.mp3" type="audio/mpeg" /></audio> };
html! { <link rel="stylesheet" type="text/css" href="/app.css" /> };
}
/// For unquoted text apostrophes should be parsed correctly
#[test]
fn apostrophe() {
assert_eq!(html! { Aren't }, VText::new("Aren't").into());
assert_eq!(html! { Aren'ttt }, VText::new("Aren'ttt").into());
}
/// Verify that all of our self closing tags work without backslashes.
#[test]
fn self_closing_tag_without_backslash() {
let mut expected = VElement::new("div");
let children = vec![
"area", "base", "br", "col", "hr", "img", "input", "link", "meta", "param", "command",
"keygen", "source",
]
.into_iter()
.map(|tag| VirtualNode::element(tag))
.collect();
expected.children = children;
HtmlMacroTest {
generated: html! {
<div>
<area> <base> <br> <col> <hr> <img> <input> <link> <meta> <param> <command>
<keygen> <source>
</div>
},
expected: expected.into(),
}
.test();
}
/// Verify that our self closing tags work with backslashes
#[test]
fn self_closing_tag_with_backslace() {
HtmlMacroTest {
generated: html! {
<br />
},
expected: VirtualNode::element("br"),
}
.test();
}
#[test]
fn if_true_block() {
let child_valid = html! { <b></b> };
let child_invalid = html! { <i></i> };
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("b")];
HtmlMacroTest {
generated: html! {
<div>
{if true {child_valid} else {child_invalid}}
</div>
},
expected: expected.into(),
}
.test();
}
#[test]
fn if_false_block() {
let child_valid = html! { <b></b> };
let child_invalid = html! { <i></i> };
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("i")];
HtmlMacroTest {
generated: html! {
<div>
{if false {
child_valid
} else {
child_invalid
}}
</div>
},
expected: expected.into(),
}
.test();
}
#[test]
fn single_branch_if_true_block() {
let child_valid = html! { <b></b> };
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("b")];
HtmlMacroTest {
generated: html! {
<div>{if true {child_valid}}</div>
},
expected: expected.into(),
}
.test();
}
#[test]
fn single_branch_if_false_block() {
let child_valid = html! { <b></b> };
let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::text("")];
HtmlMacroTest {
generated: html! {
<div>{if false {child_valid}}</div>
},
expected: expected.into(),
}
.test();
}
#[test]
fn custom_component_props() {
struct Counter {
count: u8,
}
impl View for Counter {
fn render(&self) -> VirtualNode {
html! {
<span>Counter = {format!("{}", self.count)}</span>
}
}
}
let mut expected = VElement::new("div");
let mut child = VElement::new("span");
child.children = vec![VirtualNode::text("Counter = "), VirtualNode::text("1")];
expected.children = vec![child.into()];
HtmlMacroTest {
generated: html! {
<div><Counter count={1}/></div>
},
expected: expected.into(),
}
.test();
}
#[test]
fn custom_component_children() {
struct Child;
impl View for Child {
fn render(&self) -> VirtualNode {
html! {
<span></span>
}
}
}
let mut expected = VElement::new("div");
let mut child = VElement::new("span");
child.children = vec![VirtualNode::text("Hello World")];
expected.children = vec![child.into()];
HtmlMacroTest {
generated: html! {
<div>
<Child>Hello World</Child>
</div>
},
expected: expected.into(),
}
.test();
}
+171
View File
@@ -0,0 +1,171 @@
use html_macro::html;
use virtual_node::{IterableNodes, VirtualNode};
#[test]
fn text_root_node() {
assert_eq!(&html! { some text }.to_string(), "some text");
}
#[test]
fn text_variable_root() {
let text = "hello world";
assert_eq!(&html! { { text } }.to_string(), "hello world");
}
#[test]
fn raw_string_literal() {
assert_eq!(
&html! { <div>{ r#"Hello World"# }</div> }.to_string(),
"<div>Hello World</div>"
);
}
#[test]
fn text_variable_child() {
let text = "world";
assert_eq!(
&html! { <div>{ text }</div> }.to_string(),
"<div>world</div>"
)
}
#[test]
fn text_space_after_start_tag() {
assert_eq!(
&html! { <div> After Start Tag</div> }.to_string(),
"<div> After Start Tag</div>"
)
}
#[test]
fn text_space_before_end_tag() {
assert_eq!(
&html! { <div>Before End Tag </div> }.to_string(),
"<div>Before End Tag </div>"
)
}
#[test]
fn text_space_before_block() {
let text = "Before Block";
assert_eq!(
&html! { <div> {text}</div> }.to_string(),
"<div> Before Block</div>"
)
}
#[test]
fn text_space_after_block() {
let text = "Hello";
assert_eq!(
&html! { <div>{text} </div> }.to_string(),
"<div>Hello </div>"
)
}
#[test]
fn text_space_in_block_ignored() {
let text = "Hello";
assert_eq!(
&html! { <div>{ text }</div> }.to_string(),
"<div>Hello</div>"
)
}
#[test]
fn text_multiple_text_no_space_between() {
let hello = "Hello";
let world = "World";
assert_eq!(
&html! { <div>{ hello }{ world }</div> }.to_string(),
"<div>HelloWorld</div>"
)
}
#[test]
fn text_multiple_text_space_between() {
let hello = "Hello";
let world = "World";
assert_eq!(
&html! { <div>{ hello } { world }</div> }.to_string(),
"<div>Hello World</div>"
)
}
#[test]
fn text_multiple_text_space_around() {
let hello = "Hello";
let world = "World";
assert_eq!(
&html! { <div> { hello }{ world } </div> }.to_string(),
"<div> HelloWorld </div>"
)
}
#[test]
fn text_multiple_text_space_between_around() {
let hello = "Hello";
let world = "World";
assert_eq!(
&html! { <div> { hello } { world } </div> }.to_string(),
"<div> Hello World </div>"
)
}
#[test]
fn text_tokens_in_between_vars_without_space() {
let hello = "Hello";
let world = "World";
assert_eq!(
&html! { <div>{ hello }NoSpace{ world }</div> }.to_string(),
"<div>HelloNoSpaceWorld</div>"
)
}
#[test]
fn text_tokens_in_between_vars_with_space() {
let hello = "Hello";
let world = "World";
assert_eq!(
&html! { <div>{ hello } Space { world }</div> }.to_string(),
"<div>Hello Space World</div>"
)
}
#[test]
fn text_tokens_in_between_vars_space_around_between() {
let hello = "Hello";
let world = "World";
assert_eq!(
&html! { <div> { hello } Space { world } </div> }.to_string(),
"<div> Hello Space World </div>"
)
}
#[test]
fn text_space_before_next_open_tag() {
assert_eq!(
&html! { <div>Hello <img /> world</div> }.to_string(),
"<div>Hello <img> world</div>"
)
}
#[test]
fn text_no_space_before_open_tag() {
assert_eq!(
&html! { <div>Hello<img /> world</div> }.to_string(),
"<div>Hello<img> world</div>"
)
}
+7
View File
@@ -0,0 +1,7 @@
#[test]
fn ui() {
let t = trybuild::TestCases::new();
let ui_tests = concat!(env!("CARGO_MANIFEST_DIR"), "/src/tests/ui/*.rs");
t.compile_fail(ui_tests);
}
@@ -0,0 +1,11 @@
#![feature(proc_macro_hygiene)]
extern crate virtual_dom_rs;
use virtual_dom_rs::prelude::*;
// Used a tag name that does not exist in the HTML spec
fn main() {
html! {
<invalidtagname></invalidtagname>
};
}
@@ -0,0 +1,11 @@
error: invalidtagname is not a valid HTML tag.
If you are trying to use a valid HTML tag, perhaps there's a typo?
If you are trying to use a custom component, please capitalize the component name.
custom components: https://chinedufn.github.io/percy/html-macro/custom-components/index.html
--> $DIR/invalid_html_tag.rs:9:10
|
9 | <invalidtagname></invalidtagname>
| ^^^^^^^^^^^^^^
@@ -0,0 +1,12 @@
#![feature(proc_macro_hygiene)]
extern crate virtual_dom_rs;
use virtual_dom_rs::prelude::*;
// We are using open and close tags for a tag that should
// actually be a self closing tag
fn main () {
html! {
<br></br>
};
}
@@ -0,0 +1,5 @@
error: br is a self closing tag. Try "<br>" or "<br />"
--> $DIR/should_be_self_closing_tag.rs:10:15
|
10 | <br></br>
| ^^
@@ -0,0 +1,11 @@
#![feature(proc_macro_hygiene)]
extern crate virtual_dom_rs;
use virtual_dom_rs::prelude::*;
// Expected a closing div tag, found a closing strong tag
fn main () {
html! {
<div> </strong>
};
}
@@ -0,0 +1,5 @@
error: Wrong closing tag. Try changing "strong" into "div"
--> $DIR/wrong_closing_tag.rs:9:17
|
9 | <div> </strong>
| ^^^^^^