pub use stygian_extract_derive::Extract;
#[derive(Debug, thiserror::Error)]
pub enum ExtractionError {
#[error("required field `{field}` had no match for selector `{selector}`")]
Missing {
field: &'static str,
selector: &'static str,
},
#[error("CDP error extracting field `{field}`: {source}")]
CdpFailed {
field: &'static str,
#[source]
source: Box<crate::error::BrowserError>,
},
#[error("nested extraction for field `{field}` failed: {source}")]
Nested {
field: &'static str,
#[source]
source: Box<Self>,
},
}
pub trait Extractable: Sized {
fn extract_from(
node: &crate::page::NodeHandle,
) -> impl std::future::Future<Output = Result<Self, ExtractionError>> + Send;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn extraction_error_missing_display() {
let e = ExtractionError::Missing {
field: "foo",
selector: ".bar",
};
let msg = e.to_string();
assert!(
msg.contains("foo"),
"display must contain field name 'foo'; got: {msg}"
);
assert!(
msg.contains(".bar"),
"display must contain selector '.bar'; got: {msg}"
);
}
#[test]
fn extraction_error_nested_display() {
let inner = ExtractionError::Missing {
field: "href",
selector: "a",
};
let e = ExtractionError::Nested {
field: "link",
source: Box::new(inner),
};
let msg = e.to_string();
assert!(
msg.contains("link"),
"display must contain outer field name 'link'; got: {msg}",
);
}
}