agent_first_http/sdk/fetch/
wait.rs1use crate::shared::error::{Error, ErrorCode};
4
5#[derive(Debug, Clone, Default, PartialEq, Eq)]
7pub enum Wait {
8 #[default]
10 Auto,
11 Load,
13 Idle,
15 Selector(String),
20 SelectorVisible(String),
26 Ms(u64),
28}
29
30impl Wait {
31 pub fn parse(s: &str) -> Result<Self, Error> {
32 if s == "auto" {
33 Ok(Self::Auto)
34 } else if s == "load" {
35 Ok(Self::Load)
36 } else if s == "idle" {
37 Ok(Self::Idle)
38 } else if let Some(sel) = s.strip_prefix("selector-visible:") {
39 if sel.is_empty() {
40 Err(Error::new(
41 ErrorCode::InvalidArgument,
42 "--wait selector-visible: requires a non-empty CSS selector",
43 ))
44 } else {
45 Ok(Self::SelectorVisible(sel.to_string()))
46 }
47 } else if let Some(sel) = s.strip_prefix("selector:") {
48 if sel.is_empty() {
49 Err(Error::new(
50 ErrorCode::InvalidArgument,
51 "--wait selector: requires a non-empty CSS selector",
52 ))
53 } else {
54 Ok(Self::Selector(sel.to_string()))
55 }
56 } else if let Some(ms) = s.strip_prefix("ms:") {
57 let n: u64 = ms.parse().map_err(|_| {
58 Error::new(
59 ErrorCode::InvalidArgument,
60 format!("--wait ms: not a u64: {ms:?}"),
61 )
62 })?;
63 Ok(Self::Ms(n))
64 } else {
65 Err(Error::new(
66 ErrorCode::InvalidArgument,
67 format!(
68 "--wait: unknown mode {s:?}; expected \
69 auto|load|idle|selector:<css>|selector-visible:<css>|ms:<n>"
70 ),
71 ))
72 }
73 }
74
75 #[must_use]
76 pub fn mode_name(&self) -> &'static str {
77 match self {
78 Self::Auto => "auto",
79 Self::Load => "load",
80 Self::Idle => "idle",
81 Self::Selector(_) => "selector",
82 Self::SelectorVisible(_) => "selector_visible",
83 Self::Ms(_) => "ms",
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn parses_simple_modes() {
94 assert_eq!(Wait::parse("auto").unwrap(), Wait::Auto);
95 assert_eq!(Wait::parse("load").unwrap(), Wait::Load);
96 assert_eq!(Wait::parse("idle").unwrap(), Wait::Idle);
97 assert_eq!(
98 Wait::parse("selector:#root").unwrap(),
99 Wait::Selector("#root".into())
100 );
101 assert_eq!(
102 Wait::parse("selector-visible:#root").unwrap(),
103 Wait::SelectorVisible("#root".into())
104 );
105 assert_eq!(Wait::parse("ms:250").unwrap(), Wait::Ms(250));
106 }
107
108 #[test]
109 fn rejects_empty_selector() {
110 let err = Wait::parse("selector:").err();
111 assert_eq!(err.map(|e| e.error_code), Some(ErrorCode::InvalidArgument));
112 let err = Wait::parse("selector-visible:").err();
113 assert_eq!(err.map(|e| e.error_code), Some(ErrorCode::InvalidArgument));
114 }
115
116 #[test]
117 fn selector_visible_prefix_does_not_collide_with_selector() {
118 let parsed = Wait::parse("selector-visible:.btn").unwrap();
122 assert_eq!(parsed, Wait::SelectorVisible(".btn".into()));
123 }
124
125 #[test]
126 fn rejects_bad_ms() {
127 let err = Wait::parse("ms:nope").err();
128 assert_eq!(err.map(|e| e.error_code), Some(ErrorCode::InvalidArgument));
129 }
130
131 #[test]
132 fn rejects_unknown_mode() {
133 let err = Wait::parse("forever").err();
134 assert_eq!(err.map(|e| e.error_code), Some(ErrorCode::InvalidArgument));
135 }
136}