1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::sync::Arc;

use crate::{
    common::{
        command::Command,
        connection_common::{unwrap, unwrap_vec},
    },
    error::{WebDriverError, WebDriverResult},
    sync::{webelement::unwrap_element_sync, Alert, RemoteConnectionSync, WebElement},
    By, SessionId, WindowHandle,
};

/// Struct for switching between frames/windows/alerts.
pub struct SwitchTo {
    session_id: SessionId,
    conn: Arc<RemoteConnectionSync>,
}

impl SwitchTo {
    /// Create a new SwitchTo struct. This is typically created internally
    /// via a call to `WebDriver::switch_to()`.
    pub fn new(session_id: SessionId, conn: Arc<RemoteConnectionSync>) -> Self {
        SwitchTo { session_id, conn }
    }

    /// Return the element with focus, or BODY if nothing has focus.
    pub fn active_element(&self) -> WebDriverResult<WebElement> {
        let v = self
            .conn
            .execute(Command::GetActiveElement(&self.session_id))?;
        unwrap_element_sync(self.conn.clone(), self.session_id.clone(), &v["value"])
    }

    /// Return Alert struct for processing the active alert on the page.
    pub fn alert(&self) -> Alert {
        Alert::new(self.session_id.clone(), self.conn.clone())
    }

    /// Switch focus to the default frame.
    pub fn default_content(&self) -> WebDriverResult<()> {
        self.conn
            .execute(Command::SwitchToFrameDefault(&self.session_id))
            .map(|_| ())
    }

    /// Switch focus to the frame by index.
    pub fn frame_number(&self, frame_number: u16) -> WebDriverResult<()> {
        self.conn
            .execute(Command::SwitchToFrameNumber(&self.session_id, frame_number))
            .map(|_| ())
    }

    /// Switch focus to the element with the specified Id or Name.
    ///
    /// This will attempt to find the element first by Id, and if that fails,
    /// by Name.
    pub fn frame_name(&self, frame_name: &str) -> WebDriverResult<()> {
        let v = match self
            .conn
            .execute(Command::FindElement(&self.session_id, By::Id(frame_name)))
        {
            Ok(elem) => elem,
            Err(WebDriverError::NoSuchElement(_)) => self
                .conn
                .execute(Command::FindElement(&self.session_id, By::Name(frame_name)))?,
            Err(e) => return Err(e),
        };
        let elem = unwrap_element_sync(self.conn.clone(), self.session_id.clone(), &v["value"])?;
        self.frame_element(elem)
    }

    /// Switch focus to the specified element.
    pub fn frame_element(&self, frame_element: WebElement) -> WebDriverResult<()> {
        self.conn
            .execute(Command::SwitchToFrameElement(
                &self.session_id,
                &frame_element.element_id,
            ))
            .map(|_| ())
    }

    /// Switch focus to the parent frame.
    pub fn parent_frame(&self) -> WebDriverResult<()> {
        self.conn
            .execute(Command::SwitchToParentFrame(&self.session_id))
            .map(|_| ())
    }

    /// Switch focus to the specified window.
    pub fn window(&self, handle: &WindowHandle) -> WebDriverResult<()> {
        self.conn
            .execute(Command::SwitchToWindow(&self.session_id, handle))
            .map(|_| ())
    }

    /// Switch focus to the window with the specified name.
    pub fn window_name(&self, name: &str) -> WebDriverResult<()> {
        let original_handle = self
            .conn
            .execute(Command::GetWindowHandle(&self.session_id))
            .map(|v| unwrap::<String>(&v["value"]))??;

        let v = self
            .conn
            .execute(Command::GetWindowHandles(&self.session_id))?;
        let handles: Vec<String> = unwrap_vec(&v["value"])?;
        for handle in handles {
            self.window(&WindowHandle::from(handle))?;
            let current_name = self
                .conn
                .execute(Command::ExecuteScript(
                    &self.session_id,
                    String::from("return window.name"),
                    Vec::new(),
                ))
                .map(|v| v["value"].clone())?;

            if let Some(x) = current_name.as_str() {
                if x == name {
                    return Ok(());
                }
            }
        }

        self.window(&WindowHandle::from(original_handle))?;
        Err(WebDriverError::NotFoundError(format!(
            "No window handle found matching '{}'",
            name
        )))
    }
}