use blitz_dom::NodeId;
use std::path::PathBuf;
use blitz_dom::{Document, DocumentConfig};
use blitz_script::ScriptDocument;
use blitz_traits::events::{BlitzKeyEvent, DomEvent, KeyState, UiEvent};
use keyboard_types::{Code, Key, Location, Modifiers};
use url::Url;
fn preact_example_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../examples/preact")
}
fn load_todomvc() -> ScriptDocument {
let index_path = preact_example_dir()
.join("index.html")
.canonicalize()
.unwrap();
let html = std::fs::read_to_string(&index_path).unwrap();
let base_url = Url::from_file_path(&index_path).unwrap();
let mut doc = ScriptDocument::from_html(
&html,
DocumentConfig {
base_url: Some(base_url.to_string()),
..Default::default()
},
);
doc.execute_scripts();
resolve(&mut doc);
doc
}
fn resolve(doc: &mut ScriptDocument) {
doc.inner_mut().resolve(0.0);
}
fn query(doc: &ScriptDocument, selector: &str) -> Option<NodeId> {
doc.inner().query_selector(selector).unwrap()
}
fn query_all(doc: &ScriptDocument, selector: &str) -> Vec<NodeId> {
doc.inner().query_selector_all(selector).unwrap().to_vec()
}
fn text_of(doc: &ScriptDocument, node_id: NodeId) -> String {
doc.inner().get_node(node_id).unwrap().text_content()
}
fn enter_key() -> BlitzKeyEvent {
BlitzKeyEvent {
key: Key::Enter,
code: Code::Enter,
modifiers: Modifiers::empty(),
location: Location::Standard,
is_auto_repeating: false,
is_composing: false,
state: KeyState::Pressed,
text: None,
}
}
fn click(doc: &mut ScriptDocument, selector: &str) {
resolve(doc);
let event = {
let inner = doc.inner();
let node_id = inner
.query_selector(selector)
.unwrap()
.unwrap_or_else(|| panic!("no node matching {selector}"));
DomEvent::new(
node_id,
inner
.get_node(node_id)
.unwrap()
.synthetic_click_event(Modifiers::empty()),
)
};
doc.dispatch_dom_event(event);
}
fn add_todo(doc: &mut ScriptDocument, text: &str) {
resolve(doc);
doc.eval(&format!(
"document.querySelector('.new-todo').value = {text:?};"
));
let input_id = query(doc, ".new-todo").expect("new-todo input");
doc.inner_mut().set_focus_to(input_id);
doc.handle_ui_event(UiEvent::KeyDown(enter_key()));
}
#[test]
fn renders_initial_ui() {
let doc = load_todomvc();
let h1 = query(&doc, ".app h1").expect("h1 should be rendered by Preact");
assert_eq!(text_of(&doc, h1), "todos");
let input = query(&doc, "input.new-todo").expect("new-todo input");
let inner = doc.inner();
let placeholder = inner
.get_node(input)
.unwrap()
.attr(blitz_dom::local_name!("placeholder"))
.unwrap()
.to_string();
assert_eq!(placeholder, "What needs to be done?");
drop(inner);
assert!(query(&doc, "ul li").is_none());
assert!(query(&doc, ".footer").is_none());
}
#[test]
fn add_toggle_filter_and_clear_todos() {
let mut doc = load_todomvc();
add_todo(&mut doc, "Buy milk");
add_todo(&mut doc, "Walk dog");
let items = query_all(&doc, "ul > li");
assert_eq!(items.len(), 2);
assert!(text_of(&doc, items[0]).contains("Buy milk"));
assert!(text_of(&doc, items[1]).contains("Walk dog"));
let input_id = query(&doc, ".new-todo").unwrap();
let value = {
let inner = doc.inner();
let node = inner.get_node(input_id).unwrap();
node.element_data()
.unwrap()
.text_input_data()
.unwrap()
.editor
.raw_text()
.to_string()
};
assert_eq!(value, "");
let footer = query(&doc, ".footer").expect("footer");
assert!(text_of(&doc, footer).contains("2 items left"));
click(&mut doc, "ul > li input[type='checkbox']");
let done_items = query_all(&doc, "ul > li.done");
assert_eq!(done_items.len(), 1);
assert!(text_of(&doc, done_items[0]).contains("Buy milk"));
let footer = query(&doc, ".footer").unwrap();
assert!(text_of(&doc, footer).contains("1 item left"));
click(&mut doc, ".filters button:nth-child(2)");
let items = query_all(&doc, "ul > li");
assert_eq!(items.len(), 1);
assert!(text_of(&doc, items[0]).contains("Walk dog"));
click(&mut doc, ".filters button:nth-child(3)");
let items = query_all(&doc, "ul > li");
assert_eq!(items.len(), 1);
assert!(text_of(&doc, items[0]).contains("Buy milk"));
click(&mut doc, ".filters button:nth-child(1)");
assert_eq!(query_all(&doc, "ul > li").len(), 2);
click(&mut doc, "ul > li.done button.destroy");
let items = query_all(&doc, "ul > li");
assert_eq!(items.len(), 1);
assert!(text_of(&doc, items[0]).contains("Walk dog"));
click(&mut doc, "ul > li input[type='checkbox']");
let footer = query(&doc, ".footer").unwrap();
assert!(text_of(&doc, footer).contains("0 items left"));
click(&mut doc, "button.clear");
assert!(query(&doc, "ul > li").is_none());
assert!(query(&doc, ".footer").is_none());
}