thirtyfour/
switch_to.rs

1use crate::common::command::Command;
2use crate::error::WebDriverErrorInfo;
3use crate::session::handle::SessionHandle;
4use crate::WindowHandle;
5use crate::{
6    error::{WebDriverError, WebDriverResult},
7    Alert, WebElement,
8};
9use std::sync::Arc;
10
11/// Struct for switching between frames/windows/alerts.
12#[derive(Debug)]
13pub struct SwitchTo {
14    handle: Arc<SessionHandle>,
15}
16
17impl SwitchTo {
18    /// Create a new SwitchTo struct. This is typically created internally
19    /// via a call to `WebDriver::switch_to()`.
20    pub fn new(handle: Arc<SessionHandle>) -> Self {
21        Self {
22            handle,
23        }
24    }
25
26    /// Get the active element for this session.
27    #[deprecated(
28        since = "0.30.0",
29        note = "This method has been moved to WebDriver::active_element()"
30    )]
31    pub async fn active_element(self) -> WebDriverResult<WebElement> {
32        self.handle.active_element().await
33    }
34
35    /// Switch to the specified alert.
36    #[deprecated(
37        since = "0.30.0",
38        note = "This method has been deprecated. See the `Alert` module for new method names"
39    )]
40    pub fn alert(self) -> Alert {
41        Alert::new(self.handle)
42    }
43
44    /// Switch to the default frame.
45    #[deprecated(
46        since = "0.30.0",
47        note = "This method has been moved to WebDriver::enter_default_frame()"
48    )]
49    pub async fn default_content(self) -> WebDriverResult<()> {
50        self.handle.enter_default_frame().await
51    }
52
53    /// Switch to the frame specified at the index.
54    #[deprecated(since = "0.30.0", note = "This method has been moved to WebDriver::enter_frame()")]
55    pub async fn frame_number(self, frame_number: u16) -> WebDriverResult<()> {
56        self.handle.enter_frame(frame_number).await
57    }
58
59    /// Switch to the frame contained within the element.
60    #[deprecated(
61        since = "0.30.0",
62        note = "This method has been moved to WebElement::enter_frame()"
63    )]
64    pub async fn frame_element(self, frame_element: &WebElement) -> WebDriverResult<()> {
65        frame_element.clone().enter_frame().await
66    }
67
68    /// Switch to the parent of the frame the client is currently contained within.
69    #[deprecated(
70        since = "0.30.0",
71        note = "This method has been moved to WebDriver::enter_parent_frame()"
72    )]
73    pub async fn parent_frame(self) -> WebDriverResult<()> {
74        self.handle.enter_parent_frame().await?;
75        Ok(())
76    }
77
78    /// Create a new window.
79    #[deprecated(since = "0.30.0", note = "This method has been moved to WebDriver::new_window()")]
80    pub async fn new_window(self) -> WebDriverResult<WindowHandle> {
81        self.handle.new_window().await
82    }
83
84    /// Create a new tab.
85    #[deprecated(since = "0.30.0", note = "This method has been moved to WebDriver::new_tab()")]
86    pub async fn new_tab(self) -> WebDriverResult<WindowHandle> {
87        self.handle.new_tab().await
88    }
89
90    /// Switch to the specified window.
91    #[deprecated(
92        since = "0.30.0",
93        note = "This method has been moved to WebDriver::switch_to_window()"
94    )]
95    pub async fn window(self, handle: WindowHandle) -> WebDriverResult<()> {
96        self.handle.switch_to_window(handle).await
97    }
98
99    /// Switch to the specified named window.
100    #[deprecated(
101        since = "0.30.0",
102        note = "This method has been moved to WebDriver::switch_to_named_window()"
103    )]
104    pub async fn window_name(self, name: &str) -> WebDriverResult<()> {
105        let original_handle = self.handle.window().await?;
106        let handles = self.handle.windows().await?;
107        for handle in handles {
108            self.handle.switch_to_window(handle).await?;
109            let ret = self.handle.execute(r#"return window.name;"#, Vec::new()).await?;
110            let current_name: String = ret.convert()?;
111            if current_name == name {
112                return Ok(());
113            }
114        }
115
116        self.handle.switch_to_window(original_handle).await?;
117        Err(WebDriverError::NoSuchWindow(WebDriverErrorInfo::new(format!(
118            "unable to find named window: {name}"
119        ))))
120    }
121}
122
123impl SessionHandle {
124    /// Return the element with focus, or the `<body>` element if nothing has focus.
125    ///
126    /// # Example:
127    /// ```no_run
128    /// # use thirtyfour::prelude::*;
129    /// # use thirtyfour::support::block_on;
130    /// #
131    /// # fn main() -> WebDriverResult<()> {
132    /// #     block_on(async {
133    /// #         let caps = DesiredCapabilities::chrome();
134    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
135    /// // If no element has focus, active_element() will return the body tag.
136    /// let active_elem = driver.active_element().await?;
137    /// assert_eq!(active_elem.tag_name().await?, "body");
138    ///
139    /// // Now let's manually focus an element and try active_element() again.
140    /// let elem = driver.find(By::Id("my-element-id")).await?;
141    /// elem.focus().await?;
142    ///
143    /// // And fetch the active element again.
144    /// let active_elem = driver.active_element().await?;
145    /// assert_eq!(active_elem.element_id(), elem.element_id());
146    /// #         driver.quit().await?;
147    /// #         Ok(())
148    /// #     })
149    /// # }
150    /// ```
151    pub async fn active_element(self: &Arc<SessionHandle>) -> WebDriverResult<WebElement> {
152        let r = self.cmd(Command::GetActiveElement).await?;
153        r.element(self.clone())
154    }
155
156    /// Switch to the default frame.
157    ///
158    /// # Example:
159    /// ```no_run
160    /// # use thirtyfour::prelude::*;
161    /// # use thirtyfour::support::block_on;
162    /// #
163    /// # fn main() -> WebDriverResult<()> {
164    /// #     block_on(async {
165    /// #         let caps = DesiredCapabilities::chrome();
166    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
167    /// // Enter the first iframe.
168    /// driver.enter_frame(0).await?;
169    /// // We are now inside the iframe.
170    /// driver.find(By::Id("button1")).await?;
171    /// driver.enter_default_frame().await?;
172    /// // We are now back in the original window.
173    /// #         driver.quit().await?;
174    /// #         Ok(())
175    /// #     })
176    /// # }
177    /// ```
178    pub async fn enter_default_frame(&self) -> WebDriverResult<()> {
179        self.cmd(Command::SwitchToFrameDefault).await?;
180        Ok(())
181    }
182
183    /// Switch to an iframe by index. The first iframe on the page has index 0.
184    ///
185    /// # Example:
186    /// ```no_run
187    /// # use thirtyfour::prelude::*;
188    /// # use thirtyfour::support::block_on;
189    /// #
190    /// # fn main() -> WebDriverResult<()> {
191    /// #     block_on(async {
192    /// #         let caps = DesiredCapabilities::chrome();
193    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
194    /// // Enter the first iframe.
195    /// driver.enter_frame(0).await?;
196    /// // We can now search for elements within the iframe.
197    /// let elem = driver.find(By::Id("button1")).await?;
198    /// elem.click().await?;
199    /// #         driver.quit().await?;
200    /// #         Ok(())
201    /// #     })
202    /// # }
203    /// ```
204    pub async fn enter_frame(&self, frame_number: u16) -> WebDriverResult<()> {
205        self.cmd(Command::SwitchToFrameNumber(frame_number)).await?;
206        Ok(())
207    }
208
209    /// Switch to the parent frame.
210    ///
211    /// # Example:
212    /// ```no_run
213    /// # use thirtyfour::prelude::*;
214    /// # use thirtyfour::support::block_on;
215    /// #
216    /// # fn main() -> WebDriverResult<()> {
217    /// #     block_on(async {
218    /// #         let caps = DesiredCapabilities::chrome();
219    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
220    /// // Find the iframe element and enter the iframe.
221    /// let elem_iframe = driver.find(By::Id("iframeid1")).await?;
222    /// elem_iframe.enter_frame().await?;
223    /// // We can now search for elements within the iframe.
224    /// let elem = driver.find(By::Id("button1")).await?;
225    /// elem.click().await?;
226    /// // Now switch back to the parent frame.
227    /// driver.enter_parent_frame().await?;
228    /// // We are now back in the parent document.
229    /// #         driver.quit().await?;
230    /// #         Ok(())
231    /// #     })
232    /// # }
233    /// ```
234    pub async fn enter_parent_frame(&self) -> WebDriverResult<()> {
235        self.cmd(Command::SwitchToParentFrame).await?;
236        Ok(())
237    }
238
239    /// Switch to the specified window.
240    ///
241    /// # Example:
242    /// ```no_run
243    /// # use thirtyfour::prelude::*;
244    /// # use thirtyfour::support::block_on;
245    /// #
246    /// # fn main() -> WebDriverResult<()> {
247    /// #     block_on(async {
248    /// #         let caps = DesiredCapabilities::chrome();
249    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
250    /// // Open a new tab.
251    /// driver.new_tab().await?;
252    ///
253    /// // Get window handles and switch to the new tab.
254    /// let handles = driver.windows().await?;
255    /// driver.switch_to_window(handles[1].clone()).await?;
256    ///
257    /// // We are now controlling the new tab.
258    /// driver.goto("https://www.rust-lang.org").await?;
259    /// #         driver.quit().await?;
260    /// #         Ok(())
261    /// #     })
262    /// # }
263    /// ```
264    pub async fn switch_to_window(&self, handle: WindowHandle) -> WebDriverResult<()> {
265        self.cmd(Command::SwitchToWindow(handle)).await?;
266        Ok(())
267    }
268
269    /// Switch to the window with the specified name. This uses the `window.name` property.
270    /// You can set a window name via `WebDriver::set_window_name("someName").await?`.
271    ///
272    /// # Example:
273    /// ```no_run
274    /// # use thirtyfour::prelude::*;
275    /// # use thirtyfour::support::block_on;
276    /// #
277    /// # fn main() -> WebDriverResult<()> {
278    /// #     block_on(async {
279    /// #         let caps = DesiredCapabilities::chrome();
280    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
281    /// // Set main window name so we can switch back easily.
282    /// driver.set_window_name("mywindow").await?;
283    ///
284    /// // Open a new tab.
285    /// driver.new_tab().await?;
286    ///
287    /// // Get window handles and switch to the new tab.
288    /// let handles = driver.windows().await?;
289    /// driver.switch_to_window(handles[1].clone()).await?;
290    ///
291    /// // We are now controlling the new tab.
292    /// assert_eq!(driver.title().await?, "");
293    /// driver.switch_to_named_window("mywindow").await?;
294    ///
295    /// // We are now back in the original tab.
296    /// #         driver.quit().await?;
297    /// #         Ok(())
298    /// #     })
299    /// # }
300    /// ```
301    pub async fn switch_to_named_window(
302        self: &Arc<SessionHandle>,
303        name: &str,
304    ) -> WebDriverResult<()> {
305        let original_handle = self.window().await?;
306        let handles = self.windows().await?;
307        for handle in handles {
308            self.switch_to_window(handle).await?;
309            let ret = self.execute(r#"return window.name;"#, Vec::new()).await?;
310            let current_name: String = ret.convert()?;
311            if current_name == name {
312                return Ok(());
313            }
314        }
315
316        self.switch_to_window(original_handle).await?;
317        Err(WebDriverError::NoSuchWindow(WebDriverErrorInfo::new(format!(
318            "unable to find named window: {name}"
319        ))))
320    }
321
322    /// Switch to a new window.
323    ///
324    /// # Example:
325    /// ```no_run
326    /// # use thirtyfour::prelude::*;
327    /// # use thirtyfour::support::block_on;
328    /// #
329    /// # fn main() -> WebDriverResult<()> {
330    /// #     block_on(async {
331    /// #         let caps = DesiredCapabilities::chrome();
332    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
333    /// // Open a new window.
334    /// let handle = driver.new_window().await?;
335    /// #         driver.quit().await?;
336    /// #         Ok(())
337    /// #     })
338    /// # }
339    /// ```
340    pub async fn new_window(&self) -> WebDriverResult<WindowHandle> {
341        self.cmd(Command::NewWindow).await?.value()
342    }
343
344    /// Switch to a new tab.
345    ///
346    /// # Example:
347    /// ```no_run
348    /// # use thirtyfour::prelude::*;
349    /// # use thirtyfour::support::block_on;
350    /// #
351    /// # fn main() -> WebDriverResult<()> {
352    /// #     block_on(async {
353    /// #         let caps = DesiredCapabilities::chrome();
354    /// #         let driver = WebDriver::new("http://localhost:4444", caps).await?;
355    /// // Open a new tab in the current window.
356    /// let handle = driver.new_tab().await?;
357    /// #         driver.quit().await?;
358    /// #         Ok(())
359    /// #     })
360    /// # }
361    /// ```
362    pub async fn new_tab(&self) -> WebDriverResult<WindowHandle> {
363        self.cmd(Command::NewTab).await?.value()
364    }
365}