Bug 1328726 - (wdclient) Add actions endpoints, key actions API. r=ato, a=test-only
authorMaja Frydrychowicz <mjzffr@gmail.com>
Tue, 24 Jan 2017 16:18:24 -0500
changeset 378810 5b1d46b36da7c51af990b3c0ad3690a10d8f780f
parent 378809 d9e64da4d0419653bd6b4b22864e0a386f2702b4
child 378811 0f3caf166881bd92ca6275b7a75e5412e287ae0f
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato, test-only
bugs1328726
milestone53.0a2
Bug 1328726 - (wdclient) Add actions endpoints, key actions API. r=ato, a=test-only MozReview-Commit-ID: CScEEaAgw0X
testing/web-platform/tests/tools/webdriver/webdriver/client.py
--- a/testing/web-platform/tests/tools/webdriver/webdriver/client.py
+++ b/testing/web-platform/tests/tools/webdriver/webdriver/client.py
@@ -65,16 +65,111 @@ class Timeouts(object):
         return self._implicit_wait
 
     @implicit_wait.setter
     def implicit_wait(self, value):
         self._set_timeouts("implicit wait", value)
         self._implicit_wait = value
 
 
+class ActionSequence(object):
+    """API for creating and performing action sequences.
+
+    Each action method adds one or more actions to a queue. When perform()
+    is called, the queued actions fire in order.
+
+    May be chained together as in::
+
+         ActionSequence(session, "key", id) \
+            .key_down("a") \
+            .key_up("a") \
+            .perform()
+    """
+    def __init__(self, session, action_type, input_id):
+        """Represents a sequence of actions of one type for one input source.
+
+        :param session: WebDriver session.
+        :param action_type: Action type; may be "none", "key", or "pointer".
+        :param input_id: ID of input source.
+        """
+        self.session = session
+        # TODO take advantage of remote end generating uuid
+        self._id = input_id
+        self._type = action_type
+        self._actions = []
+
+    @property
+    def dict(self):
+        return {
+          "type": self._type,
+          "id": self._id,
+          "actions": self._actions,
+        }
+
+    @command
+    def perform(self):
+        """Perform all queued actions."""
+        self.session.actions.perform([self.dict])
+
+    def _key_action(self, subtype, value):
+        self._actions.append({"type": subtype, "value": value})
+
+    def key_up(self, value):
+        """Queue a keyUp action for `value`.
+
+        :param value: Character to perform key action with.
+        """
+        self._key_action("keyUp", value)
+        return self
+
+    def key_down(self, value):
+        """Queue a keyDown action for `value`.
+
+        :param value: Character to perform key action with.
+        """
+        self._key_action("keyDown", value)
+        return self
+
+    def send_keys(self, keys):
+        """Queue a keyDown and keyUp action for each character in `keys`.
+
+        :param keys: String of keys to perform key actions with.
+        """
+        for c in keys:
+            self.key_down(c)
+            self.key_up(c)
+        return self
+
+
+class Actions(object):
+    def __init__(self, session):
+        self.session = session
+
+    @command
+    def perform(self, actions=None):
+        """Performs actions by tick from each action sequence in `actions`.
+
+        :param actions: List of input source action sequences. A single action
+                        sequence may be created with the help of
+                        ``ActionSequence.dict``.
+        """
+        body = {"actions": [] if actions is None else actions}
+        return self.session.send_command("POST", "actions", body)
+
+    @command
+    def release(self):
+        return self.session.send_command("DELETE", "actions")
+
+    def sequence(self, *args, **kwargs):
+        """Return an empty ActionSequence of the designated type.
+
+        See ActionSequence for parameter list.
+        """
+        return ActionSequence(self.session, *args, **kwargs)
+
 class Window(object):
     def __init__(self, session):
         self.session = session
 
     @property
     @command
     def size(self):
         resp = self.session.send_command("GET", "window/size")
@@ -185,16 +280,17 @@ class Session(object):
         self._element_cache = {}
         self.extension = None
         self.extension_cls = extension
 
         self.timeouts = Timeouts(self)
         self.window = Window(self)
         self.find = Find(self)
         self.alert = UserPrompt(self)
+        self.actions = Actions(self)
 
     def __enter__(self):
         self.start()
         return self
 
     def __exit__(self, *args, **kwargs):
         self.end()