1pub type BrowserResult<T> = Result<T, BrowserError>;
9
10#[derive(Debug, thiserror::Error)]
12pub enum BrowserError {
13 #[error("browser error: {reason}")]
15 Browser {
16 reason: String,
18 },
19
20 #[error("navigation error: {reason}")]
22 Navigation {
23 reason: String,
25 },
26
27 #[error("interaction error: {reason}")]
29 Interaction {
30 reason: String,
32 },
33
34 #[error("auth error: {reason}")]
36 Auth {
37 reason: String,
39 },
40
41 #[error("config error: {reason}")]
43 Config {
44 reason: String,
46 },
47
48 #[error("timeout: {reason}")]
50 Timeout {
51 reason: String,
53 },
54}
55
56impl BrowserError {
57 pub fn browser(reason: impl Into<String>) -> Self {
59 Self::Browser {
60 reason: reason.into(),
61 }
62 }
63
64 pub fn navigation(reason: impl Into<String>) -> Self {
66 Self::Navigation {
67 reason: reason.into(),
68 }
69 }
70
71 pub fn interaction(reason: impl Into<String>) -> Self {
73 Self::Interaction {
74 reason: reason.into(),
75 }
76 }
77
78 pub fn auth(reason: impl Into<String>) -> Self {
80 Self::Auth {
81 reason: reason.into(),
82 }
83 }
84
85 pub fn config(reason: impl Into<String>) -> Self {
87 Self::Config {
88 reason: reason.into(),
89 }
90 }
91
92 pub fn timeout(reason: impl Into<String>) -> Self {
94 Self::Timeout {
95 reason: reason.into(),
96 }
97 }
98
99 #[must_use]
101 pub const fn is_transient(&self) -> bool {
102 matches!(
103 self,
104 Self::Browser { .. } | Self::Navigation { .. } | Self::Timeout { .. }
105 )
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn transient_classification() {
115 assert!(BrowserError::browser("x").is_transient());
116 assert!(BrowserError::timeout("x").is_transient());
117 assert!(!BrowserError::auth("x").is_transient());
118 assert!(!BrowserError::config("x").is_transient());
119 }
120
121 #[test]
122 fn display_includes_reason() {
123 assert_eq!(
124 BrowserError::interaction("no element").to_string(),
125 "interaction error: no element"
126 );
127 }
128}