Auto merge of #23745 - georgeroman:implement_get_element_property_wd_command, r=jdm

Implement GetElementProperty wd command

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23745)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-07-23 21:24:57 -04:00 committed by GitHub
commit 7ffe65e672
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 23 deletions

View file

@ -60,7 +60,7 @@ use js::jsapi::{
}; };
use js::jsapi::{JS_NewStringCopyN, JS_StringHasLatin1Chars}; use js::jsapi::{JS_NewStringCopyN, JS_StringHasLatin1Chars};
use js::jsval::{ObjectValue, StringValue, UndefinedValue}; use js::jsval::{ObjectValue, StringValue, UndefinedValue};
use js::rust::wrappers::{JS_GetProperty, JS_IsArrayObject}; use js::rust::wrappers::{JS_GetProperty, JS_HasProperty, JS_IsArrayObject};
use js::rust::{get_object_class, is_dom_class, is_dom_object, maybe_wrap_value, ToString}; use js::rust::{get_object_class, is_dom_class, is_dom_object, maybe_wrap_value, ToString};
use js::rust::{HandleId, HandleObject, HandleValue, MutableHandleValue}; use js::rust::{HandleId, HandleObject, HandleValue, MutableHandleValue};
use num_traits::Float; use num_traits::Float;
@ -596,11 +596,18 @@ pub unsafe fn get_property_jsval(
Ok(cname) => cname, Ok(cname) => cname,
Err(_) => return Ok(()), Err(_) => return Ok(()),
}; };
JS_GetProperty(cx, object, cname.as_ptr(), rval); let mut found = false;
if JS_IsExceptionPending(cx) { if JS_HasProperty(cx, object, cname.as_ptr(), &mut found) && found {
return Err(Error::JSFailed); JS_GetProperty(cx, object, cname.as_ptr(), rval);
if JS_IsExceptionPending(cx) {
return Err(Error::JSFailed);
}
Ok(())
} else if JS_IsExceptionPending(cx) {
Err(Error::JSFailed)
} else {
Ok(())
} }
Ok(())
} }
/// Get a property from a JS object, and convert it to a Rust value. /// Get a property from a JS object, and convert it to a Rust value.

View file

@ -2157,6 +2157,15 @@ impl ScriptThread {
reply, reply,
) )
}, },
WebDriverScriptCommand::GetElementProperty(node_id, name, reply) => {
webdriver_handlers::handle_get_property(
&*documents,
pipeline_id,
node_id,
name,
reply,
)
},
WebDriverScriptCommand::GetElementCSS(node_id, name, reply) => { WebDriverScriptCommand::GetElementCSS(node_id, name, reply) => {
webdriver_handlers::handle_get_css(&*documents, pipeline_id, node_id, name, reply) webdriver_handlers::handle_get_css(&*documents, pipeline_id, node_id, name, reply)
}, },

View file

@ -12,9 +12,11 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::XMLSerializerBinding::XMLSerializerMethods; use crate::dom::bindings::codegen::Bindings::XMLSerializerBinding::XMLSerializerMethods;
use crate::dom::bindings::conversions::{ use crate::dom::bindings::conversions::{
ConversionResult, FromJSValConvertible, StringificationBehavior, get_property_jsval, ConversionResult, FromJSValConvertible, StringificationBehavior,
}; };
use crate::dom::bindings::error::throw_dom_exception;
use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::element::Element; use crate::dom::element::Element;
@ -710,6 +712,43 @@ pub fn handle_get_attribute(
.unwrap(); .unwrap();
} }
#[allow(unsafe_code)]
pub fn handle_get_property(
documents: &Documents,
pipeline: PipelineId,
node_id: String,
name: String,
reply: IpcSender<Result<WebDriverJSValue, ()>>,
) {
reply
.send(match find_node_by_unique_id(documents, pipeline, node_id) {
Some(node) => {
let cx = documents.find_document(pipeline).unwrap().window().get_cx();
rooted!(in(cx) let mut property = UndefinedValue());
match unsafe {
get_property_jsval(
cx,
node.reflector().get_jsobject(),
&name,
property.handle_mut(),
)
} {
Ok(_) => match unsafe { jsval_to_webdriver(cx, property.handle()) } {
Ok(property) => Ok(property),
Err(_) => Ok(WebDriverJSValue::Undefined),
},
Err(error) => {
unsafe { throw_dom_exception(cx, &node.reflector().global(), error) };
Ok(WebDriverJSValue::Undefined)
},
}
},
None => Err(()),
})
.unwrap();
}
pub fn handle_get_css( pub fn handle_get_css(
documents: &Documents, documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,

View file

@ -41,6 +41,7 @@ pub enum WebDriverScriptCommand {
GetCookie(String, IpcSender<Vec<Serde<Cookie<'static>>>>), GetCookie(String, IpcSender<Vec<Serde<Cookie<'static>>>>),
GetCookies(IpcSender<Vec<Serde<Cookie<'static>>>>), GetCookies(IpcSender<Vec<Serde<Cookie<'static>>>>),
GetElementAttribute(String, String, IpcSender<Result<Option<String>, ()>>), GetElementAttribute(String, String, IpcSender<Result<Option<String>, ()>>),
GetElementProperty(String, String, IpcSender<Result<WebDriverJSValue, ()>>),
GetElementCSS(String, String, IpcSender<Result<String, ()>>), GetElementCSS(String, String, IpcSender<Result<String, ()>>),
GetElementRect(String, IpcSender<Result<Rect<f64>, ()>>), GetElementRect(String, IpcSender<Result<Rect<f64>, ()>>),
GetElementTagName(String, IpcSender<Result<String, ()>>), GetElementTagName(String, IpcSender<Result<String, ()>>),
@ -59,7 +60,7 @@ pub enum WebDriverCookieError {
UnableToSetCookie, UnableToSetCookie,
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub enum WebDriverJSValue { pub enum WebDriverJSValue {
Undefined, Undefined,
Null, Null,

View file

@ -211,6 +211,7 @@ impl WebDriverExtensionCommand for ServoExtensionCommand {
} }
} }
#[derive(Clone)]
struct SendableWebDriverJSValue(pub WebDriverJSValue); struct SendableWebDriverJSValue(pub WebDriverJSValue);
impl Serialize for SendableWebDriverJSValue { impl Serialize for SendableWebDriverJSValue {
@ -1163,6 +1164,28 @@ impl Handler {
} }
} }
fn handle_element_property(
&self,
element: &WebElement,
name: &str,
) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap();
let cmd =
WebDriverScriptCommand::GetElementProperty(element.id.clone(), name.to_owned(), sender);
self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(SendableWebDriverJSValue(value))?,
))),
Err(_) => Err(WebDriverError::new(
ErrorStatus::StaleElementReference,
"Unable to find element in document",
)),
}
}
fn handle_element_css( fn handle_element_css(
&self, &self,
element: &WebElement, element: &WebElement,
@ -1586,6 +1609,9 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler {
WebDriverCommand::GetElementAttribute(ref element, ref name) => { WebDriverCommand::GetElementAttribute(ref element, ref name) => {
self.handle_element_attribute(element, name) self.handle_element_attribute(element, name)
}, },
WebDriverCommand::GetElementProperty(ref element, ref name) => {
self.handle_element_property(element, name)
},
WebDriverCommand::GetCSSValue(ref element, ref name) => { WebDriverCommand::GetCSSValue(ref element, ref name) => {
self.handle_element_css(element, name) self.handle_element_css(element, name)
}, },

View file

@ -8,24 +8,15 @@
[test_visibility_hidden] [test_visibility_hidden]
expected: FAIL expected: FAIL
[test_transparent_element]
expected: FAIL
[test_iframe_is_interactable] [test_iframe_is_interactable]
expected: FAIL expected: FAIL
[test_readonly_element] [test_readonly_element]
expected: FAIL expected: FAIL
[test_obscured_element]
expected: FAIL
[test_document_element_is_interactable] [test_document_element_is_interactable]
expected: FAIL expected: FAIL
[test_body_is_interactable]
expected: FAIL
[test_hidden] [test_hidden]
expected: FAIL expected: FAIL

View file

@ -1,2 +1,31 @@
[get.py] [get.py]
disabled: Unimplemented WebDriver command [test_primitives[js_primitive3-py_primitive3\]]
expected: FAIL
[test_idl_attribute]
expected: FAIL
[test_element_not_found]
expected: FAIL
[test_primitives_set_by_execute_script[42-42\]]
expected: FAIL
[test_primitives[js_primitive2-py_primitive2\]]
expected: FAIL
[test_primitives_set_by_execute_script[js_primitive2-py_primitive2\]]
expected: FAIL
[test_mutated_element]
expected: FAIL
[test_no_browsing_context]
expected: ERROR
[test_primitives_set_by_execute_script[js_primitive3-py_primitive3\]]
expected: FAIL
[test_primitives_set_by_execute_script["foobar"-foobar\]]
expected: FAIL

View file

@ -2,15 +2,9 @@
[test_history_pushstate] [test_history_pushstate]
expected: FAIL expected: FAIL
[test_basic]
expected: FAIL
[test_refresh_switches_to_parent_browsing_context] [test_refresh_switches_to_parent_browsing_context]
expected: FAIL expected: FAIL
[test_no_browsing_context] [test_no_browsing_context]
expected: ERROR expected: ERROR
[test_dismissed_beforeunload]
expected: FAIL