pub type BrowserResult<T> = Result<T, BrowserError>;
#[derive(Debug, thiserror::Error)]
pub enum BrowserError {
#[error("browser error: {reason}")]
Browser {
reason: String,
},
#[error("navigation error: {reason}")]
Navigation {
reason: String,
},
#[error("interaction error: {reason}")]
Interaction {
reason: String,
},
#[error("auth error: {reason}")]
Auth {
reason: String,
},
#[error("config error: {reason}")]
Config {
reason: String,
},
#[error("timeout: {reason}")]
Timeout {
reason: String,
},
}
impl BrowserError {
pub fn browser(reason: impl Into<String>) -> Self {
Self::Browser {
reason: reason.into(),
}
}
pub fn navigation(reason: impl Into<String>) -> Self {
Self::Navigation {
reason: reason.into(),
}
}
pub fn interaction(reason: impl Into<String>) -> Self {
Self::Interaction {
reason: reason.into(),
}
}
pub fn auth(reason: impl Into<String>) -> Self {
Self::Auth {
reason: reason.into(),
}
}
pub fn config(reason: impl Into<String>) -> Self {
Self::Config {
reason: reason.into(),
}
}
pub fn timeout(reason: impl Into<String>) -> Self {
Self::Timeout {
reason: reason.into(),
}
}
#[must_use]
pub const fn is_transient(&self) -> bool {
matches!(
self,
Self::Browser { .. } | Self::Navigation { .. } | Self::Timeout { .. }
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn transient_classification() {
assert!(BrowserError::browser("x").is_transient());
assert!(BrowserError::timeout("x").is_transient());
assert!(!BrowserError::auth("x").is_transient());
assert!(!BrowserError::config("x").is_transient());
}
#[test]
fn display_includes_reason() {
assert_eq!(
BrowserError::interaction("no element").to_string(),
"interaction error: no element"
);
}
}