use crate::actions::Actions;
use crate::elements::{Element, Form};
use crate::error;
use crate::session::{Cmd, Session, Task};
use crate::wait::Wait;
use crate::wd::{
Capabilities, Locator, NewSessionResponse, NewWindowType, PrintConfiguration,
TimeoutConfiguration, WebDriverStatus, WindowHandle,
};
use base64::Engine;
use http::Method;
use hyper_util::client::legacy::connect;
use serde_json::Value as Json;
use std::convert::{Infallible, TryFrom, TryInto as _};
use std::future::Future;
use tokio::sync::{mpsc, oneshot};
use webdriver::command::{SendKeysParameters, WebDriverCommand};
use webdriver::common::{FrameId, ELEMENT_KEY};
#[cfg_attr(not(feature = "native-tls"), allow(unused_imports))]
use crate::ClientBuilder;
use http_body_util::combinators::BoxBody;
#[derive(Clone, Debug)]
pub struct Client {
pub(crate) tx: mpsc::UnboundedSender<Task>,
pub(crate) new_session_response: Option<NewSessionResponse>,
}
impl Client {
#[cfg(feature = "native-tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
#[deprecated(since = "0.17.1", note = "Prefer ClientBuilder::native")]
pub async fn new(webdriver: &str) -> Result<Self, error::NewSessionError> {
ClientBuilder::native().connect(webdriver).await
}
pub(crate) async fn new_with_connector<C>(
webdriver: &str,
connector: C,
) -> Result<Self, error::NewSessionError>
where
C: connect::Connect + Unpin + 'static + Clone + Send + Sync,
{
Session::with_capabilities_and_connector(webdriver, &Default::default(), connector).await
}
pub async fn with_existing_session<C>(
webdriver: &str,
session_id: &str,
connector: C,
) -> Result<Self, error::NewSessionError>
where
C: connect::Connect + Unpin + 'static + Clone + Send + Sync,
{
let (client, wdb) = Session::create_client_and_parse_url(webdriver, connector).await?;
Session::setup_session(client, wdb, Some(session_id)).await
}
pub async fn with_capabilities_and_connector<C>(
webdriver: &str,
cap: &Capabilities,
connector: C,
) -> Result<Self, error::NewSessionError>
where
C: connect::Connect + Unpin + 'static + Clone + Send + Sync,
{
Session::with_capabilities_and_connector(webdriver, cap, connector).await
}
pub async fn session_id(&self) -> Result<Option<String>, error::CmdError> {
match self.issue(Cmd::GetSessionId).await? {
Json::String(s) => Ok(Some(s)),
Json::Null => Ok(None),
v => unreachable!("response to GetSessionId was not a string: {:?}", v),
}
}
pub async fn set_ua<S: Into<String>>(&self, ua: S) -> Result<(), error::CmdError> {
self.issue(Cmd::SetUa(ua.into())).await?;
Ok(())
}
pub async fn get_ua(&self) -> Result<Option<String>, error::CmdError> {
match self.issue(Cmd::GetUa).await? {
Json::String(s) => Ok(Some(s)),
Json::Null => Ok(None),
v => unreachable!("response to GetSessionId was not a string: {:?}", v),
}
}
pub fn session_creation_response(&self) -> Option<&NewSessionResponse> {
self.new_session_response.as_ref()
}
pub fn capabilities(&self) -> Option<&Capabilities> {
self.new_session_response.as_ref()?.capabilities()
}
pub async fn close(self) -> Result<(), error::CmdError> {
self.issue(Cmd::Shutdown).await?;
Ok(())
}
pub async fn persist(&self) -> Result<(), error::CmdError> {
self.issue(Cmd::Persist).await?;
Ok(())
}
pub fn raw_request(
&self,
) -> RawRequestBuilder<
'_,
fn(http::request::Builder) -> hyper::Request<BoxBody<hyper::body::Bytes, Infallible>>,
> {
RawRequestBuilder::new(self)
}
}
#[derive(Clone, Debug)]
pub struct RawRequestBuilder<'a, F> {
client: &'a Client,
method: Method,
url: String,
cookie_url: Option<String>,
request_modifier: F,
}
fn empty_body(
req: http::request::Builder,
) -> hyper::Request<BoxBody<hyper::body::Bytes, Infallible>> {
req.body(BoxBody::new(http_body_util::Empty::new()))
.unwrap()
}
impl<'a>
RawRequestBuilder<
'a,
fn(http::request::Builder) -> hyper::Request<BoxBody<hyper::body::Bytes, Infallible>>,
>
{
pub fn new(client: &'a Client) -> Self {
RawRequestBuilder {
client,
method: Method::GET,
url: String::new(),
cookie_url: Some("/please_give_me_your_cookies".to_string()),
request_modifier: empty_body,
}
}
}
impl<'a, F> RawRequestBuilder<'a, F> {
pub fn method(&mut self, method: Method) -> &mut Self {
self.method = method;
self
}
pub fn url(&mut self, url: &str) -> &mut Self {
self.url = url.to_string();
self
}
pub fn cookie_url(&mut self, url: &str) -> &mut Self {
self.cookie_url = Some(url.to_string());
self
}
pub fn skip_cookie_navigation(&mut self) -> &mut Self {
self.cookie_url = None;
self
}
}
impl<'a, F> RawRequestBuilder<'a, F> {
#[must_use]
pub fn map_request<F2>(self, f: F2) -> RawRequestBuilder<'a, F2>
where
F2: FnOnce(
http::request::Builder,
) -> hyper::Request<BoxBody<hyper::body::Bytes, Infallible>>,
{
RawRequestBuilder {
client: self.client,
method: self.method,
url: self.url,
cookie_url: self.cookie_url,
request_modifier: f,
}
}
}
impl<'a, F> RawRequestBuilder<'a, F>
where
F: FnOnce(http::request::Builder) -> hyper::Request<BoxBody<hyper::body::Bytes, Infallible>>,
{
pub async fn send(self) -> Result<hyper::Response<hyper::body::Incoming>, error::CmdError> {
let old_url = self.client.current_url_().await?;
let url = old_url.join(&self.url)?;
let cookies = if let Some(cookie_url) = self.cookie_url {
let cookie_url = url.join(&cookie_url)?;
self.client.goto(cookie_url.as_str()).await?;
let cookies = self.client.issue(WebDriverCommand::GetCookies).await?;
self.client.back().await?;
if !cookies.is_array() {
return Err(error::CmdError::NotW3C(cookies));
}
let mut all_ok = true;
let mut jar = Vec::new();
for cookie in cookies.as_array().unwrap() {
if !cookie.is_object() {
all_ok = false;
break;
}
let cookie = cookie.as_object().unwrap();
if !cookie.contains_key("name") || !cookie.contains_key("value") {
all_ok = false;
break;
}
if !cookie["name"].is_string() || !cookie["value"].is_string() {
all_ok = false;
break;
}
jar.push(
cookie::Cookie::new(
cookie["name"].as_str().unwrap().to_owned(),
cookie["value"].as_str().unwrap().to_owned(),
)
.encoded()
.to_string(),
);
}
if !all_ok {
return Err(error::CmdError::NotW3C(cookies));
}
Some(jar.join("; "))
} else {
None
};
let mut req = hyper::Request::builder();
req = req
.method(self.method)
.uri(http::Uri::try_from(url.as_str()).unwrap());
if let Some(cookies) = cookies {
req = req.header(hyper::header::COOKIE, cookies);
}
let ua = self.client.get_ua().await?;
if let Some(ua) = ua {
req = req.header(hyper::header::USER_AGENT, ua);
}
let req = (self.request_modifier)(req);
let (tx, rx) = oneshot::channel();
self.client.issue(Cmd::Raw { req, rsp: tx }).await?;
match rx.await {
Ok(Ok(r)) => Ok(r),
Ok(Err(e)) => Err(e.into()),
Err(e) => unreachable!("Session ended prematurely: {:?}", e),
}
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Status"))]
pub async fn status(&self) -> Result<WebDriverStatus, error::CmdError> {
let res = self.issue(WebDriverCommand::Status).await?;
let status: WebDriverStatus = serde_json::from_value(res)?;
Ok(status)
}
#[cfg_attr(docsrs, doc(alias = "Get Timeouts"))]
pub async fn get_timeouts(&self) -> Result<TimeoutConfiguration, error::CmdError> {
let res = self.issue(WebDriverCommand::GetTimeouts).await?;
let timeouts: TimeoutConfiguration = serde_json::from_value(res)?;
Ok(timeouts)
}
#[cfg_attr(docsrs, doc(alias = "Set Timeouts"))]
#[cfg_attr(docsrs, doc(alias = "Update Timeouts"))]
pub async fn update_timeouts(
&self,
timeouts: TimeoutConfiguration,
) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::SetTimeouts(timeouts.into_params()))
.await?;
Ok(())
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Navigate To"))]
pub async fn goto(&self, url: &str) -> Result<(), error::CmdError> {
let url = url.to_owned();
let base = self.current_url_().await?;
let url = base.join(&url)?;
self.issue(WebDriverCommand::Get(webdriver::command::GetParameters {
url: url.into(),
}))
.await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Get Current URL"))]
pub async fn current_url(&self) -> Result<url::Url, error::CmdError> {
self.current_url_().await
}
pub(crate) async fn current_url_(&self) -> Result<url::Url, error::CmdError> {
let url = self.issue(WebDriverCommand::GetCurrentUrl).await?;
if let Some(url) = url.as_str() {
let url = if url.is_empty() { "about:blank" } else { url };
Ok(url.parse()?)
} else {
Err(error::CmdError::NotW3C(url))
}
}
#[cfg_attr(docsrs, doc(alias = "Back"))]
pub async fn back(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::GoBack).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Forward"))]
pub async fn forward(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::GoForward).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Refresh"))]
pub async fn refresh(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::Refresh).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Get Title"))]
pub async fn title(&self) -> Result<String, error::CmdError> {
let title = self.issue(WebDriverCommand::GetTitle).await?;
if let Json::String(s) = title {
Ok(s)
} else {
Err(error::CmdError::NotW3C(title))
}
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Get Window Handle"))]
pub async fn window(&self) -> Result<WindowHandle, error::CmdError> {
let res = self.issue(WebDriverCommand::GetWindowHandle).await?;
match res {
Json::String(x) => Ok(x.try_into()?),
v => Err(error::CmdError::NotW3C(v)),
}
}
#[cfg_attr(docsrs, doc(alias = "Close Window"))]
pub async fn close_window(&self) -> Result<(), error::CmdError> {
let _res = self.issue(WebDriverCommand::CloseWindow).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Switch To Window"))]
pub async fn switch_to_window(&self, window: WindowHandle) -> Result<(), error::CmdError> {
let params = webdriver::command::SwitchToWindowParameters {
handle: window.into(),
};
let _res = self.issue(WebDriverCommand::SwitchToWindow(params)).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Get Window Handles"))]
pub async fn windows(&self) -> Result<Vec<WindowHandle>, error::CmdError> {
let res = self.issue(WebDriverCommand::GetWindowHandles).await?;
match res {
Json::Array(handles) => handles
.into_iter()
.map(|handle| match handle {
Json::String(x) => Ok(x.try_into()?),
v => Err(error::CmdError::NotW3C(v)),
})
.collect::<Result<Vec<_>, _>>(),
v => Err(error::CmdError::NotW3C(v)),
}
}
#[cfg_attr(docsrs, doc(alias = "New Window"))]
pub async fn new_window(&self, as_tab: bool) -> Result<NewWindowResponse, error::CmdError> {
let type_hint = if as_tab { "tab" } else { "window" }.to_string();
let type_hint = Some(type_hint);
let params = webdriver::command::NewWindowParameters { type_hint };
match self.issue(WebDriverCommand::NewWindow(params)).await? {
Json::Object(mut obj) => {
let handle = match obj
.remove("handle")
.and_then(|x| x.as_str().map(WindowHandle::try_from))
{
Some(Ok(handle)) => handle,
_ => return Err(error::CmdError::NotW3C(Json::Object(obj))),
};
let typ = match obj.get("type").and_then(|x| x.as_str()) {
Some(typ) => match typ {
"tab" => NewWindowType::Tab,
"window" => NewWindowType::Window,
_ => return Err(error::CmdError::NotW3C(Json::Object(obj))),
},
None => return Err(error::CmdError::NotW3C(Json::Object(obj))),
};
Ok(NewWindowResponse { handle, typ })
}
v => Err(error::CmdError::NotW3C(v)),
}
}
#[cfg_attr(docsrs, doc(alias = "Switch To Frame"))]
pub async fn enter_frame(&self, index: u16) -> Result<(), error::CmdError> {
let params = webdriver::command::SwitchToFrameParameters {
id: FrameId::Short(index),
};
self.issue(WebDriverCommand::SwitchToFrame(params)).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Switch To Parent Frame"))]
pub async fn enter_parent_frame(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::SwitchToParentFrame).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Set Window Rect"))]
pub async fn set_window_rect(
&self,
x: u32,
y: u32,
width: u32,
height: u32,
) -> Result<(), error::CmdError> {
let cmd = WebDriverCommand::SetWindowRect(webdriver::command::WindowRectParameters {
x: Some(x as i32),
y: Some(y as i32),
width: Some(width as i32),
height: Some(height as i32),
});
self.issue(cmd).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Get Window Rect"))]
pub async fn get_window_rect(&self) -> Result<(u64, u64, u64, u64), error::CmdError> {
match self.issue(WebDriverCommand::GetWindowRect).await? {
Json::Object(mut obj) => {
let x = match obj.remove("x").and_then(|x| x.as_u64()) {
Some(x) => x,
None => return Err(error::CmdError::NotW3C(Json::Object(obj))),
};
let y = match obj.remove("y").and_then(|y| y.as_u64()) {
Some(y) => y,
None => return Err(error::CmdError::NotW3C(Json::Object(obj))),
};
let width = match obj.remove("width").and_then(|width| width.as_u64()) {
Some(width) => width,
None => return Err(error::CmdError::NotW3C(Json::Object(obj))),
};
let height = match obj.remove("height").and_then(|height| height.as_u64()) {
Some(height) => height,
None => return Err(error::CmdError::NotW3C(Json::Object(obj))),
};
Ok((x, y, width, height))
}
v => Err(error::CmdError::NotW3C(v)),
}
}
#[cfg_attr(docsrs, doc(alias = "Set Window Rect"))]
pub async fn set_window_size(&self, width: u32, height: u32) -> Result<(), error::CmdError> {
let cmd = WebDriverCommand::SetWindowRect(webdriver::command::WindowRectParameters {
x: None,
y: None,
width: Some(width as i32),
height: Some(height as i32),
});
self.issue(cmd).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Get Window Rect"))]
pub async fn get_window_size(&self) -> Result<(u64, u64), error::CmdError> {
let (_, _, width, height) = self.get_window_rect().await?;
Ok((width, height))
}
#[cfg_attr(docsrs, doc(alias = "Set Window Rect"))]
pub async fn set_window_position(&self, x: u32, y: u32) -> Result<(), error::CmdError> {
let cmd = WebDriverCommand::SetWindowRect(webdriver::command::WindowRectParameters {
x: Some(x as i32),
y: Some(y as i32),
width: None,
height: None,
});
self.issue(cmd).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Get Window Rect"))]
pub async fn get_window_position(&self) -> Result<(u64, u64), error::CmdError> {
let (x, y, _, _) = self.get_window_rect().await?;
Ok((x, y))
}
pub async fn maximize_window(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::MaximizeWindow).await?;
Ok(())
}
pub async fn minimize_window(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::MinimizeWindow).await?;
Ok(())
}
pub async fn fullscreen_window(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::FullscreenWindow).await?;
Ok(())
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Find Element"))]
pub async fn find(&self, search: Locator<'_>) -> Result<Element, error::CmdError> {
self.by(search.into_parameters()).await
}
#[cfg_attr(docsrs, doc(alias = "Find Elements"))]
pub async fn find_all(&self, search: Locator<'_>) -> Result<Vec<Element>, error::CmdError> {
let res = self
.issue(WebDriverCommand::FindElements(search.into_parameters()))
.await?;
let array = self.parse_lookup_all(res)?;
Ok(array
.into_iter()
.map(move |e| Element {
client: self.clone(),
element: e,
})
.collect())
}
#[cfg_attr(docsrs, doc(alias = "Get Active Element"))]
pub async fn active_element(&self) -> Result<Element, error::CmdError> {
let res = self.issue(WebDriverCommand::GetActiveElement).await?;
let e = self.parse_lookup(res)?;
Ok(Element {
client: self.clone(),
element: e,
})
}
pub async fn form(&self, search: Locator<'_>) -> Result<Form, error::CmdError> {
let l = search.into_parameters();
let res = self.issue(WebDriverCommand::FindElement(l)).await?;
let f = self.parse_lookup(res)?;
Ok(Form {
client: self.clone(),
form: f,
})
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Get Page Source"))]
pub async fn source(&self) -> Result<String, error::CmdError> {
let src = self.issue(WebDriverCommand::GetPageSource).await?;
if let Some(src) = src.as_str() {
Ok(src.to_string())
} else {
Err(error::CmdError::NotW3C(src))
}
}
#[cfg_attr(docsrs, doc(alias = "Execute Script"))]
pub async fn execute(&self, script: &str, args: Vec<Json>) -> Result<Json, error::CmdError> {
let cmd = webdriver::command::JavascriptCommandParameters {
script: script.to_string(),
args: Some(args),
};
self.issue(WebDriverCommand::ExecuteScript(cmd)).await
}
#[cfg_attr(docsrs, doc(alias = "Execute Async Script"))]
pub async fn execute_async(
&self,
script: &str,
args: Vec<Json>,
) -> Result<Json, error::CmdError> {
let cmd = webdriver::command::JavascriptCommandParameters {
script: script.to_string(),
args: Some(args),
};
self.issue(WebDriverCommand::ExecuteAsyncScript(cmd)).await
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Perform Actions"))]
pub async fn perform_actions(
&self,
actions: impl Into<Actions>,
) -> Result<(), error::CmdError> {
let params = webdriver::command::ActionsParameters {
actions: actions.into().sequences.into_iter().map(|x| x.0).collect(),
};
self.issue(WebDriverCommand::PerformActions(params)).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Release Actions"))]
pub async fn release_actions(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::ReleaseActions).await?;
Ok(())
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Dismiss Alert"))]
pub async fn dismiss_alert(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::DismissAlert).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Accept Alert"))]
pub async fn accept_alert(&self) -> Result<(), error::CmdError> {
self.issue(WebDriverCommand::AcceptAlert).await?;
Ok(())
}
#[cfg_attr(docsrs, doc(alias = "Get Alert Text"))]
pub async fn get_alert_text(&self) -> Result<String, error::CmdError> {
let res = self.issue(WebDriverCommand::GetAlertText).await?;
if let Json::String(s) = res {
Ok(s)
} else {
Err(error::CmdError::NotW3C(res))
}
}
#[cfg_attr(docsrs, doc(alias = "Send Alert Text"))]
pub async fn send_alert_text(&self, text: &str) -> Result<(), error::CmdError> {
let params = SendKeysParameters {
text: text.to_string(),
};
self.issue(WebDriverCommand::SendAlertText(params)).await?;
Ok(())
}
}
impl Client {
#[cfg_attr(docsrs, doc(alias = "Take Screenshot"))]
pub async fn screenshot(&self) -> Result<Vec<u8>, error::CmdError> {
let src = self.issue(WebDriverCommand::TakeScreenshot).await?;
if let Some(src) = src.as_str() {
base64::engine::general_purpose::STANDARD
.decode(src)
.map_err(error::CmdError::ImageDecodeError)
} else {
Err(error::CmdError::NotW3C(src))
}
}
pub async fn print(
&self,
print_configuration: PrintConfiguration,
) -> Result<Vec<u8>, error::CmdError> {
let src = self
.issue(WebDriverCommand::Print(print_configuration.into_params()))
.await?;
if let Some(src) = src.as_str() {
base64::engine::general_purpose::STANDARD
.decode(src)
.map_err(error::CmdError::PdfDecodeError)
} else {
Err(error::CmdError::NotW3C(src))
}
}
}
impl Client {
#[deprecated(
since = "0.17.5",
note = "Prefer client.wait() or while !is_ready(self).await? {}."
)]
pub async fn wait_for<F, FF>(&self, mut is_ready: F) -> Result<(), error::CmdError>
where
F: FnMut(&Client) -> FF,
FF: Future<Output = Result<bool, error::CmdError>>,
{
while !is_ready(self).await? {}
Ok(())
}
#[deprecated(since = "0.17.5", note = "Use client.wait().for_element(locator).")]
pub async fn wait_for_find(&self, search: Locator<'_>) -> Result<Element, error::CmdError> {
self.wait().forever().for_element(search).await
}
#[deprecated(
since = "0.17.5",
note = "Use client.wait().for_url(current) if current.is_some() or a while loop otherwise."
)]
pub async fn wait_for_navigation(
&self,
current: Option<url::Url>,
) -> Result<(), error::CmdError> {
let current = match current {
Some(current) => current,
None => self.current_url_().await?,
};
#[allow(deprecated)]
self.wait_for(move |c| {
let current = current.clone();
let c = c.clone();
async move { Ok(c.current_url().await? != current) }
})
.await
}
}
impl Client {
pub async fn raw_client_for(
&self,
method: Method,
url: &str,
) -> Result<hyper::Response<hyper::body::Incoming>, error::CmdError> {
let mut builder = self.raw_request();
builder.method(method).url(url);
builder.send().await
}
pub async fn with_raw_client_for<F>(
&self,
method: Method,
url: &str,
before: F,
) -> Result<hyper::Response<hyper::body::Incoming>, error::CmdError>
where
F: FnOnce(
http::request::Builder,
) -> hyper::Request<BoxBody<hyper::body::Bytes, Infallible>>,
{
let mut builder = self.raw_request();
builder.method(method).url(url);
builder.map_request(before).send().await
}
}
impl Client {
pub fn wait(&self) -> Wait<'_> {
Wait::new(self)
}
}
impl Client {
pub(crate) async fn by(
&self,
locator: webdriver::command::LocatorParameters,
) -> Result<Element, error::CmdError> {
let res = self.issue(WebDriverCommand::FindElement(locator)).await?;
let e = self.parse_lookup(res)?;
Ok(Element {
client: self.clone(),
element: e,
})
}
pub(crate) fn parse_lookup(
&self,
res: Json,
) -> Result<webdriver::common::WebElement, error::CmdError> {
let mut res = match res {
Json::Object(o) => o,
res => return Err(error::CmdError::NotW3C(res)),
};
if !res.contains_key(ELEMENT_KEY) {
return Err(error::CmdError::NotW3C(Json::Object(res)));
}
match res.remove(ELEMENT_KEY) {
Some(Json::String(wei)) => {
return Ok(webdriver::common::WebElement(wei));
}
Some(v) => {
res.insert(ELEMENT_KEY.to_string(), v);
}
None => {}
}
Err(error::CmdError::NotW3C(Json::Object(res)))
}
pub(crate) fn parse_lookup_all(
&self,
res: Json,
) -> Result<Vec<webdriver::common::WebElement>, error::CmdError> {
let res = match res {
Json::Array(a) => a,
res => return Err(error::CmdError::NotW3C(res)),
};
let mut array = Vec::new();
for json in res {
let e = self.parse_lookup(json)?;
array.push(e);
}
Ok(array)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NewWindowResponse {
pub handle: WindowHandle,
pub typ: NewWindowType,
}