use layout_dom_api::LayoutDom;
use serval_scripted_dom::ScriptedDom;
use crate::api::{Cookie, FlipDonor, FormValues, FrameHandle, LayerSet, PortableViewState};
pub struct ServalDonor<'a> {
dom: &'a ScriptedDom,
url: Option<String>,
scroll: (f32, f32),
cookies: Vec<Cookie>,
visual: Option<FrameHandle>,
}
impl<'a> ServalDonor<'a> {
pub fn new(dom: &'a ScriptedDom) -> Self {
Self {
dom,
url: None,
scroll: (0.0, 0.0),
cookies: Vec::new(),
visual: None,
}
}
pub fn with_url(mut self, url: impl Into<String>) -> Self {
self.url = Some(url.into());
self
}
pub fn with_scroll(mut self, scroll: (f32, f32)) -> Self {
self.scroll = scroll;
self
}
pub fn with_cookies(mut self, cookies: Vec<Cookie>) -> Self {
self.cookies = cookies;
self
}
pub fn with_visual(mut self, frame: FrameHandle) -> Self {
self.visual = Some(frame);
self
}
}
impl FlipDonor for ServalDonor<'_> {
fn donates(&self) -> LayerSet {
let mut set = LayerSet::FORM | LayerSet::DOM;
if self.url.is_some() {
set = set | LayerSet::NAV;
}
if !self.cookies.is_empty() {
set = set | LayerSet::SESSION;
}
if self.visual.is_some() {
set = set | LayerSet::VISUAL;
}
set
}
fn capture(&self) -> PortableViewState {
let root = self.dom.document();
PortableViewState {
url: self.url.clone(),
scroll: self.scroll,
form: Some(FormValues(self.dom.form_values(root))),
cookies: self.cookies.clone(),
dom_snapshot: Some(self.dom.outer_html(root)),
visual: self.visual,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_donor_donates_form_and_dom_only() {
let dom = ScriptedDom::new();
let set = ServalDonor::new(&dom).donates();
assert!(set.contains(LayerSet::FORM));
assert!(set.contains(LayerSet::DOM));
assert!(!set.contains(LayerSet::NAV));
assert!(!set.contains(LayerSet::SESSION));
assert!(!set.contains(LayerSet::VISUAL));
}
#[test]
fn fed_layers_widen_donates_and_fill_capture() {
let dom = ScriptedDom::new();
let donor = ServalDonor::new(&dom)
.with_url("https://example.com/page")
.with_scroll((0.0, 120.0))
.with_cookies(vec![Cookie {
name: "sid".into(),
value: "abc".into(),
..Cookie::default()
}])
.with_visual(FrameHandle(7));
let set = donor.donates();
assert!(set.contains(LayerSet::NAV | LayerSet::SESSION | LayerSet::VISUAL));
let state = donor.capture();
assert_eq!(state.url.as_deref(), Some("https://example.com/page"));
assert_eq!(state.scroll, (0.0, 120.0));
assert_eq!(state.cookies.len(), 1);
assert_eq!(state.visual, Some(FrameHandle(7)));
assert!(state.form.is_some());
assert!(state.dom_snapshot.is_some());
}
#[test]
fn scroll_without_url_does_not_claim_nav() {
let dom = ScriptedDom::new();
let set = ServalDonor::new(&dom).with_scroll((10.0, 20.0)).donates();
assert!(!set.contains(LayerSet::NAV));
}
}