Implement link and partial link text selectors for FindElement and related WebDriver commands

This commit is contained in:
George Roman 2019-06-20 17:53:02 +03:00
parent 75275965f0
commit 0ec852eb41
8 changed files with 183 additions and 102 deletions

View file

@ -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,

View file

@ -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<Item = String> + '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::<Node>().unique_id())
}
fn all_matching_links(
root_node: &Node,
link_text: String,
partial: bool,
) -> Result<Vec<String>, ()> {
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<Option<String>, ()> {
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<Result<Option<String>, ()>>,
) {
let node_id = documents
.find_document(pipeline)
.ok_or(())
.and_then(|doc| first_matching_link(&doc.upcast::<Node>(), 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<Result<Vec<String>, ()>>,
) {
let node_ids = documents
.find_document(pipeline)
.ok_or(())
.and_then(|doc| all_matching_links(&doc.upcast::<Node>(), 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<Result<Option<String>, ()>>,
) {
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<Result<Vec<String>, ()>>,
) {
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,

View file

@ -25,12 +25,16 @@ pub enum WebDriverScriptCommand {
ExecuteScript(String, IpcSender<WebDriverJSResult>),
ExecuteAsyncScript(String, IpcSender<WebDriverJSResult>),
FindElementCSS(String, IpcSender<Result<Option<String>, ()>>),
FindElementLinkText(String, bool, IpcSender<Result<Option<String>, ()>>),
FindElementTagName(String, IpcSender<Result<Option<String>, ()>>),
FindElementsCSS(String, IpcSender<Result<Vec<String>, ()>>),
FindElementsLinkText(String, bool, IpcSender<Result<Vec<String>, ()>>),
FindElementsTagName(String, IpcSender<Result<Vec<String>, ()>>),
FindElementElementCSS(String, String, IpcSender<Result<Option<String>, ()>>),
FindElementElementLinkText(String, String, bool, IpcSender<Result<Option<String>, ()>>),
FindElementElementTagName(String, String, IpcSender<Result<Option<String>, ()>>),
FindElementElementsCSS(String, String, IpcSender<Result<Vec<String>, ()>>),
FindElementElementsLinkText(String, String, bool, IpcSender<Result<Vec<String>, ()>>),
FindElementElementsTagName(String, String, IpcSender<Result<Vec<String>, ()>>),
FocusElement(String, IpcSender<Result<(), ()>>),
GetActiveElement(IpcSender<Option<String>>),

View file

@ -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(),

View file

@ -2,72 +2,27 @@
[test_xhtml_namespace[css selector-#linkText\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>partial link&amp;text</a>-k&t\]]
expected: FAIL
[test_htmldocument[xpath-/html\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>&nbsp;partial link text&nbsp;</a>-link\]]
expected: FAIL
[test_find_element_link_text[<a href=#>link<br>text</a>-link\ntext\]]
expected: FAIL
[test_xhtml_namespace[xpath-//*[name()='a'\]\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=# style='text-transform: uppercase'>partial link text</a>-LINK\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>partial link text</a>-link\]]
expected: FAIL
[test_xhtml_namespace[tag name-a\]]
expected: FAIL
[test_find_element_link_text[<a href=#>link&amp;text</a>-link&text\]]
expected: FAIL
[test_find_element[partial link text-link text\]]
expected: FAIL
[test_find_element_link_text[<a href=#>LINK TEXT</a>-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[<a href=#>partial link<br>text</a>-k\nt\]]
expected: FAIL
[test_find_element_link_text[<a href=#>&nbsp;link text&nbsp;</a>-link text\]]
expected: FAIL
[test_find_element_link_text[<a href=# style='text-transform: uppercase'>link text</a>-LINK TEXT\]]
expected: FAIL
[test_no_element[css selector-#wontExist\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>PARTIAL LINK TEXT</a>-LINK\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>partial link text</a>-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[<a href=#>link text</a>-link text\]]
expected: FAIL
[test_no_browsing_context]
expected: ERROR

View file

@ -2,75 +2,30 @@
[test_xhtml_namespace[css selector-#linkText\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>partial link&amp;text</a>-k&t\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>&nbsp;partial link text&nbsp;</a>-link\]]
expected: FAIL
[test_find_element_link_text[<a href=#>link<br>text</a>-link\ntext\]]
expected: FAIL
[test_xhtml_namespace[xpath-//*[name()='a'\]\]]
expected: FAIL
[test_parent_htmldocument]
expected: FAIL
[test_find_element_partial_link_text[<a href=# style='text-transform: uppercase'>partial link text</a>-LINK\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>partial link text</a>-link\]]
expected: FAIL
[test_xhtml_namespace[tag name-a\]]
expected: FAIL
[test_find_element_link_text[<a href=#>link&amp;text</a>-link&text\]]
expected: FAIL
[test_find_element[partial link text-link text\]]
expected: FAIL
[test_find_element_link_text[<a href=#>LINK TEXT</a>-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[<a href=#>partial link<br>text</a>-k\nt\]]
expected: FAIL
[test_parent_of_document_node_errors]
expected: FAIL
[test_find_element_link_text[<a href=#>&nbsp;link text&nbsp;</a>-link text\]]
expected: FAIL
[test_find_element_link_text[<a href=# style='text-transform: uppercase'>link text</a>-LINK TEXT\]]
expected: FAIL
[test_no_element[css selector-#wontExist\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>PARTIAL LINK TEXT</a>-LINK\]]
expected: FAIL
[test_find_element_partial_link_text[<a href=#>partial link text</a>-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[<a href=#>link text</a>-link text\]]
expected: FAIL
[test_no_browsing_context]
expected: ERROR

View file

@ -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[<a href=# style='text-transform: uppercase'>link text</a>-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[<a href=#>partial link text</a>-k t\]]
expected: FAIL

View file

@ -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[<a href=# style='text-transform: uppercase'>link text</a>-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[<a href=#>partial link text</a>-k t\]]
expected: FAIL