geckodriver: Broken implementation of most of what's in the spec (and some things that aren't) except Actions

Source-Repo: https://github.com/mozilla/geckodriver
Source-Revision: 14215bccc7dce187ee96ab111bc545deda2c7e8b

--HG--
extra : rebase_source : 452b949d8be2903c6d5522b9cf91230c0a4b8e82
This commit is contained in:
James Graham 2015-01-06 11:14:55 +00:00
Родитель 97d7fef217
Коммит ba54211b54
5 изменённых файлов: 697 добавлений и 172 удалений

Просмотреть файл

@ -1,16 +1,15 @@
use core::u16;
use std::collections::TreeMap;
use serialize::json;
use serialize::json::{ToJson, Json};
use regex::Captures;
use common::{WebDriverResult, WebDriverError, ErrorStatus};
use common::{WebDriverResult, WebDriverError, ErrorStatus, Nullable, WebElement, FrameId, LocatorStrategy};
use response::Date; //TODO: Put all these types in a specific file
use messagebuilder::MatchType;
#[deriving(PartialEq)]
pub enum WebDriverCommand {
GetMarionetteId, //TODO: move this
NewSession,
DeleteSession,
Get(GetParameters),
@ -22,7 +21,6 @@ pub enum WebDriverCommand {
GetWindowHandle,
GetWindowHandles,
Close,
Timeouts(TimeoutsParameters),
SetWindowSize(WindowSizeParameters),
GetWindowSize,
MaximizeWindow,
@ -30,6 +28,8 @@ pub enum WebDriverCommand {
SwitchToWindow(SwitchToWindowParameters),
SwitchToFrame(SwitchToFrameParameters),
SwitchToParentFrame,
FindElement(LocatorParameters),
FindElements(LocatorParameters),
IsDisplayed(WebElement),
IsSelected(WebElement),
GetElementAttribute(WebElement, String),
@ -39,7 +39,16 @@ pub enum WebDriverCommand {
GetElementRect(WebElement),
IsEnabled(WebElement),
ExecuteScript(JavascriptCommandParameters),
ExecuteAsyncScript(JavascriptCommandParameters)
ExecuteAsyncScript(JavascriptCommandParameters),
GetCookie(GetCookieParameters),
AddCookie(AddCookieParameters),
SetTimeouts(TimeoutsParameters),
//Actions(ActionsParameters)
DismissAlert,
AcceptAlert,
GetAlertText,
SendAlertText(SendAlertTextParameters),
TakeScreenshot(TakeScreenshotParameters)
}
#[deriving(PartialEq)]
@ -83,9 +92,9 @@ impl WebDriverMessage {
MatchType::GetWindowHandle => WebDriverCommand::GetWindowHandle,
MatchType::GetWindowHandles => WebDriverCommand::GetWindowHandles,
MatchType::Close => WebDriverCommand::Close,
MatchType::Timeouts => {
MatchType::SetTimeouts => {
let parameters: TimeoutsParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::Timeouts(parameters)
WebDriverCommand::SetTimeouts(parameters)
},
MatchType::SetWindowSize => {
let parameters: WindowSizeParameters = try!(Parameters::from_json(&body_data));
@ -102,6 +111,14 @@ impl WebDriverMessage {
WebDriverCommand::SwitchToFrame(parameters)
},
MatchType::SwitchToParentFrame => WebDriverCommand::SwitchToParentFrame,
MatchType::FindElement => {
let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::FindElement(parameters)
},
MatchType::FindElements => {
let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::FindElements(parameters)
},
MatchType::IsDisplayed => {
let element = WebElement::new(params.name("elementId").to_string());
WebDriverCommand::IsDisplayed(element)
@ -130,7 +147,7 @@ impl WebDriverMessage {
},
MatchType::GetElementRect => {
let element = WebElement::new(params.name("elementId").to_string());
WebDriverCommand::GetElementText(element)
WebDriverCommand::GetElementRect(element)
},
MatchType::IsEnabled => {
let element = WebElement::new(params.name("elementId").to_string());
@ -139,10 +156,35 @@ impl WebDriverMessage {
MatchType::ExecuteScript => {
let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::ExecuteScript(parameters)
}
},
MatchType::ExecuteAsyncScript => {
let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::ExecuteAsyncScript(parameters)
},
MatchType::GetCookie => {
let parameters: GetCookieParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::GetCookie(parameters)
},
MatchType::AddCookie => {
let parameters: AddCookieParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::AddCookie(parameters)
},
MatchType::DismissAlert => {
WebDriverCommand::DismissAlert
},
MatchType::AcceptAlert => {
WebDriverCommand::AcceptAlert
},
MatchType::GetAlertText => {
WebDriverCommand::GetAlertText
},
MatchType::SendAlertText => {
let parameters: SendAlertTextParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::SendAlertText(parameters)
}
MatchType::TakeScreenshot => {
let parameters: TakeScreenshotParameters = try!(Parameters::from_json(&body_data));
WebDriverCommand::TakeScreenshot(parameters)
}
};
Ok(WebDriverMessage::new(session_id, command))
@ -160,7 +202,7 @@ impl ToJson for WebDriverMessage {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
let parameters = match self.command {
WebDriverCommand::GetMarionetteId | WebDriverCommand::NewSession |
WebDriverCommand::NewSession |
WebDriverCommand::DeleteSession | WebDriverCommand::GetCurrentUrl |
WebDriverCommand::GoBack | WebDriverCommand::GoForward | WebDriverCommand::Refresh |
WebDriverCommand::GetTitle | WebDriverCommand::GetWindowHandle |
@ -170,16 +212,23 @@ impl ToJson for WebDriverMessage {
WebDriverCommand::IsSelected(_) | WebDriverCommand::GetElementAttribute(_, _) |
WebDriverCommand::GetCSSValue(_, _) | WebDriverCommand::GetElementText(_) |
WebDriverCommand::GetElementTagName(_) | WebDriverCommand::GetElementRect(_) |
WebDriverCommand::IsEnabled(_) => {
WebDriverCommand::IsEnabled(_) | WebDriverCommand::AddCookie(_) |
WebDriverCommand::DismissAlert | WebDriverCommand::AcceptAlert |
WebDriverCommand::GetAlertText => {
None
},
WebDriverCommand::Get(ref x) => Some(x.to_json()),
WebDriverCommand::Timeouts(ref x) => Some(x.to_json()),
WebDriverCommand::SetTimeouts(ref x) => Some(x.to_json()),
WebDriverCommand::SetWindowSize(ref x) => Some(x.to_json()),
WebDriverCommand::SwitchToWindow(ref x) => Some(x.to_json()),
WebDriverCommand::SwitchToFrame(ref x) => Some(x.to_json()),
WebDriverCommand::FindElement(ref x) => Some(x.to_json()),
WebDriverCommand::FindElements(ref x) => Some(x.to_json()),
WebDriverCommand::ExecuteScript(ref x) |
WebDriverCommand::ExecuteAsyncScript(ref x) => Some(x.to_json())
WebDriverCommand::ExecuteAsyncScript(ref x) => Some(x.to_json()),
WebDriverCommand::GetCookie(ref x) => Some(x.to_json()),
WebDriverCommand::SendAlertText(ref x) => Some(x.to_json()),
WebDriverCommand::TakeScreenshot(ref x) => Some(x.to_json())
};
if parameters.is_some() {
data.insert("parameters".to_string(), parameters.unwrap());
@ -188,76 +237,6 @@ impl ToJson for WebDriverMessage {
}
}
#[deriving(PartialEq)]
struct WebElement {
id: String
}
impl WebElement {
fn new(id: String) -> WebElement {
WebElement {
id: id
}
}
}
impl ToJson for WebElement {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
data.insert("element-6066-11e4-a52e-4f735466cecf".to_string(), self.id.to_json());
json::Object(data)
}
}
#[deriving(PartialEq)]
enum FrameId {
Short(u16),
Element(WebElement),
Null
}
impl ToJson for FrameId {
fn to_json(&self) -> json::Json {
match *self {
FrameId::Short(x) => {
json::Json::U64(x as u64)
},
FrameId::Element(ref x) => {
json::Json::String(x.id.clone())
},
FrameId::Null => {
json::Json::Null
}
}
}
}
#[deriving(PartialEq, Clone)]
enum Nullable<T: ToJson> {
Value(T),
Null
}
impl<T: ToJson> Nullable<T> {
//This is not very pretty
fn from_json<F: FnOnce(&json::Json) -> WebDriverResult<T>>(value: &json::Json, f: F) -> WebDriverResult<Nullable<T>> {
if value.is_null() {
Ok(Nullable::Null)
} else {
Ok(Nullable::Value(try!(f(value))))
}
}
}
impl<T:ToJson> ToJson for Nullable<T> {
fn to_json(&self) -> json::Json {
match *self {
Nullable::Value(ref x) => x.to_json(),
Nullable::Null => json::Json::Null
}
}
}
trait Parameters {
fn from_json(body: &json::Json) -> WebDriverResult<Self>;
}
@ -397,6 +376,45 @@ impl ToJson for SwitchToWindowParameters {
}
}
#[deriving(PartialEq)]
struct LocatorParameters {
using: LocatorStrategy,
value: String
}
impl Parameters for LocatorParameters {
fn from_json(body: &json::Json) -> WebDriverResult<LocatorParameters> {
let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
"Message body was not an object");
let using = try!(LocatorStrategy::from_json(
try_opt!(data.get("using"),
ErrorStatus::InvalidArgument,
"Missing 'using' parameter")));
let value = try_opt!(
try_opt!(data.get("value"),
ErrorStatus::InvalidArgument,
"Missing 'using' parameter").as_string(),
ErrorStatus::InvalidArgument,
"Could not convert using to string").into_string();
return Ok(LocatorParameters {
using: using,
value: value
})
}
}
impl ToJson for LocatorParameters {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
data.insert("using".to_string(), self.using.to_json());
data.insert("value".to_string(), self.value.to_json());
json::Object(data)
}
}
#[deriving(PartialEq)]
struct SwitchToFrameParameters {
id: FrameId
@ -404,28 +422,13 @@ struct SwitchToFrameParameters {
impl Parameters for SwitchToFrameParameters {
fn from_json(body: &json::Json) -> WebDriverResult<SwitchToFrameParameters> {
let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
let data = try_opt!(body.as_object(),
ErrorStatus::UnknownError,
"Message body was not an object");
let id_json = try_opt!(data.get("id"),
ErrorStatus::UnknownError,
"Missing 'id' parameter");
let id = if id_json.is_u64() {
let value = id_json.as_u64().unwrap();
if value <= u16::MAX as u64 {
FrameId::Short(value as u16)
} else {
return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
"frame id out of range"))
}
} else if id_json.is_null() {
FrameId::Null
} else if id_json.is_string() {
let value = id_json.as_string().unwrap();
FrameId::Element(WebElement::new(value.to_string()))
} else {
return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
"frame id has unexpected type"))
};
let id = try!(FrameId::from_json(try_opt!(data.get("id"),
ErrorStatus::UnknownError,
"Missing 'id' parameter")));
Ok(SwitchToFrameParameters {
id: id
})
@ -490,3 +493,217 @@ impl ToJson for JavascriptCommandParameters {
json::Object(data)
}
}
#[deriving(PartialEq)]
struct GetCookieParameters {
name: Nullable<String>
}
impl Parameters for GetCookieParameters {
fn from_json(body: &json::Json) -> WebDriverResult<GetCookieParameters> {
let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
"Message body was not an object");
let name_json = try_opt!(data.get("name"),
ErrorStatus::InvalidArgument,
"Missing 'name' parameter");
let name = try!(Nullable::from_json(
name_json,
|x| {
Ok(try_opt!(x.as_string(),
ErrorStatus::UnknownError,
"Failed to convert name to String").into_string())
}));
return Ok(GetCookieParameters {
name: name
})
}
}
impl ToJson for GetCookieParameters {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
data.insert("name".to_string(), self.name.to_json());
json::Object(data)
}
}
#[deriving(PartialEq)]
struct AddCookieParameters {
name: String,
value: String,
path: Nullable<String>,
domain: Nullable<String>,
expiry: Nullable<Date>,
maxAge: Date,
secure: bool,
httpOnly: bool
}
impl Parameters for AddCookieParameters {
fn from_json(body: &json::Json) -> WebDriverResult<AddCookieParameters> {
let data = try_opt!(body.as_object(),
ErrorStatus::UnknownError,
"Message body was not an object");
let name = try_opt!(
try_opt!(data.get("name"),
ErrorStatus::InvalidArgument,
"Missing 'name' parameter").as_string(),
ErrorStatus::InvalidArgument,
"'name' is not a string").into_string();
let value = try_opt!(
try_opt!(data.get("value"),
ErrorStatus::InvalidArgument,
"Missing 'value' parameter").as_string(),
ErrorStatus::InvalidArgument,
"'value' is not a string").into_string();
let path = match data.get("path") {
Some(path_json) => {
try!(Nullable::from_json(
path_json,
|x| {
Ok(try_opt!(x.as_string(),
ErrorStatus::UnknownError,
"Failed to convert path to String").into_string())
}))
},
None => Nullable::Null
};
let domain = match data.get("domain") {
Some(domain_json) => {
try!(Nullable::from_json(
domain_json,
|x| {
Ok(try_opt!(x.as_string(),
ErrorStatus::UnknownError,
"Failed to convert domain to String").into_string())
}))
},
None => Nullable::Null
};
//TODO: This is supposed to support some text format
let expiry = match data.get("expiry") {
Some(expiry_json) => {
try!(Nullable::from_json(
expiry_json,
|x| {
Ok(Date::new(try_opt!(x.as_u64(),
ErrorStatus::UnknownError,
"Failed to convert expiry to Date")))
}))
},
None => Nullable::Null
};
let max_age = Date::new(try_opt!(
try_opt!(data.get("maxAge"),
ErrorStatus::InvalidArgument,
"Missing 'maxAge' parameter").as_u64(),
ErrorStatus::InvalidArgument,
"'value' is not a string"));
let secure = match data.get("secure") {
Some(x) => try_opt!(x.as_boolean(),
ErrorStatus::UnknownError,
"Failed to convert secure to boolean"),
None => false
};
let http_only = match data.get("httpOnly") {
Some(x) => try_opt!(x.as_boolean(),
ErrorStatus::UnknownError,
"Failed to convert httpOnly to boolean"),
None => false
};
return Ok(AddCookieParameters {
name: name,
value: value,
path: path,
domain: domain,
expiry: expiry,
maxAge: max_age,
secure: secure,
httpOnly: http_only
})
}
}
impl ToJson for AddCookieParameters {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
data.insert("name".to_string(), self.name.to_json());
data.insert("value".to_string(), self.value.to_json());
data.insert("path".to_string(), self.path.to_json());
data.insert("domain".to_string(), self.domain.to_json());
data.insert("expiry".to_string(), self.expiry.to_json());
data.insert("maxAge".to_string(), self.maxAge.to_json());
data.insert("secure".to_string(), self.secure.to_json());
data.insert("httpOnly".to_string(), self.httpOnly.to_json());
json::Object(data)
}
}
#[deriving(PartialEq)]
struct SendAlertTextParameters {
keysToSend: String
}
impl Parameters for SendAlertTextParameters {
fn from_json(body: &json::Json) -> WebDriverResult<SendAlertTextParameters> {
let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
"Message body was not an object");
let keys = try_opt!(
try_opt!(data.get("keysToSend"),
ErrorStatus::InvalidArgument,
"Missing 'handle' parameter").as_string(),
ErrorStatus::InvalidArgument,
"'keysToSend' not a string").into_string();
return Ok(SendAlertTextParameters {
keysToSend: keys
})
}
}
impl ToJson for SendAlertTextParameters {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
data.insert("keysToSend".to_string(), self.keysToSend.to_json());
json::Object(data)
}
}
#[deriving(PartialEq)]
struct TakeScreenshotParameters {
element: Nullable<WebElement>
}
impl Parameters for TakeScreenshotParameters {
fn from_json(body: &json::Json) -> WebDriverResult<TakeScreenshotParameters> {
let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
"Message body was not an object");
let element = match data.get("element") {
Some(element_json) => try!(Nullable::from_json(
element_json,
|x| {
Ok(try!(WebElement::from_json(x)))
})),
None => Nullable::Null
};
return Ok(TakeScreenshotParameters {
element: element
})
}
}
impl ToJson for TakeScreenshotParameters {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
data.insert("element".to_string(), self.element.to_json());
json::Object(data)
}
}

Просмотреть файл

@ -1,4 +1,5 @@
use serialize::json;
use core::u16;
use serialize::{json, Encodable, Encoder};
use serialize::json::{ToJson, ParserError};
use std::collections::TreeMap;
use std::error::{Error, FromError};
@ -118,3 +119,149 @@ impl FromError<ParserError> for WebDriverError {
WebDriverError::new(ErrorStatus::UnknownError, msg.as_slice())
}
}
#[deriving(PartialEq, Clone, Show)]
pub enum Nullable<T: ToJson> {
Value(T),
Null
}
impl<T: ToJson> Nullable<T> {
//This is not very pretty
pub fn from_json<F: FnOnce(&json::Json) -> WebDriverResult<T>>(value: &json::Json, f: F) -> WebDriverResult<Nullable<T>> {
if value.is_null() {
Ok(Nullable::Null)
} else {
Ok(Nullable::Value(try!(f(value))))
}
}
}
impl<T: ToJson> ToJson for Nullable<T> {
fn to_json(&self) -> json::Json {
match *self {
Nullable::Value(ref x) => x.to_json(),
Nullable::Null => json::Json::Null
}
}
}
impl<S: Encoder<E>, E, T: ToJson> Encodable<S, E> for Nullable<T> {
fn encode(&self, s: &mut S) -> Result<(), E> {
match *self {
Nullable::Value(ref x) => x.to_json().encode(s),
Nullable::Null => s.emit_nil()
}
}
}
#[deriving(PartialEq)]
pub struct WebElement {
id: String
}
impl WebElement {
pub fn new(id: String) -> WebElement {
WebElement {
id: id
}
}
pub fn from_json(data: &json::Json) -> WebDriverResult<WebElement> {
Ok(WebElement::new(
try_opt!(
try_opt!(
try_opt!(data.as_object(),
ErrorStatus::InvalidArgument,
"Could not convert webelement to object").get(
"element-6066-11e4-a52e-4f735466cecf"),
ErrorStatus::InvalidArgument,
"Could not find webelement key").as_string(),
ErrorStatus::InvalidArgument,
"Could not convert web element to string").into_string()))
}
}
impl ToJson for WebElement {
fn to_json(&self) -> json::Json {
let mut data = TreeMap::new();
data.insert("element-6066-11e4-a52e-4f735466cecf".to_string(), self.id.to_json());
json::Object(data)
}
}
#[deriving(PartialEq)]
pub enum FrameId {
Short(u16),
Element(WebElement),
Null
}
impl FrameId {
pub fn from_json(data: &json::Json) -> WebDriverResult<FrameId> {
match data {
&json::Json::U64(x) => {
if x <= u16::MAX as u64 {
Ok(FrameId::Short(x as u16))
} else {
Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
"frame id out of range"))
}
},
&json::Json::Null => Ok(FrameId::Null),
&json::Json::String(ref x) => Ok(FrameId::Element(WebElement::new(x.clone()))),
_ => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
"frame id has unexpected type"))
}
}
}
impl ToJson for FrameId {
fn to_json(&self) -> json::Json {
match *self {
FrameId::Short(x) => {
json::Json::U64(x as u64)
},
FrameId::Element(ref x) => {
json::Json::String(x.id.clone())
},
FrameId::Null => {
json::Json::Null
}
}
}
}
#[deriving(PartialEq)]
pub enum LocatorStrategy {
CSSSelector,
LinkText,
PartialLinkText,
XPath
}
impl LocatorStrategy {
pub fn from_json(body: &json::Json) -> WebDriverResult<LocatorStrategy> {
match try_opt!(body.as_string(),
ErrorStatus::InvalidArgument,
"Cound not convert strategy to string") {
"css selector" => Ok(LocatorStrategy::CSSSelector),
"link text" => Ok(LocatorStrategy::LinkText),
"partial link text" => Ok(LocatorStrategy::PartialLinkText),
"xpath" => Ok(LocatorStrategy::XPath),
_ => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
"Unknown locator strategy"))
}
}
}
impl ToJson for LocatorStrategy {
fn to_json(&self) -> json::Json {
json::Json::String(match *self {
LocatorStrategy::CSSSelector => "css selector",
LocatorStrategy::LinkText => "link text",
LocatorStrategy::PartialLinkText => "partial link text",
LocatorStrategy::XPath => "xpath"
}.into_string())
}
}

Просмотреть файл

@ -4,16 +4,19 @@ use std::collections::TreeMap;
use std::io::{IoResult, TcpStream, IoError};
use command::{WebDriverMessage};
use command::WebDriverCommand::{GetMarionetteId, NewSession, DeleteSession, Get, GetCurrentUrl,
use command::WebDriverCommand::{NewSession, DeleteSession, Get, GetCurrentUrl,
GoBack, GoForward, Refresh, GetTitle, GetWindowHandle,
GetWindowHandles, Close, Timeouts, SetWindowSize,
GetWindowHandles, Close, SetWindowSize,
GetWindowSize, MaximizeWindow, SwitchToWindow, SwitchToFrame,
SwitchToParentFrame, IsDisplayed, IsSelected,
GetElementAttribute, GetCSSValue, GetElementText,
SwitchToParentFrame, FindElement, FindElements, IsDisplayed,
IsSelected, GetElementAttribute, GetCSSValue, GetElementText,
GetElementTagName, GetElementRect, IsEnabled, ExecuteScript,
ExecuteAsyncScript};
use response::{WebDriverResponse, NewSessionResponse, ValueResponse, WindowSizeResponse, ElementRectResponse};
use common::{WebDriverResult, WebDriverError, ErrorStatus};
ExecuteAsyncScript, GetCookie, AddCookie, SetTimeouts,
DismissAlert, AcceptAlert, GetAlertText, SendAlertText,
TakeScreenshot};
use response::{WebDriverResponse, NewSessionResponse, ValueResponse, WindowSizeResponse,
ElementRectResponse, CookieResponse, Date, Cookie};
use common::{WebDriverResult, WebDriverError, ErrorStatus, Nullable};
pub struct MarionetteSession {
pub session_id: String,
@ -37,16 +40,6 @@ impl MarionetteSession {
pub fn update(&mut self, msg: &WebDriverMessage, resp: &TreeMap<String, json::Json>) -> WebDriverResult<()> {
match msg.command {
GetMarionetteId => {
let to = try_opt!(
try_opt!(resp.get("to"),
ErrorStatus::UnknownError,
"Unable to get to value").as_string(),
ErrorStatus::UnknownError,
"Unable to convert 'to' to a string");
self.to = to.to_string();
},
NewSession => {
let session_id = try_opt!(
try_opt!(resp.get("sessionId"),
@ -61,49 +54,63 @@ impl MarionetteSession {
Ok(())
}
fn command_name(msg:&WebDriverMessage) -> String {
fn command_name(msg:&WebDriverMessage) -> Option<String> {
match msg.command {
GetMarionetteId => "getMarionetteID",
NewSession => "newSession",
DeleteSession => "deleteSession",
Get(_) => "get",
GetCurrentUrl => "getCurrentUrl",
GoBack => "goBack",
GoForward => "goForward",
Refresh => "refresh",
GetTitle => "getTitle",
GetWindowHandle => "getWindowHandle",
GetWindowHandles => "getWindowHandles",
Close => "close",
Timeouts(_) => "timeouts",
SetWindowSize(_) => "setWindowSize",
GetWindowSize => "getWindowSize",
MaximizeWindow => "maximizeWindow",
SwitchToWindow(_) => "switchToWindow",
SwitchToFrame(_) => "switchToFrame",
SwitchToParentFrame => "switchToParentFrame",
IsDisplayed(_) => "isElementDisplayed",
IsSelected(_) => "isElementSelected",
GetElementAttribute(_, _) => "getElementAttribute",
GetCSSValue(_, _) => "getElementValueOfCssProperty",
GetElementText(_) => "getElementText",
GetElementTagName(_) => "getElementTagName",
GetElementRect(_) => "getElementRect",
IsEnabled(_) => "isElementEnabled",
ExecuteScript(_) => "executeScript",
ExecuteAsyncScript(_) => "executeAsyncScript"
}.to_string()
NewSession => Some("newSession"),
DeleteSession => Some("deleteSession"),
Get(_) => Some("get"),
GetCurrentUrl => Some("getCurrentUrl"),
GoBack => Some("goBack"),
GoForward => Some("goForward"),
Refresh => Some("refresh"),
GetTitle => Some("getTitle"),
GetWindowHandle => Some("getWindowHandle"),
GetWindowHandles => Some("getWindowHandles"),
Close => Some("close"),
SetTimeouts(_) => Some("timeouts"),
SetWindowSize(_) => Some("setWindowSize"),
GetWindowSize => Some("getWindowSize"),
MaximizeWindow => Some("maximizeWindow"),
SwitchToWindow(_) => Some("switchToWindow"),
SwitchToFrame(_) => Some("switchToFrame"),
SwitchToParentFrame => Some("switchToParentFrame"),
FindElement(_) => Some("findElement"),
FindElements(_) => Some("findElements"),
IsDisplayed(_) => Some("isElementDisplayed"),
IsSelected(_) => Some("isElementSelected"),
GetElementAttribute(_, _) => Some("getElementAttribute"),
GetCSSValue(_, _) => Some("getElementValueOfCssProperty"),
GetElementText(_) => Some("getElementText"),
GetElementTagName(_) => Some("getElementTagName"),
GetElementRect(_) => Some("getElementRect"),
IsEnabled(_) => Some("isElementEnabled"),
ExecuteScript(_) => Some("executeScript"),
ExecuteAsyncScript(_) => Some("executeAsyncScript"),
GetCookie(_) => Some("getCookies"),
AddCookie(_) => Some("addCookie"),
DismissAlert => None, //Unsupported
AcceptAlert => None, //Unsupported
GetAlertText => None, //Unsupported
SendAlertText(_) => None, //Unsupported
TakeScreenshot(_) => Some("takeScreenshot")
}.map(|x| x.into_string())
}
pub fn msg_to_marionette(&self, msg: &WebDriverMessage) -> json::Json {
let mut data = msg.to_json().as_object().unwrap().clone();
pub fn msg_to_marionette(&self, msg: &WebDriverMessage) -> WebDriverResult<json::Json> {
let command_name = try_opt!(MarionetteSession::command_name(msg),
ErrorStatus::UnsupportedOperation,
"Operation not supported");
let mut data = try_opt!(msg.to_json().as_object(),
ErrorStatus::UnknownError,
"Failed to convert message to Object"
).clone();
match msg.session_id {
Some(ref x) => data.insert("sessionId".to_string(), x.to_json()),
None => None
};
data.insert("to".to_string(), self.to.to_json());
data.insert("name".to_string(), MarionetteSession::command_name(msg).to_json());
json::Object(data)
data.insert("name".to_string(), command_name.to_json());
Ok(json::Object(data))
}
pub fn response_from_json(&mut self, message: &WebDriverMessage,
@ -129,23 +136,26 @@ impl MarionetteSession {
return Err(WebDriverError::new(status, err_msg));
}
self.update(message, &json_data);
try!(self.update(message, &json_data));
match message.command {
//Everything that doesn't have a response value
GetMarionetteId => Ok(None),
Get(_) | GoBack | GoForward | Refresh | Close | Timeouts(_) |
Get(_) | GoBack | GoForward | Refresh | Close | SetTimeouts(_) |
SetWindowSize(_) | MaximizeWindow | SwitchToWindow(_) | SwitchToFrame(_) |
SwitchToParentFrame => {
SwitchToParentFrame | AddCookie(_) | DismissAlert | AcceptAlert |
SendAlertText(_) => {
Ok(Some(WebDriverResponse::Void))
},
//Things that simply return the contents of the marionette "value" property
GetCurrentUrl | GetTitle | GetWindowHandle | GetWindowHandles | IsDisplayed(_) |
IsSelected(_) | GetElementAttribute(_, _) | GetCSSValue(_, _) | GetElementText(_) |
GetElementTagName(_) | IsEnabled(_) | ExecuteScript(_) | ExecuteAsyncScript(_) => {
GetCurrentUrl | GetTitle | GetWindowHandle | GetWindowHandles |
FindElement(_) | FindElements(_) | IsDisplayed(_) | IsSelected(_) |
GetElementAttribute(_, _) | GetCSSValue(_, _) | GetElementText(_) |
GetElementTagName(_) | IsEnabled(_) | ExecuteScript(_) | ExecuteAsyncScript(_) |
GetAlertText | TakeScreenshot(_) => {
let value = try_opt!(json_data.get("value"),
ErrorStatus::UnknownError,
"Failed to find value field");
//TODO: Convert webelement keys
Ok(Some(WebDriverResponse::Generic(ValueResponse::new(value.clone()))))
},
GetWindowSize => {
@ -209,14 +219,84 @@ impl MarionetteSession {
"Failed to interpret width as integer");
Ok(Some(WebDriverResponse::ElementRect(ElementRectResponse::new(x, y, width, height))))
}
},
GetCookie(_) => {
let value = try_opt!(
try_opt!(json_data.get("value"),
ErrorStatus::UnknownError,
"Failed to find value field").as_array(),
ErrorStatus::UnknownError,
"Failed to interpret value as array");
let cookies = try!(value.iter().map(|x| {
let name = try_opt!(
try_opt!(x.find("name"),
ErrorStatus::UnknownError,
"Failed to find name field").as_string(),
ErrorStatus::UnknownError,
"Failed to interpret name as string").into_string();
let value = try_opt!(
try_opt!(x.find("value"),
ErrorStatus::UnknownError,
"Failed to find value field").as_string(),
ErrorStatus::UnknownError,
"Failed to interpret value as string").into_string();
let path = try!(
Nullable::from_json(try_opt!(x.find("path"),
ErrorStatus::UnknownError,
"Failed to find path field"),
|x| {
Ok((try_opt!(x.as_string(),
ErrorStatus::UnknownError,
"Failed to interpret path as String")).into_string())
}));
let domain = try!(
Nullable::from_json(try_opt!(x.find("domain"),
ErrorStatus::UnknownError,
"Failed to find domain field"),
|x| {
Ok((try_opt!(x.as_string(),
ErrorStatus::UnknownError,
"Failed to interpret domain as String")).into_string())
}));
let expiry = try!(
Nullable::from_json(try_opt!(x.find("expiry"),
ErrorStatus::UnknownError,
"Failed to find expiry field"),
|x| {
Ok(Date::new((try_opt!(
x.as_u64(),
ErrorStatus::UnknownError,
"Failed to interpret domain as String"))))
}));
let max_age = Date::new(try_opt!(
try_opt!(x.find("maxAge"),
ErrorStatus::UnknownError,
"Failed to find maxAge field").as_u64(),
ErrorStatus::UnknownError,
"Failed to interpret maxAge as u64"));
let secure = match x.find("secure") {
Some(x) => try_opt!(x.as_boolean(),
ErrorStatus::UnknownError,
"Failed to interpret secure as boolean"),
None => false
};
let http_only = match x.find("httpOnly") {
Some(x) => try_opt!(x.as_boolean(),
ErrorStatus::UnknownError,
"Failed to interpret http_only as boolean"),
None => false
};
Ok(Cookie::new(name, value, path, domain, expiry, max_age, secure, http_only))
}).collect::<Result<Vec<_>, _>>());
Ok(Some(WebDriverResponse::Cookie(CookieResponse::new(cookies))))
},
NewSession => {
let session_id = try_opt!(
try_opt!(json_data.get("sessionId"),
ErrorStatus::InvalidSessionId,
"Failed to find sessionId field").as_string(),
ErrorStatus::InvalidSessionId,
"sessionId was not a string");
"sessionId was not a string").into_string();
let value = try_opt!(
try_opt!(json_data.get("value"),
@ -226,7 +306,7 @@ impl MarionetteSession {
"value field was not an Object");
Ok(Some(WebDriverResponse::NewSession(NewSessionResponse::new(
session_id.to_string(), json::Object(value.clone())))))
session_id, json::Object(value.clone())))))
}
DeleteSession => {
Ok(Some(WebDriverResponse::DeleteSession))
@ -310,9 +390,7 @@ impl MarionetteConnection {
}
pub fn send_message(&mut self, msg: &WebDriverMessage) -> WebDriverResult<Option<WebDriverResponse>> {
let resp = {
self.session.msg_to_marionette(msg)
};
let resp = try!(self.session.msg_to_marionette(msg));
let resp = match self.send(&resp) {
Ok(resp_data) => self.session.response_from_json(msg, resp_data[]),
Err(x) => Err(x)

Просмотреть файл

@ -18,13 +18,14 @@ pub enum MatchType {
GetWindowHandle,
GetWindowHandles,
Close,
Timeouts,
SetWindowSize,
GetWindowSize,
MaximizeWindow,
SwitchToWindow,
SwitchToFrame,
SwitchToParentFrame,
FindElement,
FindElements,
IsDisplayed,
IsSelected,
GetElementAttribute,
@ -35,6 +36,15 @@ pub enum MatchType {
IsEnabled,
ExecuteScript,
ExecuteAsyncScript,
GetCookie,
AddCookie,
SetTimeouts,
//Actions XXX - once I understand the spec, perhaps
DismissAlert,
AcceptAlert,
GetAlertText,
SendAlertText,
TakeScreenshot
}
#[deriving(Clone)]
@ -131,13 +141,14 @@ pub fn get_builder() -> MessageBuilder {
(Get, "/session/{sessionId}/window_handle", MatchType::GetWindowHandle),
(Get, "/session/{sessionId}/window_handles", MatchType::GetWindowHandles),
(Delete, "/session/{sessionId}/window_handle", MatchType::Close),
(Post, "/session/{sessionId}/timeouts", MatchType::Timeouts),
(Post, "/session/{sessionId}/window/size", MatchType::SetWindowSize),
(Get, "/session/{sessionId}/window/size", MatchType::GetWindowSize),
(Post, "/session/{sessionId}/window/maximize", MatchType::MaximizeWindow),
(Post, "/session/{sessionId}/window", MatchType::SwitchToWindow),
(Post, "/session/{sessionId}/frame", MatchType::SwitchToFrame),
(Post, "/session/{sessionId}/frame/parent", MatchType::SwitchToParentFrame),
(Post, "/session/{sessionId}/element", MatchType::FindElement),
(Post, "/session/{sessionId}/elements", MatchType::FindElements),
(Get, "/session/{sessionId}/element/{element}/isDisplayed", MatchType::IsDisplayed),
(Get, "/session/{sessionId}/element/{element}/isSelected", MatchType::IsSelected),
(Get, "/session/{sessionId}/element/{element}/attribute/{name}", MatchType::GetElementAttribute),
@ -148,6 +159,15 @@ pub fn get_builder() -> MessageBuilder {
(Get, "/session/{sessionId}/element/{element}/enabled", MatchType::IsEnabled),
(Post, "/session/{sessionId}/execute", MatchType::ExecuteScript),
(Post, "/session/{sessionId}/execute_async", MatchType::ExecuteAsyncScript),
(Get, "/session/{sessionId}/cookie", MatchType::GetCookie),
(Post, "/session/{sessionId}/cookie", MatchType::AddCookie),
(Post, "/session/{sessionId}/timeouts", MatchType::SetTimeouts),
//(Post, "/session/{sessionId}/actions", MatchType::Actions),
(Post, "/session/{sessionId}/dismiss_alert", MatchType::DismissAlert),
(Post, "/session/{sessionId}/accept_alert", MatchType::AcceptAlert),
(Get, "/session/{sessionId}/alert_text", MatchType::GetAlertText),
(Post, "/session/{sessionId}/alert_text", MatchType::SendAlertText),
(Get, "/session/{sessionId}/screenshot", MatchType::TakeScreenshot)
];
debug!("Creating routes");
for &(ref method, ref url, ref match_type) in matchers.iter() {

Просмотреть файл

@ -1,4 +1,7 @@
use serialize::json;
use serialize::json::ToJson;
use common::Nullable;
#[deriving(Show)]
pub enum WebDriverResponse {
@ -6,6 +9,7 @@ pub enum WebDriverResponse {
DeleteSession,
WindowSize(WindowSizeResponse),
ElementRect(ElementRectResponse),
Cookie(CookieResponse),
Generic(ValueResponse),
Void
}
@ -17,6 +21,7 @@ impl WebDriverResponse {
WebDriverResponse::DeleteSession => "".into_string(),
WebDriverResponse::WindowSize(x) => json::encode(&x),
WebDriverResponse::ElementRect(x) => json::encode(&x),
WebDriverResponse::Cookie(x) => json::encode(&x),
WebDriverResponse::Generic(x) => json::encode(&x),
WebDriverResponse::Void => "".into_string()
}
@ -84,3 +89,61 @@ impl ElementRectResponse {
}
}
}
#[deriving(Encodable, PartialEq, Show)]
pub struct Date(u64);
impl Date {
pub fn new(timestamp: u64) -> Date {
Date(timestamp)
}
}
impl ToJson for Date {
fn to_json(&self) -> json::Json {
let &Date(x) = self;
x.to_json()
}
}
//TODO: some of these fields are probably supposed to be optional
#[deriving(Encodable, PartialEq, Show)]
pub struct Cookie {
name: String,
value: String,
path: Nullable<String>,
domain: Nullable<String>,
expiry: Nullable<Date>,
maxAge: Date,
secure: bool,
httpOnly: bool
}
impl Cookie {
pub fn new(name: String, value: String, path: Nullable<String>, domain: Nullable<String>,
expiry: Nullable<Date>, max_age: Date, secure: bool, http_only: bool) -> Cookie {
Cookie {
name: name,
value: value,
path: path,
domain: domain,
expiry: expiry,
maxAge: max_age,
secure: secure,
httpOnly: http_only
}
}
}
#[deriving(Encodable, Show)]
pub struct CookieResponse {
value: Vec<Cookie>
}
impl CookieResponse {
pub fn new(value: Vec<Cookie>) -> CookieResponse {
CookieResponse {
value: value
}
}
}