diff --git a/tools/webdriver/webdriver/client.py b/tools/webdriver/webdriver/client.py index 52ebc95e84aaea..947e42d7f857a4 100644 --- a/tools/webdriver/webdriver/client.py +++ b/tools/webdriver/webdriver/client.py @@ -218,7 +218,9 @@ def perform(self, actions=None): ``ActionSequence.dict``. """ body = {"actions": [] if actions is None else actions} - return self.session.send_session_command("POST", "actions", body) + actions = self.session.send_session_command("POST", "actions", body) + self.session.switch_frame(None) + return actions @command def release(self): @@ -308,8 +310,11 @@ def __init__(self, session): self.session = session @command - def css(self, selector, all=True): - return self._find_element("css selector", selector, all) + def css(self, element_selector, frame, all=True): + if (frame != "window"): + self.session.switch_frame(frame) + elements = self._find_element("css selector", element_selector, all) + return elements def _find_element(self, strategy, selector, all): route = "elements" if all else "element" diff --git a/tools/wptrunner/wptrunner/executors/base.py b/tools/wptrunner/wptrunner/executors/base.py index d1c123a3ef39c0..588e0b2fad6afb 100644 --- a/tools/wptrunner/wptrunner/executors/base.py +++ b/tools/wptrunner/wptrunner/executors/base.py @@ -669,11 +669,11 @@ def __call__(self, payload): for action in actionSequence["actions"]: if (action["type"] == "pointerMove" and isinstance(action["origin"], dict)): - action["origin"] = self.get_element(action["origin"]["selector"]) + action["origin"] = self.get_element(action["origin"]["selector"], action["frame"]["frame"]) self.protocol.action_sequence.send_actions({"actions": actions}) - def get_element(self, selector): - element = self.protocol.select.element_by_selector(selector) + def get_element(self, element_selector, frame): + element = self.protocol.select.element_by_selector(element_selector, frame) return element class GenerateTestReportAction(object): diff --git a/tools/wptrunner/wptrunner/executors/executormarionette.py b/tools/wptrunner/wptrunner/executors/executormarionette.py index 7ab701879ff1c0..c46571bd544927 100644 --- a/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/tools/wptrunner/wptrunner/executors/executormarionette.py @@ -386,6 +386,9 @@ def setup(self): def elements_by_selector(self, selector): return self.marionette.find_elements("css selector", selector) + def elements_by_selector_and_frame(self, element_selector, frame): + return self.marionette.find_elements("css selector", element_selector) + class MarionetteClickProtocolPart(ClickProtocolPart): def setup(self): diff --git a/tools/wptrunner/wptrunner/executors/executorselenium.py b/tools/wptrunner/wptrunner/executors/executorselenium.py index e7b9f45dc81d5f..9a2d223f649535 100644 --- a/tools/wptrunner/wptrunner/executors/executorselenium.py +++ b/tools/wptrunner/wptrunner/executors/executorselenium.py @@ -149,6 +149,9 @@ def setup(self): def elements_by_selector(self, selector): return self.webdriver.find_elements_by_css_selector(selector) + def elements_by_selector_and_frame(self, element_selector, frame): + return self.webdriver.find_elements_by_css_selector(element_selector) + class SeleniumClickProtocolPart(ClickProtocolPart): def setup(self): diff --git a/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/tools/wptrunner/wptrunner/executors/executorwebdriver.py index 65938a7678b1ae..ce7691c4d565ac 100644 --- a/tools/wptrunner/wptrunner/executors/executorwebdriver.py +++ b/tools/wptrunner/wptrunner/executors/executorwebdriver.py @@ -142,6 +142,9 @@ def setup(self): def elements_by_selector(self, selector): return self.webdriver.find.css(selector) + def elements_by_selector_and_frame(self, element_selector, frame): + return self.webdriver.find.css(element_selector, frame) + class WebDriverClickProtocolPart(ClickProtocolPart): def setup(self): diff --git a/tools/wptrunner/wptrunner/executors/protocol.py b/tools/wptrunner/wptrunner/executors/protocol.py index d08b74bfc36ae9..afc6b7df901b39 100644 --- a/tools/wptrunner/wptrunner/executors/protocol.py +++ b/tools/wptrunner/wptrunner/executors/protocol.py @@ -235,12 +235,15 @@ class SelectorProtocolPart(ProtocolPart): name = "select" - def element_by_selector(self, selector): - elements = self.elements_by_selector(selector) + def element_by_selector(self, element_selector, frame="window"): + elements = self.elements_by_selector_and_frame(element_selector, frame) + frame_name = "window" + if (frame != "window"): + frame_name = frame.id if len(elements) == 0: - raise ValueError("Selector '%s' matches no elements" % selector) + raise ValueError("Selector '%s' in frame '%s' matches no elements" % (element_selector, frame_name)) elif len(elements) > 1: - raise ValueError("Selector '%s' matches multiple elements" % selector) + raise ValueError("Selector '%s' in frame '%s' matches multiple elements" % (element_selector, frame_name)) return elements[0] @abstractmethod @@ -251,6 +254,14 @@ def elements_by_selector(self, selector): :returns: A list of protocol-specific handles to elements""" pass + @abstractmethod + def elements_by_selector_and_frame(self, element_selector, frame): + """Select elements matching a CSS selector + + :param str selector: The CSS selector + :returns: A list of protocol-specific handles to elements""" + pass + class ClickProtocolPart(ProtocolPart): """Protocol part for performing trusted clicks""" diff --git a/tools/wptrunner/wptrunner/testdriver-extra.js b/tools/wptrunner/wptrunner/testdriver-extra.js index 09d7c290867122..edd172ac080622 100644 --- a/tools/wptrunner/wptrunner/testdriver-extra.js +++ b/tools/wptrunner/wptrunner/testdriver-extra.js @@ -21,10 +21,26 @@ } }); + const get_frame = function(element, frame) { + let foundFrame = frame; + let frameDocument = frame == window ? window.document : frame.contentDocument; + if (!frameDocument.contains(element)) { + foundFrame = null; + let frames = document.getElementsByTagName("iframe"); + for (let i = 0; i < frames.length; i++) { + if (get_frame(element, frames[i])) { + foundFrame = frames[i]; + break; + } + } + } + return foundFrame; + }; + const get_selector = function(element) { let selector; - if (element.id && document.getElementById(element.id) === element) { + if (element.id) { const id = element.id; selector = "#"; @@ -81,8 +97,16 @@ for (let actionSequence of actions) { if (actionSequence.type == "pointer") { for (let action of actionSequence.actions) { - if (action.type == "pointerMove" && action.origin instanceof Element) { - action.origin = {selector: get_selector(action.origin)}; + // The origin of each action can only be an element or a string of a value "viewport" or "pointer". + if (action.type == "pointerMove" && typeof(action.origin) != 'string') { + let frame = get_frame(action.origin, window); + if (frame != null) { + if (frame == window) + action.frame = {frame: "window"}; + else + action.frame = {frame: frame}; + action.origin = {selector: get_selector(action.origin)}; + } } } }