use blitz_dom::{Document, DocumentConfig};
use blitz_script::ScriptDocument;
use blitz_traits::events::DomEvent;
use blitz_traits::navigation::{NavigationOptions, NavigationProvider};
use keyboard_types::Modifiers;
#[derive(Default)]
struct RecordedNavigation(std::sync::Mutex<Vec<String>>);
impl NavigationProvider for RecordedNavigation {
fn navigate_to(&self, options: NavigationOptions) {
if let Ok(mut destinations) = self.0.lock() {
destinations.push(options.url.to_string());
}
}
}
fn page(script: &str) -> (ScriptDocument, std::sync::Arc<RecordedNavigation>) {
let navigation = std::sync::Arc::new(RecordedNavigation::default());
let document = ScriptDocument::from_html(
&format!(
r#"<html><body>
<form id="f" action="https://example.com/submitted">
<input id="q" name="q" value="typed">
<button id="go" type="submit">Go</button>
</form>
<p id="out">not yet</p>
<script>{script}</script>
</body></html>"#
),
DocumentConfig {
base_url: Some("https://example.com/".to_owned()),
navigation_provider: Some(navigation.clone()),
..Default::default()
},
);
(document, navigation)
}
fn press_submit(document: &mut ScriptDocument) {
let (button, click) = {
let inner = document.inner();
let button = inner
.query_selector("#go")
.unwrap()
.expect("the fixture has a submit button");
let click = inner
.get_node(button)
.unwrap()
.synthetic_click_event(Modifiers::empty());
(button, click)
};
document.dispatch_dom_event(DomEvent::new(button, click));
document.poll(None);
}
fn text_of(document: &ScriptDocument, selector: &str) -> String {
let inner = document.inner();
let id = inner.query_selector(selector).unwrap().unwrap();
inner.get_node(id).unwrap().text_content()
}
#[test]
fn a_prevented_submission_does_not_navigate() {
let (mut document, navigation) = page(
r#"document.getElementById('f').addEventListener('submit', function (event) {
event.preventDefault();
document.getElementById('out').textContent = 'handled';
});"#,
);
document.execute_scripts();
press_submit(&mut document);
assert_eq!(
text_of(&document, "#out"),
"handled",
"the page's submit handler never ran"
);
assert!(
navigation.0.lock().unwrap().is_empty(),
"the form navigated even though the page prevented it: {:?}",
navigation.0.lock().unwrap()
);
}
#[test]
fn an_unhandled_submission_still_navigates() {
let (mut document, navigation) = page("");
document.execute_scripts();
press_submit(&mut document);
let destinations = navigation.0.lock().unwrap();
assert_eq!(
destinations.len(),
1,
"a form nobody handled should still submit: {destinations:?}"
);
assert!(
destinations[0].contains("/submitted"),
"submitted to the wrong place: {destinations:?}"
);
}
#[test]
fn an_observed_submission_still_navigates() {
let (mut document, navigation) = page(
r#"document.getElementById('f').addEventListener('submit', function () {
document.getElementById('out').textContent = 'seen';
});"#,
);
document.execute_scripts();
press_submit(&mut document);
assert_eq!(text_of(&document, "#out"), "seen");
assert_eq!(
navigation.0.lock().unwrap().len(),
1,
"watching a submission is not cancelling it"
);
}