Skip to main content

allwright/
client_capture.rs

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}