Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / page / actions / action_runner.py
index f4135f7..ca6e7c0 100644 (file)
@@ -5,25 +5,33 @@
 import time
 
 from telemetry.page.actions.javascript_click import ClickElementAction
+from telemetry.page.actions.loop import LoopAction
 from telemetry.page.actions.navigate import NavigateAction
+from telemetry.page.actions.pinch import PinchAction
+from telemetry.page.actions.play import PlayAction
+from telemetry.page.actions.repaint_continuously import (
+    RepaintContinuouslyAction)
+from telemetry.page.actions.scroll import ScrollAction
+from telemetry.page.actions.scroll_bounce import ScrollBounceAction
+from telemetry.page.actions.seek import SeekAction
 from telemetry.page.actions.swipe import SwipeAction
 from telemetry.page.actions.tap import TapAction
 from telemetry.page.actions.wait import WaitForElementAction
-from telemetry.web_perf import timeline_interaction_record as tir_module
+from telemetry.web_perf import timeline_interaction_record
 
 
 class ActionRunner(object):
 
-  def __init__(self, tab):
+  def __init__(self, tab, skip_waits=False):
     self._tab = tab
+    self._skip_waits = skip_waits
 
-  # TODO(nednguyen): remove this (or make private) when
-  # crbug.com/361809 is marked fixed
-  def RunAction(self, action):
+  def _RunAction(self, action):
     action.WillRunAction(self._tab)
     action.RunAction(self._tab)
 
-  def BeginInteraction(self, label, is_smooth=False, is_responsive=False):
+  def BeginInteraction(self, label, is_fast=False, is_smooth=False,
+                       is_responsive=False, repeatable=False):
     """Marks the beginning of an interaction record.
 
     An interaction record is a labeled time period containing
@@ -35,22 +43,31 @@ class ActionRunner(object):
     Args:
       label: A label for this particular interaction. This can be any
           user-defined string, but must not contain '/'.
+      is_fast: Whether to measure how fast the browser completes necessary work
+          for this interaction record. See fast_metric.py for details.
       is_smooth: Whether to check for smoothness metrics for this interaction.
       is_responsive: Whether to check for responsiveness metrics for
           this interaction.
+      repeatable: Whether other interactions may use the same logical name
+          as this interaction. All interactions with the same logical name must
+          have the same flags.
     """
     flags = []
+    if is_fast:
+      flags.append(timeline_interaction_record.IS_FAST)
     if is_smooth:
-      flags.append(tir_module.IS_SMOOTH)
+      flags.append(timeline_interaction_record.IS_SMOOTH)
     if is_responsive:
-      flags.append(tir_module.IS_RESPONSIVE)
+      flags.append(timeline_interaction_record.IS_RESPONSIVE)
+    if repeatable:
+      flags.append(timeline_interaction_record.REPEATABLE)
 
     interaction = Interaction(self._tab, label, flags)
     interaction.Begin()
     return interaction
 
-  def BeginGestureInteraction(
-      self, label, is_smooth=False, is_responsive=False):
+  def BeginGestureInteraction(self, label, is_fast=False, is_smooth=False,
+                              is_responsive=False, repeatable=False):
     """Marks the beginning of a gesture-based interaction record.
 
     This is similar to normal interaction record, but it will
@@ -64,31 +81,41 @@ class ActionRunner(object):
     Args:
       label: A label for this particular interaction. This can be any
           user-defined string, but must not contain '/'.
+      is_fast: Whether to measure how fast the browser completes necessary work
+          for this interaction record. See fast_metric.py for details.
       is_smooth: Whether to check for smoothness metrics for this interaction.
       is_responsive: Whether to check for responsiveness metrics for
           this interaction.
+      repeatable: Whether other interactions may use the same logical name
+          as this interaction. All interactions with the same logical name must
+          have the same flags.
     """
-    return self.BeginInteraction('Gesture_' + label, is_smooth, is_responsive)
+    return self.BeginInteraction('Gesture_' + label, is_fast, is_smooth,
+                                 is_responsive, repeatable)
 
-  def NavigateToPage(self, page, timeout_seconds=None):
-    """ Navigate to the given page.
+  def NavigateToPage(self, page, timeout_in_seconds=60):
+    """Navigate to the given page.
 
     Args:
       page: page is an instance of page.Page
+      timeout_in_seconds: The timeout in seconds (default to 60).
     """
     if page.is_file:
       target_side_url = self._tab.browser.http_server.UrlOf(page.file_path_url)
     else:
       target_side_url = page.url
-    attributes = {
-        'url': target_side_url,
-        'script_to_evaluate_on_commit': page.script_to_evaluate_on_commit}
-    if timeout_seconds:
-      attributes['timeout_seconds'] = timeout_seconds
-    self.RunAction(NavigateAction(attributes))
-
-  def WaitForNavigate(self, timeout_seconds=60):
-    self._tab.WaitForNavigate(timeout_seconds)
+    self._RunAction(NavigateAction(
+        url=target_side_url,
+        script_to_evaluate_on_commit=page.script_to_evaluate_on_commit,
+        timeout_in_seconds=timeout_in_seconds))
+
+  def WaitForNavigate(self, timeout_in_seconds_seconds=60):
+    self._tab.WaitForNavigate(timeout_in_seconds_seconds)
+    self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+
+  def ReloadPage(self):
+    """Reloads the page."""
+    self._tab.ExecuteJavaScript('window.location.reload()')
     self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
 
   def ExecuteJavaScript(self, statement):
@@ -127,21 +154,22 @@ class ActionRunner(object):
     Args:
       seconds: The number of seconds to wait.
     """
-    time.sleep(seconds)
+    if not self._skip_waits:
+      time.sleep(seconds)
 
-  def WaitForJavaScriptCondition(self, condition, timeout=60):
+  def WaitForJavaScriptCondition(self, condition, timeout_in_seconds=60):
     """Wait for a JavaScript condition to become true.
 
     Example: runner.WaitForJavaScriptCondition('window.foo == 10');
 
     Args:
       condition: The JavaScript condition (as string).
-      timeout: The timeout in seconds (default to 60).
+      timeout_in_seconds: The timeout in seconds (default to 60).
     """
-    self._tab.WaitForJavaScriptExpression(condition, timeout)
+    self._tab.WaitForJavaScriptExpression(condition, timeout_in_seconds)
 
   def WaitForElement(self, selector=None, text=None, element_function=None,
-                     timeout=60):
+                     timeout_in_seconds=60):
     """Wait for an element to appear in the document.
 
     The element may be selected via selector, text, or element_function.
@@ -153,11 +181,11 @@ class ActionRunner(object):
       element_function: A JavaScript function (as string) that is used
           to retrieve the element. For example:
           '(function() { return foo.element; })()'.
-      timeout: The timeout in seconds (default to 60).
+      timeout_in_seconds: The timeout in seconds (default to 60).
     """
-    self.RunAction(WaitForElementAction(
+    self._RunAction(WaitForElementAction(
         selector=selector, text=text, element_function=element_function,
-        timeout=timeout))
+        timeout_in_seconds=timeout_in_seconds))
 
   def TapElement(self, selector=None, text=None, element_function=None):
     """Tap an element.
@@ -172,7 +200,7 @@ class ActionRunner(object):
           to retrieve the element. For example:
           '(function() { return foo.element; })()'.
     """
-    self.RunAction(TapAction(
+    self._RunAction(TapAction(
         selector=selector, text=text, element_function=element_function))
 
   def ClickElement(self, selector=None, text=None, element_function=None):
@@ -188,11 +216,211 @@ class ActionRunner(object):
           to retrieve the element. For example:
           '(function() { return foo.element; })()'.
     """
-    self.RunAction(ClickElementAction(
+    self._RunAction(ClickElementAction(
         selector=selector, text=text, element_function=element_function))
 
+  def PinchPage(self, left_anchor_ratio=0.5, top_anchor_ratio=0.5,
+                scale_factor=None, speed_in_pixels_per_second=800):
+    """Perform the pinch gesture on the page.
+
+    It computes the pinch gesture automatically based on the anchor
+    coordinate and the scale factor. The scale factor is the ratio of
+    of the final span and the initial span of the gesture.
+
+    Args:
+      left_anchor_ratio: The horizontal pinch anchor coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      top_anchor_ratio: The vertical pinch anchor coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      scale_factor: The ratio of the final span to the initial span.
+          The default scale factor is
+          3.0 / (window.outerWidth/window.innerWidth).
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
+    """
+    self._RunAction(PinchAction(
+        left_anchor_ratio=left_anchor_ratio, top_anchor_ratio=top_anchor_ratio,
+        scale_factor=scale_factor,
+        speed_in_pixels_per_second=speed_in_pixels_per_second))
+
+  def PinchElement(self, selector=None, text=None, element_function=None,
+                   left_anchor_ratio=0.5, top_anchor_ratio=0.5,
+                   scale_factor=None, speed_in_pixels_per_second=800):
+    """Perform the pinch gesture on an element.
+
+    It computes the pinch gesture automatically based on the anchor
+    coordinate and the scale factor. The scale factor is the ratio of
+    of the final span and the initial span of the gesture.
+
+    Args:
+      selector: A CSS selector describing the element.
+      text: The element must contains this exact text.
+      element_function: A JavaScript function (as string) that is used
+          to retrieve the element. For example:
+          'function() { return foo.element; }'.
+      left_anchor_ratio: The horizontal pinch anchor coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          the element.
+      top_anchor_ratio: The vertical pinch anchor coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          the element.
+      scale_factor: The ratio of the final span to the initial span.
+          The default scale factor is
+          3.0 / (window.outerWidth/window.innerWidth).
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
+    """
+    self._RunAction(PinchAction(
+        selector=selector, text=text, element_function=element_function,
+        left_anchor_ratio=left_anchor_ratio, top_anchor_ratio=top_anchor_ratio,
+        scale_factor=scale_factor,
+        speed_in_pixels_per_second=speed_in_pixels_per_second))
+
+  def ScrollPage(self, left_start_ratio=0.5, top_start_ratio=0.5,
+                 direction='down', distance=None, distance_expr=None,
+                 speed_in_pixels_per_second=800, use_touch=False):
+    """Perform scroll gesture on the page.
+
+    You may specify distance or distance_expr, but not both. If
+    neither is specified, the default scroll distance is variable
+    depending on direction (see scroll.js for full implementation).
+
+    Args:
+      left_start_ratio: The horizontal starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      top_start_ratio: The vertical starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      direction: The direction of scroll, either 'left', 'right',
+          'up', or 'down'
+      distance: The distance to scroll (in pixel).
+      distance_expr: A JavaScript expression (as string) that can be
+          evaluated to compute scroll distance. Example:
+          'window.scrollTop' or '(function() { return crazyMath(); })()'.
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
+      use_touch: Whether scrolling should be done with touch input.
+    """
+    self._RunAction(ScrollAction(
+        left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
+        direction=direction, distance=distance, distance_expr=distance_expr,
+        speed_in_pixels_per_second=speed_in_pixels_per_second,
+        use_touch=use_touch))
+
+  def ScrollElement(self, selector=None, text=None, element_function=None,
+                    left_start_ratio=0.5, top_start_ratio=0.5,
+                    direction='down', distance=None, distance_expr=None,
+                    speed_in_pixels_per_second=800, use_touch=False):
+    """Perform scroll gesture on the element.
+
+    The element may be selected via selector, text, or element_function.
+    Only one of these arguments must be specified.
+
+    You may specify distance or distance_expr, but not both. If
+    neither is specified, the default scroll distance is variable
+    depending on direction (see scroll.js for full implementation).
+
+    Args:
+      selector: A CSS selector describing the element.
+      text: The element must contains this exact text.
+      element_function: A JavaScript function (as string) that is used
+          to retrieve the element. For example:
+          'function() { return foo.element; }'.
+      left_start_ratio: The horizontal starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          the element.
+      top_start_ratio: The vertical starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          the element.
+      direction: The direction of scroll, either 'left', 'right',
+          'up', or 'down'
+      distance: The distance to scroll (in pixel).
+      distance_expr: A JavaScript expression (as string) that can be
+          evaluated to compute scroll distance. Example:
+          'window.scrollTop' or '(function() { return crazyMath(); })()'.
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
+      use_touch: Whether scrolling should be done with touch input.
+    """
+    self._RunAction(ScrollAction(
+        selector=selector, text=text, element_function=element_function,
+        left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
+        direction=direction, distance=distance, distance_expr=distance_expr,
+        speed_in_pixels_per_second=speed_in_pixels_per_second,
+        use_touch=use_touch))
+
+  def ScrollBouncePage(self, left_start_ratio=0.5, top_start_ratio=0.5,
+                       direction='down', distance=100,
+                       overscroll=10, repeat_count=10,
+                       speed_in_pixels_per_second=400):
+    """Perform scroll bounce gesture on the page.
+
+    This gesture scrolls the page by the number of pixels specified in
+    distance, in the given direction, followed by a scroll by
+    (distance + overscroll) pixels in the opposite direction.
+    The above gesture is repeated repeat_count times.
+
+    Args:
+      left_start_ratio: The horizontal starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      top_start_ratio: The vertical starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      direction: The direction of scroll, either 'left', 'right',
+          'up', or 'down'
+      distance: The distance to scroll (in pixel).
+      overscroll: The number of additional pixels to scroll back, in
+          addition to the givendistance.
+      repeat_count: How often we want to repeat the full gesture.
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
+    """
+    self._RunAction(ScrollBounceAction(
+        left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
+        direction=direction, distance=distance,
+        overscroll=overscroll, repeat_count=repeat_count,
+        speed_in_pixels_per_second=speed_in_pixels_per_second))
+
+  def ScrollBounceElement(self, selector=None, text=None, element_function=None,
+                          left_start_ratio=0.5, top_start_ratio=0.5,
+                          direction='down', distance=100,
+                          overscroll=10, repeat_count=10,
+                          speed_in_pixels_per_second=400):
+    """Perform scroll bounce gesture on the element.
+
+    This gesture scrolls on the element by the number of pixels specified in
+    distance, in the given direction, followed by a scroll by
+    (distance + overscroll) pixels in the opposite direction.
+    The above gesture is repeated repeat_count times.
+
+    Args:
+      selector: A CSS selector describing the element.
+      text: The element must contains this exact text.
+      element_function: A JavaScript function (as string) that is used
+          to retrieve the element. For example:
+          'function() { return foo.element; }'.
+      left_start_ratio: The horizontal starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      top_start_ratio: The vertical starting coordinate of the
+          gesture, as a ratio of the visible bounding rectangle for
+          document.body.
+      direction: The direction of scroll, either 'left', 'right',
+          'up', or 'down'
+      distance: The distance to scroll (in pixel).
+      overscroll: The number of additional pixels to scroll back, in
+          addition to the givendistance.
+      repeat_count: How often we want to repeat the full gesture.
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
+    """
+    self._RunAction(ScrollBounceAction(
+        selector=selector, text=text, element_function=element_function,
+        left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
+        direction=direction, distance=distance,
+        overscroll=overscroll, repeat_count=repeat_count,
+        speed_in_pixels_per_second=speed_in_pixels_per_second))
+
   def SwipePage(self, left_start_ratio=0.5, top_start_ratio=0.5,
-                direction='left', distance=100, speed=800):
+                direction='left', distance=100, speed_in_pixels_per_second=800):
     """Perform swipe gesture on the page.
 
     Args:
@@ -205,17 +433,22 @@ class ActionRunner(object):
       direction: The direction of swipe, either 'left', 'right',
           'up', or 'down'
       distance: The distance to swipe (in pixel).
-      speed: The speed of the gesture.
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
     """
-    self.RunAction(SwipeAction(
+    self._RunAction(SwipeAction(
         left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
-        direction=direction, distance=distance, speed=speed))
+        direction=direction, distance=distance,
+        speed_in_pixels_per_second=speed_in_pixels_per_second))
 
   def SwipeElement(self, selector=None, text=None, element_function=None,
                    left_start_ratio=0.5, top_start_ratio=0.5,
-                   direction='left', distance=100, speed=800):
+                   direction='left', distance=100,
+                   speed_in_pixels_per_second=800):
     """Perform swipe gesture on the element.
 
+    The element may be selected via selector, text, or element_function.
+    Only one of these arguments must be specified.
+
     Args:
       selector: A CSS selector describing the element.
       text: The element must contains this exact text.
@@ -231,12 +464,83 @@ class ActionRunner(object):
       direction: The direction of swipe, either 'left', 'right',
           'up', or 'down'
       distance: The distance to swipe (in pixel).
-      speed: The speed of the gesture.
+      speed_in_pixels_per_second: The speed of the gesture (in pixels/s).
     """
-    self.RunAction(SwipeAction(
+    self._RunAction(SwipeAction(
         selector=selector, text=text, element_function=element_function,
         left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
-        direction=direction, distance=distance, speed=speed))
+        direction=direction, distance=distance,
+        speed_in_pixels_per_second=speed_in_pixels_per_second))
+
+  def PlayMedia(self, selector=None,
+                playing_event_timeout_in_seconds=0,
+                ended_event_timeout_in_seconds=0):
+    """Invokes the "play" action on media elements (such as video).
+
+    Args:
+      selector: A CSS selector describing the element. If none is
+          specified, play the first media element on the page. If the
+          selector matches more than 1 media element, all of them will
+          be played.
+      playing_event_timeout_in_seconds: Maximum waiting time for the "playing"
+          event (dispatched when the media begins to play) to be fired.
+          0 means do not wait.
+      ended_event_timeout_in_seconds: Maximum waiting time for the "ended"
+          event (dispatched when playback completes) to be fired.
+          0 means do not wait.
+
+    Raises:
+      TimeoutException: If the maximum waiting time is exceeded.
+    """
+    self._RunAction(PlayAction(
+        selector=selector,
+        playing_event_timeout_in_seconds=playing_event_timeout_in_seconds,
+        ended_event_timeout_in_seconds=ended_event_timeout_in_seconds))
+
+  def SeekMedia(self, seconds, selector=None, timeout_in_seconds=0,
+                log_time=True, label=''):
+    """Performs a seek action on media elements (such as video).
+
+    Args:
+      seconds: The media time to seek to.
+      selector: A CSS selector describing the element. If none is
+          specified, seek the first media element on the page. If the
+          selector matches more than 1 media element, all of them will
+          be seeked.
+      timeout_in_seconds: Maximum waiting time for the "seeked" event
+          (dispatched when the seeked operation completes) to be
+          fired.  0 means do not wait.
+      log_time: Whether to log the seek time for the perf
+          measurement. Useful when performing multiple seek.
+      label: A suffix string to name the seek perf measurement.
+
+    Raises:
+      TimeoutException: If the maximum waiting time is exceeded.
+    """
+    self._RunAction(SeekAction(
+        seconds=seconds, selector=selector,
+        timeout_in_seconds=timeout_in_seconds,
+        log_time=log_time, label=label))
+
+  def LoopMedia(self, loop_count, selector=None, timeout_in_seconds=None):
+    """Loops a media playback.
+
+    Args:
+      loop_count: The number of times to loop the playback.
+      selector: A CSS selector describing the element. If none is
+          specified, loop the first media element on the page. If the
+          selector matches more than 1 media element, all of them will
+          be looped.
+      timeout_in_seconds: Maximum waiting time for the looped playback to
+          complete. 0 means do not wait. None (the default) means to
+          wait loop_count * 60 seconds.
+
+    Raises:
+      TimeoutException: If the maximum waiting time is exceeded.
+    """
+    self._RunAction(LoopAction(
+        loop_count=loop_count, selector=selector,
+        timeout_in_seconds=timeout_in_seconds))
 
   def ForceGarbageCollection(self):
     """Forces JavaScript garbage collection on the page."""
@@ -251,6 +555,15 @@ class ActionRunner(object):
     """
     raw_input("Interacting... Press Enter to continue.")
 
+  def RepaintContinuously(self, seconds):
+    """Continuously repaints the visible content.
+
+    It does this by requesting animation frames until the given number
+    of seconds have elapsed AND at least three RAFs have been
+    fired. Times out after max(60, self.seconds), if less than three
+    RAFs were fired."""
+    self._RunAction(RepaintContinuouslyAction(
+        seconds=0 if self._skip_waits else seconds))
 
 class Interaction(object):
 
@@ -268,12 +581,12 @@ class Interaction(object):
     assert not self._started
     self._started = True
     self._action_runner.ExecuteJavaScript('console.time("%s");' %
-        tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
+        timeline_interaction_record.GetJavaScriptMarker(
             self._label, self._flags))
 
   def End(self):
     assert self._started
     self._started = False
     self._action_runner.ExecuteJavaScript('console.timeEnd("%s");' %
-        tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
+        timeline_interaction_record.GetJavaScriptMarker(
             self._label, self._flags))