use serde_json::{json, Value};
use crate::cdp::client::CdpClient;
use crate::commands;
use crate::session::{self, SessionStore};
pub fn mutates_page(cmd: &str) -> bool {
matches!(
cmd,
"click" | "tap" | "dblclick" | "double_click" | "double-click"
| "fill" | "type" | "press" | "select" | "check" | "uncheck"
| "upload" | "drag" | "hover" | "scroll"
| "fill-form" | "fill_form" | "fillform"
| "fill_and_submit" | "fill-and-submit"
)
}
pub async fn attach_change_report(
client: &CdpClient,
store: &mut SessionStore,
browser_name: &str,
page_name: &str,
target_id: &str,
report: crate::run_helpers::ReportPolicy,
old_text: Option<&str>,
stored: Option<(String, String)>,
out: &mut Value,
) {
crate::snapshot::settle(client, 100, 1000).await;
let Ok(snapshot) = commands::inspect::run(client, false, None, None, None).await else {
crate::run_helpers::attach_verdict(
out,
crate::verdict::classify(crate::verdict::Observation::ReadFailed),
);
return;
};
let Some(old_text) = old_text else {
if let Some(browser_s) = store.browsers.get_mut(browser_name) {
let page = session::ensure_page(browser_s, page_name, target_id);
page.uid_map = snapshot.uid_map;
page.last_snapshot = Some(snapshot.text);
let (f, l) = snapshot.identity.map_or((None, None), |(f, l)| (Some(f), Some(l)));
page.last_snapshot_frame = f;
page.last_snapshot_loader = l;
}
crate::run_helpers::attach_verdict(
out,
crate::verdict::classify(crate::verdict::Observation::NoBaseline),
);
return;
};
let identity = commands::diff::Identity::from_loader(
stored.as_ref().map(|(f, l)| (f.as_str(), l.as_str())),
snapshot.identity.as_ref().map(|(f, l)| (f.as_str(), l.as_str())),
);
let cmp = commands::diff::compare(identity, old_text, &snapshot.text);
let body = if report.budget == 0 {
cmp.text.clone()
} else {
crate::truncate::truncate_str(
cmp.text.trim_end(),
report.budget,
"\n… truncated, send {\"cmd\":\"inspect\"} for the rest",
)
.into_owned()
};
if let Some(obj) = out.as_object_mut() {
obj.insert(
"changed".into(),
json!({
"added": cmp.added,
"removed": cmp.removed,
"changed": cmp.changed,
"unchanged": cmp.unchanged,
"moved": cmp.moved,
"anonymous": cmp.anonymous,
"document_changed": cmp.document_changed,
"identity_known": cmp.identity_known,
}),
);
obj.insert("delta".into(), json!(body));
if cmp.focus_from.is_some() || cmp.focus_to.is_some() {
obj.insert("focus".into(), json!({"from": cmp.focus_from, "to": cmp.focus_to}));
}
if let Some(hint) = cmp.hint {
obj.entry("hint").or_insert_with(|| json!(hint));
}
}
crate::run_helpers::attach_verdict(
out,
crate::verdict::classify(crate::verdict::Observation::Compared {
document_changed: cmp.document_changed,
identity_known: cmp.identity_known,
edits: cmp.added + cmp.removed + cmp.changed,
moved: cmp.moved,
focus_moved: cmp.focus_from.is_some() || cmp.focus_to.is_some(),
}),
);
if let Some(browser_s) = store.browsers.get_mut(browser_name) {
let page = session::ensure_page(browser_s, page_name, target_id);
page.uid_map = snapshot.uid_map;
page.last_snapshot = Some(snapshot.text);
let (f, l) = snapshot.identity.map_or((None, None), |(f, l)| (Some(f), Some(l)));
page.last_snapshot_frame = f;
page.last_snapshot_loader = l;
}
}