Skip to content

Commit

Permalink
Add support for returning array-like types from the Execute(Async)Scr…
Browse files Browse the repository at this point in the history
…ipt wd command
  • Loading branch information
georgeroman committed Aug 10, 2019
1 parent b3c0ed2 commit 58f80f4
Show file tree
Hide file tree
Showing 22 changed files with 88 additions and 187 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/script/Cargo.toml
Expand Up @@ -111,6 +111,7 @@ url = "1.6"
utf-8 = "0.7"
uuid = {version = "0.7", features = ["v4"]}
xml5ever = {version = "0.14"}
webdriver = "0.40"
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
webvr_traits = {path = "../webvr_traits"}
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
Expand Down
2 changes: 1 addition & 1 deletion components/script/dom/window.rs
Expand Up @@ -964,7 +964,7 @@ impl WindowMethods for Window {

#[allow(unsafe_code)]
fn WebdriverCallback(&self, cx: JSContext, val: HandleValue) {
let rv = unsafe { jsval_to_webdriver(*cx, val) };
let rv = unsafe { jsval_to_webdriver(*cx, &self.globalscope, val) };
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
chan.send(rv).unwrap();
Expand Down
71 changes: 64 additions & 7 deletions components/script/webdriver_handlers.rs
Expand Up @@ -12,7 +12,10 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::XMLSerializerBinding::XMLSerializerMethods;
use crate::dom::bindings::conversions::{
get_property_jsval, ConversionResult, FromJSValConvertible, StringificationBehavior,
get_property, get_property_jsval, is_array_like, root_from_object,
};
use crate::dom::bindings::conversions::{
ConversionBehavior, ConversionResult, FromJSValConvertible, StringificationBehavior,
};
use crate::dom::bindings::error::throw_dom_exception;
use crate::dom::bindings::inheritance::Castable;
Expand All @@ -29,12 +32,13 @@ use crate::dom::node::{window_from_node, Node, ShadowIncluding};
use crate::dom::nodelist::NodeList;
use crate::dom::window::Window;
use crate::dom::xmlserializer::XMLSerializer;
use crate::script_runtime::JSContext as SafeJSContext;
use crate::script_thread::Documents;
use cookie::Cookie;
use euclid::default::{Point2D, Rect, Size2D};
use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::JSContext;
use js::jsapi::{JSAutoRealm, JSContext};
use js::jsval::UndefinedValue;
use js::rust::HandleValue;
use msg::constellation_msg::BrowsingContextId;
Expand All @@ -47,6 +51,7 @@ use script_traits::webdriver_msg::{
WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue,
};
use servo_url::ServoUrl;
use webdriver::common::WebElement;

fn find_node_by_unique_id(
documents: &Documents,
Expand Down Expand Up @@ -106,9 +111,15 @@ fn first_matching_link(
}

#[allow(unsafe_code)]
pub unsafe fn jsval_to_webdriver(cx: *mut JSContext, val: HandleValue) -> WebDriverJSResult {
pub unsafe fn jsval_to_webdriver(
cx: *mut JSContext,
global_scope: &GlobalScope,
val: HandleValue,
) -> WebDriverJSResult {
if val.get().is_undefined() {
Ok(WebDriverJSValue::Undefined)
} else if val.get().is_null() {
Ok(WebDriverJSValue::Null)
} else if val.get().is_boolean() {
Ok(WebDriverJSValue::Boolean(val.get().to_boolean()))
} else if val.get().is_double() || val.get().is_int32() {
Expand All @@ -128,8 +139,52 @@ pub unsafe fn jsval_to_webdriver(cx: *mut JSContext, val: HandleValue) -> WebDri
_ => unreachable!(),
};
Ok(WebDriverJSValue::String(String::from(string)))
} else if val.get().is_null() {
Ok(WebDriverJSValue::Null)
} else if val.get().is_object() {
rooted!(in(cx) let object = match FromJSValConvertible::from_jsval(cx, val, ()).unwrap() {
ConversionResult::Success(object) => object,
_ => unreachable!(),
});
let _ac = JSAutoRealm::new(cx, *object);

if let Ok(element) = root_from_object::<HTMLElement>(*object, cx) {
return Ok(WebDriverJSValue::Element(WebElement(
element.upcast::<Node>().unique_id(),
)));
}

if !is_array_like(cx, val) {
return Err(WebDriverJSError::UnknownType);
}

let mut result: Vec<WebDriverJSValue> = Vec::new();

let length =
match get_property::<u32>(cx, object.handle(), "length", ConversionBehavior::Default) {
Ok(length) => match length {
Some(length) => length,
_ => return Err(WebDriverJSError::UnknownType),
},
Err(error) => {
throw_dom_exception(SafeJSContext::from_ptr(cx), global_scope, error);
return Err(WebDriverJSError::JSError);
},
};

for i in 0..length {
rooted!(in(cx) let mut item = UndefinedValue());
match get_property_jsval(cx, object.handle(), &i.to_string(), item.handle_mut()) {
Ok(_) => match jsval_to_webdriver(cx, global_scope, item.handle()) {
Ok(converted_item) => result.push(converted_item),
err @ Err(_) => return err,
},
Err(error) => {
throw_dom_exception(SafeJSContext::from_ptr(cx), global_scope, error);
return Err(WebDriverJSError::JSError);
},
}
}

Ok(WebDriverJSValue::ArrayLike(result))
} else {
Err(WebDriverJSError::UnknownType)
}
Expand All @@ -149,7 +204,7 @@ pub fn handle_execute_script(
window
.upcast::<GlobalScope>()
.evaluate_js_on_global_with_result(&eval, rval.handle_mut());
jsval_to_webdriver(*cx, rval.handle())
jsval_to_webdriver(*cx, &window.upcast::<GlobalScope>(), rval.handle())
};

reply.send(result).unwrap();
Expand Down Expand Up @@ -734,7 +789,9 @@ pub fn handle_get_property(
property.handle_mut(),
)
} {
Ok(_) => match unsafe { jsval_to_webdriver(*cx, property.handle()) } {
Ok(_) => match unsafe {
jsval_to_webdriver(*cx, &node.reflector().global(), property.handle())
} {
Ok(property) => Ok(property),
Err(_) => Ok(WebDriverJSValue::Undefined),
},
Expand Down
1 change: 1 addition & 0 deletions components/script_traits/Cargo.toml
Expand Up @@ -38,6 +38,7 @@ servo_url = {path = "../url"}
style_traits = {path = "../style_traits", features = ["servo"]}
time = "0.1.12"
url = "1.2"
webdriver = "0.40"
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
webvr_traits = {path = "../webvr_traits"}
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
6 changes: 5 additions & 1 deletion components/script_traits/webdriver_msg.rs
Expand Up @@ -10,6 +10,7 @@ use hyper_serde::Serde;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::BrowsingContextId;
use servo_url::ServoUrl;
use webdriver::common::WebElement;

#[derive(Debug, Deserialize, Serialize)]
pub enum WebDriverScriptCommand {
Expand Down Expand Up @@ -66,13 +67,16 @@ pub enum WebDriverJSValue {
Null,
Boolean(bool),
Number(f64),
String(String), // TODO: Object and WebElement
String(String),
Element(WebElement),
ArrayLike(Vec<WebDriverJSValue>),
}

#[derive(Debug, Deserialize, Serialize)]
pub enum WebDriverJSError {
Timeout,
UnknownType,
JSError,
/// Occurs when handler received an event message for a layout channel that is not
/// associated with the current script thread
BrowsingContextNotFound,
Expand Down
10 changes: 10 additions & 0 deletions components/webdriver_server/lib.rs
Expand Up @@ -224,6 +224,12 @@ impl Serialize for SendableWebDriverJSValue {
WebDriverJSValue::Boolean(x) => serializer.serialize_bool(x),
WebDriverJSValue::Number(x) => serializer.serialize_f64(x),
WebDriverJSValue::String(ref x) => serializer.serialize_str(&x),
WebDriverJSValue::Element(ref x) => x.serialize(serializer),
WebDriverJSValue::ArrayLike(ref x) => x
.iter()
.map(|element| SendableWebDriverJSValue(element.clone()))
.collect::<Vec<SendableWebDriverJSValue>>()
.serialize(serializer),
}
}
}
Expand Down Expand Up @@ -1397,6 +1403,10 @@ impl Handler {
ErrorStatus::UnsupportedOperation,
"Unsupported return type",
)),
Err(WebDriverJSError::JSError) => Err(WebDriverError::new(
ErrorStatus::JavascriptError,
"JS evaluation raised an exception",
)),
Err(WebDriverJSError::BrowsingContextNotFound) => Err(WebDriverError::new(
ErrorStatus::JavascriptError,
"Pipeline id not found in browsing context",
Expand Down
Expand Up @@ -5,12 +5,6 @@
[test_form_control_send_text[textarea\]]
expected: FAIL

[test_not_blurred[input\]]
expected: FAIL

[test_file_upload]
expected: FAIL

[test_not_blurred[textarea\]]
expected: FAIL

@@ -1,13 +1,2 @@
[form_controls.py]
[test_textarea]
expected: FAIL

[test_input_append]
expected: FAIL

[test_textarea_append]
expected: FAIL

[test_input]
expected: FAIL

disabled: Triggers setup errors in other tests
@@ -1,25 +1,10 @@
[collections.py]
[test_html_form_controls_collection]
expected: FAIL

[test_html_options_collection]
expected: FAIL

[test_file_list]
expected: FAIL

[test_arguments]
expected: FAIL

[test_html_collection]
expected: FAIL

[test_array]
expected: FAIL

[test_node_list]
expected: FAIL

[test_html_all_collection]
expected: FAIL

12 changes: 3 additions & 9 deletions tests/wpt/metadata/webdriver/tests/execute_script/cyclic.py.ini
@@ -1,19 +1,13 @@
[cyclic.py]
[test_element_in_collection]
expected: FAIL

[test_object_in_array]
expected: FAIL

[test_object]
expected: FAIL

[test_array]
expected: FAIL

[test_array_in_object]
expected: FAIL

[test_element_in_object]
expected: FAIL

[test_element_in_collection]
expected:
if os == "mac": FAIL
Expand Up @@ -23,6 +23,3 @@
[test_abort_by_user_prompt_twice[alert\]]
expected: FAIL

[test_override_listeners]
expected: FAIL

This file was deleted.

12 changes: 0 additions & 12 deletions tests/wpt/metadata/webdriver/tests/find_element/find.py.ini
@@ -1,25 +1,13 @@
[find.py]
[test_xhtml_namespace[css selector-#linkText\]]
expected: FAIL

[test_htmldocument[xpath-/html\]]
expected: FAIL

[test_xhtml_namespace[xpath-//*[name()='a'\]\]]
expected: FAIL

[test_xhtml_namespace[tag name-a\]]
expected: FAIL

[test_xhtml_namespace[link text-full link text\]]
expected: FAIL

[test_no_element[css selector-#wontExist\]]
expected: FAIL

[test_xhtml_namespace[partial link text-link text\]]
expected: FAIL

[test_find_element[xpath-//a\]]
expected: FAIL

Expand Down
@@ -1,28 +1,16 @@
[find.py]
[test_xhtml_namespace[css selector-#linkText\]]
expected: FAIL

[test_xhtml_namespace[xpath-//*[name()='a'\]\]]
expected: FAIL

[test_parent_htmldocument]
expected: FAIL

[test_xhtml_namespace[tag name-a\]]
expected: FAIL

[test_xhtml_namespace[link text-full link text\]]
expected: FAIL

[test_parent_of_document_node_errors]
expected: FAIL

[test_no_element[css selector-#wontExist\]]
expected: FAIL

[test_xhtml_namespace[partial link text-link text\]]
expected: FAIL

[test_find_element[xpath-//a\]]
expected: FAIL

Expand Down

0 comments on commit 58f80f4

Please sign in to comment.