1use super::command::command_retry_options;
2use super::selectors::normalize_selector_for_transport;
3use super::tab::ensure_tab_open;
4use super::types::*;
5use crate::proto::{self, context_session_command::Command, context_session_event::Event};
6
7impl Tab {
8 async fn capture(
9 &self,
10 kind: proto::CaptureKind,
11 selector: &str,
12 attribute_name: &str,
13 options: CommandOptions,
14 ) -> Result<proto::CaptureResolvedEvent> {
15 let mut state = self.inner.state.lock().await;
16 let handle = self.ensure_handle(&mut state).await?;
17 ensure_tab_open(handle, &self.inner.session_id)?;
18 handle
19 .command_tx
20 .send(proto::ContextSessionCommand {
21 surface_session_id: self.inner.surface_session_id.clone(),
22 context_session_id: self.inner.session_id.clone(),
23 command: Some(Command::Capture(proto::CaptureCommand {
24 kind: kind as i32,
25 css_selector: if selector.is_empty() {
26 String::new()
27 } else {
28 normalize_selector_for_transport(selector)
29 },
30 attribute_name: attribute_name.into(),
31 retry_options: command_retry_options(options.timeout_ms),
32 })),
33 })
34 .await
35 .map_err(|_| Error::new("failed to send capture command"))?;
36 loop {
37 let event = handle
38 .events
39 .message()
40 .await?
41 .ok_or_else(|| Error::new("page session closed while capturing"))?;
42 match event.event {
43 Some(Event::CaptureResolved(result)) => return Ok(result),
44 Some(Event::Error(error)) => return Err(Error::new(error.message)),
45 Some(Event::Closed(_)) => {
46 handle.closed = true;
47 return Err(Error::new("page session closed while capturing"));
48 }
49 _ => {}
50 }
51 }
52 }
53 pub async fn url(&self) -> Result<String> {
54 self.url_with_options(CommandOptions::default()).await
55 }
56 pub async fn url_with_options(&self, options: CommandOptions) -> Result<String> {
57 let r = self
58 .capture(proto::CaptureKind::Url, "", "", options)
59 .await?;
60 Ok(r.value.unwrap_or_default())
61 }
62 pub async fn input_value(&self, selector: impl Into<String>) -> Result<String> {
63 self.input_value_with_options(selector, CommandOptions::default())
64 .await
65 }
66 pub async fn input_value_with_options(
67 &self,
68 selector: impl Into<String>,
69 options: CommandOptions,
70 ) -> Result<String> {
71 let r = self
72 .capture(
73 proto::CaptureKind::InputValue,
74 &selector.into(),
75 "",
76 options,
77 )
78 .await?;
79 Ok(r.value.unwrap_or_default())
80 }
81 pub async fn selected_options(
82 &self,
83 selector: impl Into<String>,
84 ) -> Result<Vec<CapturedOption>> {
85 self.selected_options_with_options(selector, CommandOptions::default())
86 .await
87 }
88 pub async fn selected_options_with_options(
89 &self,
90 selector: impl Into<String>,
91 options: CommandOptions,
92 ) -> Result<Vec<CapturedOption>> {
93 let r = self
94 .capture(
95 proto::CaptureKind::SelectedOptions,
96 &selector.into(),
97 "",
98 options,
99 )
100 .await?;
101 Ok(r.selected_options
102 .into_iter()
103 .map(|o| CapturedOption {
104 value: o.value,
105 label: o.label,
106 index: o.index,
107 })
108 .collect())
109 }
110 pub async fn selected_text(&self, selector: impl Into<String>) -> Result<Option<String>> {
111 self.selected_text_with_options(selector, CommandOptions::default())
112 .await
113 }
114 pub async fn selected_text_with_options(
115 &self,
116 selector: impl Into<String>,
117 options: CommandOptions,
118 ) -> Result<Option<String>> {
119 let r = self
120 .capture(
121 proto::CaptureKind::SelectedText,
122 &selector.into(),
123 "",
124 options,
125 )
126 .await?;
127 Ok(r.value)
128 }
129 pub async fn is_checked(&self, selector: impl Into<String>) -> Result<bool> {
130 self.is_checked_with_options(selector, CommandOptions::default())
131 .await
132 }
133 pub async fn is_checked_with_options(
134 &self,
135 selector: impl Into<String>,
136 options: CommandOptions,
137 ) -> Result<bool> {
138 let r = self
139 .capture(proto::CaptureKind::Checked, &selector.into(), "", options)
140 .await?;
141 Ok(r.checked.unwrap_or(false))
142 }
143 pub async fn get_attribute(
144 &self,
145 selector: impl Into<String>,
146 name: impl Into<String>,
147 ) -> Result<Option<String>> {
148 self.get_attribute_with_options(selector, name, CommandOptions::default())
149 .await
150 }
151 pub async fn get_attribute_with_options(
152 &self,
153 selector: impl Into<String>,
154 name: impl Into<String>,
155 options: CommandOptions,
156 ) -> Result<Option<String>> {
157 let r = self
158 .capture(
159 proto::CaptureKind::Attribute,
160 &selector.into(),
161 &name.into(),
162 options,
163 )
164 .await?;
165 Ok(r.value)
166 }
167 pub async fn bounding_box(&self, selector: impl Into<String>) -> Result<Option<BoundingBox>> {
168 self.bounding_box_with_options(selector, CommandOptions::default())
169 .await
170 }
171 pub async fn bounding_box_with_options(
172 &self,
173 selector: impl Into<String>,
174 options: CommandOptions,
175 ) -> Result<Option<BoundingBox>> {
176 let r = self
177 .capture(
178 proto::CaptureKind::BoundingBox,
179 &selector.into(),
180 "",
181 options,
182 )
183 .await?;
184 Ok(r.bounding_box.map(|b| BoundingBox {
185 x: b.x,
186 y: b.y,
187 width: b.width,
188 height: b.height,
189 }))
190 }
191}
192impl Locator {
193 pub async fn input_value(&self) -> Result<String> {
194 self.input_value_with_options(CommandOptions::default())
195 .await
196 }
197 pub async fn input_value_with_options(&self, options: CommandOptions) -> Result<String> {
198 self.page
199 .input_value_with_options(self.selector.clone(), options)
200 .await
201 }
202 pub async fn selected_options(&self) -> Result<Vec<CapturedOption>> {
203 self.selected_options_with_options(CommandOptions::default())
204 .await
205 }
206 pub async fn selected_options_with_options(
207 &self,
208 options: CommandOptions,
209 ) -> Result<Vec<CapturedOption>> {
210 self.page
211 .selected_options_with_options(self.selector.clone(), options)
212 .await
213 }
214 pub async fn selected_text(&self) -> Result<Option<String>> {
215 self.selected_text_with_options(CommandOptions::default())
216 .await
217 }
218 pub async fn selected_text_with_options(
219 &self,
220 options: CommandOptions,
221 ) -> Result<Option<String>> {
222 self.page
223 .selected_text_with_options(self.selector.clone(), options)
224 .await
225 }
226 pub async fn is_checked(&self) -> Result<bool> {
227 self.is_checked_with_options(CommandOptions::default())
228 .await
229 }
230 pub async fn is_checked_with_options(&self, options: CommandOptions) -> Result<bool> {
231 self.page
232 .is_checked_with_options(self.selector.clone(), options)
233 .await
234 }
235 pub async fn get_attribute(&self, name: impl Into<String>) -> Result<Option<String>> {
236 self.get_attribute_with_options(name, CommandOptions::default())
237 .await
238 }
239 pub async fn get_attribute_with_options(
240 &self,
241 name: impl Into<String>,
242 options: CommandOptions,
243 ) -> Result<Option<String>> {
244 self.page
245 .get_attribute_with_options(self.selector.clone(), name, options)
246 .await
247 }
248 pub async fn bounding_box(&self) -> Result<Option<BoundingBox>> {
249 self.bounding_box_with_options(CommandOptions::default())
250 .await
251 }
252 pub async fn bounding_box_with_options(
253 &self,
254 options: CommandOptions,
255 ) -> Result<Option<BoundingBox>> {
256 self.page
257 .bounding_box_with_options(self.selector.clone(), options)
258 .await
259 }
260}