From 0ec852eb4131f39cab66f13321c18a425c66caad Mon Sep 17 00:00:00 2001 From: George Roman Date: Thu, 20 Jun 2019 17:53:02 +0300 Subject: [PATCH] Implement link and partial link text selectors for FindElement and related WebDriver commands --- components/script/script_thread.rs | 44 ++++++++ components/script/webdriver_handlers.rs | 101 ++++++++++++++++++ components/script_traits/webdriver_msg.rs | 4 + components/webdriver_server/lib.rs | 34 ++++++ .../webdriver/tests/find_element/find.py.ini | 45 -------- .../find_element_from_element/find.py.ini | 45 -------- .../webdriver/tests/find_elements/find.py.ini | 6 -- .../find_elements_from_element/find.py.ini | 6 -- 8 files changed, 183 insertions(+), 102 deletions(-) diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index ae18f075b0e..07626cc80bd 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -2019,6 +2019,15 @@ impl ScriptThread { reply, ) }, + WebDriverScriptCommand::FindElementLinkText(selector, partial, reply) => { + webdriver_handlers::handle_find_element_link_text( + &*documents, + pipeline_id, + selector, + partial, + reply, + ) + }, WebDriverScriptCommand::FindElementTagName(selector, reply) => { webdriver_handlers::handle_find_element_tag_name( &*documents, @@ -2035,6 +2044,15 @@ impl ScriptThread { reply, ) }, + WebDriverScriptCommand::FindElementsLinkText(selector, partial, reply) => { + webdriver_handlers::handle_find_elements_link_text( + &*documents, + pipeline_id, + selector, + partial, + reply, + ) + }, WebDriverScriptCommand::FindElementsTagName(selector, reply) => { webdriver_handlers::handle_find_elements_tag_name( &*documents, @@ -2052,6 +2070,19 @@ impl ScriptThread { reply, ) }, + WebDriverScriptCommand::FindElementElementLinkText( + selector, + element_id, + partial, + reply, + ) => webdriver_handlers::handle_find_element_element_link_text( + &*documents, + pipeline_id, + element_id, + selector, + partial, + reply, + ), WebDriverScriptCommand::FindElementElementTagName(selector, element_id, reply) => { webdriver_handlers::handle_find_element_element_tag_name( &*documents, @@ -2070,6 +2101,19 @@ impl ScriptThread { reply, ) }, + WebDriverScriptCommand::FindElementElementsLinkText( + selector, + element_id, + partial, + reply, + ) => webdriver_handlers::handle_find_element_elements_link_text( + &*documents, + pipeline_id, + element_id, + selector, + partial, + reply, + ), WebDriverScriptCommand::FindElementElementsTagName(selector, element_id, reply) => { webdriver_handlers::handle_find_element_elements_tag_name( &*documents, diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index c960878f60d..03b61875b3b 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -24,6 +24,7 @@ use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmlinputelement::HTMLInputElement; use crate::dom::htmloptionelement::HTMLOptionElement; 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_thread::Documents; @@ -58,6 +59,50 @@ fn find_node_by_unique_id( }) } +fn matching_links<'a>( + links: &'a NodeList, + link_text: String, + partial: bool, +) -> impl Iterator + 'a { + links + .iter() + .filter(move |node| { + let content = node + .GetTextContent() + .map_or("".to_owned(), String::from) + .trim() + .to_owned(); + if partial { + content.contains(&link_text) + } else { + content == link_text + } + }) + .map(|node| node.upcast::().unique_id()) +} + +fn all_matching_links( + root_node: &Node, + link_text: String, + partial: bool, +) -> Result, ()> { + root_node + .query_selector_all(DOMString::from("a")) + .map_err(|_| ()) + .map(|nodes| matching_links(&nodes, link_text, partial).collect()) +} + +fn first_matching_link( + root_node: &Node, + link_text: String, + partial: bool, +) -> Result, ()> { + root_node + .query_selector_all(DOMString::from("a")) + .map_err(|_| ()) + .map(|nodes| matching_links(&nodes, link_text, partial).take(1).next()) +} + #[allow(unsafe_code)] pub unsafe fn jsval_to_webdriver(cx: *mut JSContext, val: HandleValue) -> WebDriverJSResult { if val.get().is_undefined() { @@ -182,6 +227,20 @@ pub fn handle_find_element_css( reply.send(node_id).unwrap(); } +pub fn handle_find_element_link_text( + documents: &Documents, + pipeline: PipelineId, + selector: String, + partial: bool, + reply: IpcSender, ()>>, +) { + let node_id = documents + .find_document(pipeline) + .ok_or(()) + .and_then(|doc| first_matching_link(&doc.upcast::(), selector.clone(), partial)); + reply.send(node_id).unwrap(); +} + pub fn handle_find_element_tag_name( documents: &Documents, pipeline: PipelineId, @@ -223,6 +282,20 @@ pub fn handle_find_elements_css( reply.send(node_ids).unwrap(); } +pub fn handle_find_elements_link_text( + documents: &Documents, + pipeline: PipelineId, + selector: String, + partial: bool, + reply: IpcSender, ()>>, +) { + let node_ids = documents + .find_document(pipeline) + .ok_or(()) + .and_then(|doc| all_matching_links(&doc.upcast::(), selector.clone(), partial)); + reply.send(node_ids).unwrap(); +} + pub fn handle_find_elements_tag_name( documents: &Documents, pipeline: PipelineId, @@ -259,6 +332,20 @@ pub fn handle_find_element_element_css( reply.send(node_id).unwrap(); } +pub fn handle_find_element_element_link_text( + documents: &Documents, + pipeline: PipelineId, + element_id: String, + selector: String, + partial: bool, + reply: IpcSender, ()>>, +) { + let node_id = find_node_by_unique_id(documents, pipeline, element_id) + .ok_or(()) + .and_then(|node| first_matching_link(&node, selector.clone(), partial)); + reply.send(node_id).unwrap(); +} + pub fn handle_find_element_element_tag_name( documents: &Documents, pipeline: PipelineId, @@ -301,6 +388,20 @@ pub fn handle_find_element_elements_css( reply.send(node_ids).unwrap(); } +pub fn handle_find_element_elements_link_text( + documents: &Documents, + pipeline: PipelineId, + element_id: String, + selector: String, + partial: bool, + reply: IpcSender, ()>>, +) { + let node_ids = find_node_by_unique_id(documents, pipeline, element_id) + .ok_or(()) + .and_then(|node| all_matching_links(&node, selector.clone(), partial)); + reply.send(node_ids).unwrap(); +} + pub fn handle_find_element_elements_tag_name( documents: &Documents, pipeline: PipelineId, diff --git a/components/script_traits/webdriver_msg.rs b/components/script_traits/webdriver_msg.rs index d0b0357309f..db7fc65d042 100644 --- a/components/script_traits/webdriver_msg.rs +++ b/components/script_traits/webdriver_msg.rs @@ -25,12 +25,16 @@ pub enum WebDriverScriptCommand { ExecuteScript(String, IpcSender), ExecuteAsyncScript(String, IpcSender), FindElementCSS(String, IpcSender, ()>>), + FindElementLinkText(String, bool, IpcSender, ()>>), FindElementTagName(String, IpcSender, ()>>), FindElementsCSS(String, IpcSender, ()>>), + FindElementsLinkText(String, bool, IpcSender, ()>>), FindElementsTagName(String, IpcSender, ()>>), FindElementElementCSS(String, String, IpcSender, ()>>), + FindElementElementLinkText(String, String, bool, IpcSender, ()>>), FindElementElementTagName(String, String, IpcSender, ()>>), FindElementElementsCSS(String, String, IpcSender, ()>>), + FindElementElementsLinkText(String, String, bool, IpcSender, ()>>), FindElementElementsTagName(String, String, IpcSender, ()>>), FocusElement(String, IpcSender>), GetActiveElement(IpcSender>), diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index d938a5153fb..d227973edc9 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -811,6 +811,14 @@ impl Handler { let cmd = WebDriverScriptCommand::FindElementCSS(parameters.value.clone(), sender); self.browsing_context_script_command(cmd)?; }, + LocatorStrategy::LinkText | LocatorStrategy::PartialLinkText => { + let cmd = WebDriverScriptCommand::FindElementLinkText( + parameters.value.clone(), + parameters.using == LocatorStrategy::PartialLinkText, + sender, + ); + self.browsing_context_script_command(cmd)?; + }, LocatorStrategy::TagName => { let cmd = WebDriverScriptCommand::FindElementTagName(parameters.value.clone(), sender); @@ -914,6 +922,14 @@ impl Handler { let cmd = WebDriverScriptCommand::FindElementsCSS(parameters.value.clone(), sender); self.browsing_context_script_command(cmd)?; }, + LocatorStrategy::LinkText | LocatorStrategy::PartialLinkText => { + let cmd = WebDriverScriptCommand::FindElementsLinkText( + parameters.value.clone(), + parameters.using == LocatorStrategy::PartialLinkText, + sender, + ); + self.browsing_context_script_command(cmd)?; + }, LocatorStrategy::TagName => { let cmd = WebDriverScriptCommand::FindElementsTagName(parameters.value.clone(), sender); @@ -961,6 +977,15 @@ impl Handler { ); self.browsing_context_script_command(cmd)?; }, + LocatorStrategy::LinkText | LocatorStrategy::PartialLinkText => { + let cmd = WebDriverScriptCommand::FindElementElementLinkText( + parameters.value.clone(), + element.id.clone(), + parameters.using == LocatorStrategy::PartialLinkText, + sender, + ); + self.browsing_context_script_command(cmd)?; + }, LocatorStrategy::TagName => { let cmd = WebDriverScriptCommand::FindElementElementTagName( parameters.value.clone(), @@ -1008,6 +1033,15 @@ impl Handler { ); self.browsing_context_script_command(cmd)?; }, + LocatorStrategy::LinkText | LocatorStrategy::PartialLinkText => { + let cmd = WebDriverScriptCommand::FindElementElementsLinkText( + parameters.value.clone(), + element.id.clone(), + parameters.using == LocatorStrategy::PartialLinkText, + sender, + ); + self.browsing_context_script_command(cmd)?; + }, LocatorStrategy::TagName => { let cmd = WebDriverScriptCommand::FindElementElementsTagName( parameters.value.clone(), diff --git a/tests/wpt/metadata/webdriver/tests/find_element/find.py.ini b/tests/wpt/metadata/webdriver/tests/find_element/find.py.ini index 7bdd2a78362..a03197015f7 100644 --- a/tests/wpt/metadata/webdriver/tests/find_element/find.py.ini +++ b/tests/wpt/metadata/webdriver/tests/find_element/find.py.ini @@ -2,72 +2,27 @@ [test_xhtml_namespace[css selector-#linkText\]] expected: FAIL - [test_find_element_partial_link_text[partial link&text-k&t\]] - expected: FAIL - [test_htmldocument[xpath-/html\]] expected: FAIL - [test_find_element_partial_link_text[ partial link text -link\]] - expected: FAIL - - [test_find_element_link_text[link
text
-link\ntext\]] - expected: FAIL - [test_xhtml_namespace[xpath-//*[name()='a'\]\]] expected: FAIL - [test_find_element_partial_link_text[partial link text-LINK\]] - expected: FAIL - - [test_find_element_partial_link_text[partial link text-link\]] - expected: FAIL - [test_xhtml_namespace[tag name-a\]] expected: FAIL - [test_find_element_link_text[link&text-link&text\]] - expected: FAIL - - [test_find_element[partial link text-link text\]] - expected: FAIL - - [test_find_element_link_text[LINK TEXT-LINK TEXT\]] - expected: FAIL - [test_xhtml_namespace[link text-full link text\]] expected: FAIL - [test_find_element[link text-full link text\]] - expected: FAIL - - [test_find_element_partial_link_text[partial link
text
-k\nt\]] - expected: FAIL - - [test_find_element_link_text[ link text -link text\]] - expected: FAIL - - [test_find_element_link_text[link text-LINK TEXT\]] - expected: FAIL - [test_no_element[css selector-#wontExist\]] expected: FAIL - [test_find_element_partial_link_text[PARTIAL LINK TEXT-LINK\]] - expected: FAIL - - [test_find_element_partial_link_text[partial link text-k t\]] - expected: FAIL - [test_xhtml_namespace[partial link text-link text\]] expected: FAIL [test_find_element[xpath-//a\]] expected: FAIL - [test_find_element_link_text[link text-link text\]] - expected: FAIL - [test_no_browsing_context] expected: ERROR diff --git a/tests/wpt/metadata/webdriver/tests/find_element_from_element/find.py.ini b/tests/wpt/metadata/webdriver/tests/find_element_from_element/find.py.ini index ab4ed4ee7c9..26433cb614c 100644 --- a/tests/wpt/metadata/webdriver/tests/find_element_from_element/find.py.ini +++ b/tests/wpt/metadata/webdriver/tests/find_element_from_element/find.py.ini @@ -2,75 +2,30 @@ [test_xhtml_namespace[css selector-#linkText\]] expected: FAIL - [test_find_element_partial_link_text[partial link&text-k&t\]] - expected: FAIL - - [test_find_element_partial_link_text[ partial link text -link\]] - expected: FAIL - - [test_find_element_link_text[link
text
-link\ntext\]] - expected: FAIL - [test_xhtml_namespace[xpath-//*[name()='a'\]\]] expected: FAIL [test_parent_htmldocument] expected: FAIL - [test_find_element_partial_link_text[partial link text-LINK\]] - expected: FAIL - - [test_find_element_partial_link_text[partial link text-link\]] - expected: FAIL - [test_xhtml_namespace[tag name-a\]] expected: FAIL - [test_find_element_link_text[link&text-link&text\]] - expected: FAIL - - [test_find_element[partial link text-link text\]] - expected: FAIL - - [test_find_element_link_text[LINK TEXT-LINK TEXT\]] - expected: FAIL - [test_xhtml_namespace[link text-full link text\]] expected: FAIL - [test_find_element[link text-full link text\]] - expected: FAIL - - [test_find_element_partial_link_text[partial link
text
-k\nt\]] - expected: FAIL - [test_parent_of_document_node_errors] expected: FAIL - [test_find_element_link_text[ link text -link text\]] - expected: FAIL - - [test_find_element_link_text[link text-LINK TEXT\]] - expected: FAIL - [test_no_element[css selector-#wontExist\]] expected: FAIL - [test_find_element_partial_link_text[PARTIAL LINK TEXT-LINK\]] - expected: FAIL - - [test_find_element_partial_link_text[partial link text-k t\]] - expected: FAIL - [test_xhtml_namespace[partial link text-link text\]] expected: FAIL [test_find_element[xpath-//a\]] expected: FAIL - [test_find_element_link_text[link text-link text\]] - expected: FAIL - [test_no_browsing_context] expected: ERROR diff --git a/tests/wpt/metadata/webdriver/tests/find_elements/find.py.ini b/tests/wpt/metadata/webdriver/tests/find_elements/find.py.ini index 27b11b2d6ad..f61c9e9c94b 100644 --- a/tests/wpt/metadata/webdriver/tests/find_elements/find.py.ini +++ b/tests/wpt/metadata/webdriver/tests/find_elements/find.py.ini @@ -11,9 +11,6 @@ [test_xhtml_namespace[xpath-//*[name()='a'\]\]] expected: FAIL - [test_find_elements[link text-full link text\]] - expected: FAIL - [test_find_elements_link_text[link text-LINK TEXT\]] expected: FAIL @@ -35,9 +32,6 @@ [test_xhtml_namespace[link text-full link text\]] expected: FAIL - [test_find_elements[partial link text-link text\]] - expected: FAIL - [test_find_elements_partial_link_text[partial link text-k t\]] expected: FAIL diff --git a/tests/wpt/metadata/webdriver/tests/find_elements_from_element/find.py.ini b/tests/wpt/metadata/webdriver/tests/find_elements_from_element/find.py.ini index 52f2c179c81..125027d9d0c 100644 --- a/tests/wpt/metadata/webdriver/tests/find_elements_from_element/find.py.ini +++ b/tests/wpt/metadata/webdriver/tests/find_elements_from_element/find.py.ini @@ -11,9 +11,6 @@ [test_xhtml_namespace[css selector-#linkText\]] expected: FAIL - [test_find_elements[link text-full link text\]] - expected: FAIL - [test_find_elements_link_text[link text-LINK TEXT\]] expected: FAIL @@ -35,9 +32,6 @@ [test_xhtml_namespace[link text-full link text\]] expected: FAIL - [test_find_elements[partial link text-link text\]] - expected: FAIL - [test_find_elements_partial_link_text[partial link text-k t\]] expected: FAIL