• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import time
6
7from telemetry.page.actions.javascript_click import ClickElementAction
8from telemetry.page.actions.navigate import NavigateAction
9from telemetry.page.actions.swipe import SwipeAction
10from telemetry.page.actions.tap import TapAction
11from telemetry.page.actions.wait import WaitForElementAction
12from telemetry.web_perf import timeline_interaction_record as tir_module
13
14
15class ActionRunner(object):
16
17  def __init__(self, tab):
18    self._tab = tab
19
20  # TODO(nednguyen): remove this (or make private) when
21  # crbug.com/361809 is marked fixed
22  def RunAction(self, action):
23    action.WillRunAction(self._tab)
24    action.RunAction(self._tab)
25
26  def BeginInteraction(self, label, is_smooth=False, is_responsive=False):
27    """Marks the beginning of an interaction record.
28
29    An interaction record is a labeled time period containing
30    interaction that developers care about. Each set of metrics
31    specified in flags will be calculated for this time period.. The
32    End() method in the returned object must be called once to mark
33    the end of the timeline.
34
35    Args:
36      label: A label for this particular interaction. This can be any
37          user-defined string, but must not contain '/'.
38      is_smooth: Whether to check for smoothness metrics for this interaction.
39      is_responsive: Whether to check for responsiveness metrics for
40          this interaction.
41    """
42    flags = []
43    if is_smooth:
44      flags.append(tir_module.IS_SMOOTH)
45    if is_responsive:
46      flags.append(tir_module.IS_RESPONSIVE)
47
48    interaction = Interaction(self._tab, label, flags)
49    interaction.Begin()
50    return interaction
51
52  def BeginGestureInteraction(
53      self, label, is_smooth=False, is_responsive=False):
54    """Marks the beginning of a gesture-based interaction record.
55
56    This is similar to normal interaction record, but it will
57    auto-narrow the interaction time period to only include the
58    synthetic gesture event output by Chrome. This is typically use to
59    reduce noise in gesture-based analysis (e.g., analysis for a
60    swipe/scroll).
61
62    The interaction record label will be prepended with 'Gesture_'.
63
64    Args:
65      label: A label for this particular interaction. This can be any
66          user-defined string, but must not contain '/'.
67      is_smooth: Whether to check for smoothness metrics for this interaction.
68      is_responsive: Whether to check for responsiveness metrics for
69          this interaction.
70    """
71    return self.BeginInteraction('Gesture_' + label, is_smooth, is_responsive)
72
73  def NavigateToPage(self, page, timeout_seconds=None):
74    """ Navigate to the given page.
75
76    Args:
77      page: page is an instance of page.Page
78    """
79    if page.is_file:
80      target_side_url = self._tab.browser.http_server.UrlOf(page.file_path_url)
81    else:
82      target_side_url = page.url
83    attributes = {
84        'url': target_side_url,
85        'script_to_evaluate_on_commit': page.script_to_evaluate_on_commit}
86    if timeout_seconds:
87      attributes['timeout_seconds'] = timeout_seconds
88    self.RunAction(NavigateAction(attributes))
89
90  def WaitForNavigate(self, timeout_seconds=60):
91    self._tab.WaitForNavigate(timeout_seconds)
92    self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
93
94  def ExecuteJavaScript(self, statement):
95    """Executes a given JavaScript expression. Does not return the result.
96
97    Example: runner.ExecuteJavaScript('var foo = 1;');
98
99    Args:
100      statement: The statement to execute (provided as string).
101
102    Raises:
103      EvaluationException: The statement failed to execute.
104    """
105    self._tab.ExecuteJavaScript(statement)
106
107  def EvaluateJavaScript(self, expression):
108    """Returns the evaluation result of the given JavaScript expression.
109
110    The evaluation results must be convertible to JSON. If the result
111    is not needed, use ExecuteJavaScript instead.
112
113    Example: num = runner.EvaluateJavaScript('document.location.href')
114
115    Args:
116      expression: The expression to evaluate (provided as string).
117
118    Raises:
119      EvaluationException: The statement expression failed to execute
120          or the evaluation result can not be JSON-ized.
121    """
122    return self._tab.EvaluateJavaScript(expression)
123
124  def Wait(self, seconds):
125    """Wait for the number of seconds specified.
126
127    Args:
128      seconds: The number of seconds to wait.
129    """
130    time.sleep(seconds)
131
132  def WaitForJavaScriptCondition(self, condition, timeout=60):
133    """Wait for a JavaScript condition to become true.
134
135    Example: runner.WaitForJavaScriptCondition('window.foo == 10');
136
137    Args:
138      condition: The JavaScript condition (as string).
139      timeout: The timeout in seconds (default to 60).
140    """
141    self._tab.WaitForJavaScriptExpression(condition, timeout)
142
143  def WaitForElement(self, selector=None, text=None, element_function=None,
144                     timeout=60):
145    """Wait for an element to appear in the document.
146
147    The element may be selected via selector, text, or element_function.
148    Only one of these arguments must be specified.
149
150    Args:
151      selector: A CSS selector describing the element.
152      text: The element must contains this exact text.
153      element_function: A JavaScript function (as string) that is used
154          to retrieve the element. For example:
155          '(function() { return foo.element; })()'.
156      timeout: The timeout in seconds (default to 60).
157    """
158    self.RunAction(WaitForElementAction(
159        selector=selector, text=text, element_function=element_function,
160        timeout=timeout))
161
162  def TapElement(self, selector=None, text=None, element_function=None):
163    """Tap an element.
164
165    The element may be selected via selector, text, or element_function.
166    Only one of these arguments must be specified.
167
168    Args:
169      selector: A CSS selector describing the element.
170      text: The element must contains this exact text.
171      element_function: A JavaScript function (as string) that is used
172          to retrieve the element. For example:
173          '(function() { return foo.element; })()'.
174    """
175    self.RunAction(TapAction(
176        selector=selector, text=text, element_function=element_function))
177
178  def ClickElement(self, selector=None, text=None, element_function=None):
179    """Click an element.
180
181    The element may be selected via selector, text, or element_function.
182    Only one of these arguments must be specified.
183
184    Args:
185      selector: A CSS selector describing the element.
186      text: The element must contains this exact text.
187      element_function: A JavaScript function (as string) that is used
188          to retrieve the element. For example:
189          '(function() { return foo.element; })()'.
190    """
191    self.RunAction(ClickElementAction(
192        selector=selector, text=text, element_function=element_function))
193
194  def SwipePage(self, left_start_ratio=0.5, top_start_ratio=0.5,
195                direction='left', distance=100, speed=800):
196    """Perform swipe gesture on the page.
197
198    Args:
199      left_start_ratio: The horizontal starting coordinate of the
200          gesture, as a ratio of the visible bounding rectangle for
201          document.body.
202      top_start_ratio: The vertical starting coordinate of the
203          gesture, as a ratio of the visible bounding rectangle for
204          document.body.
205      direction: The direction of swipe, either 'left', 'right',
206          'up', or 'down'
207      distance: The distance to swipe (in pixel).
208      speed: The speed of the gesture.
209    """
210    self.RunAction(SwipeAction(
211        left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
212        direction=direction, distance=distance, speed=speed))
213
214  def SwipeElement(self, selector=None, text=None, element_function=None,
215                   left_start_ratio=0.5, top_start_ratio=0.5,
216                   direction='left', distance=100, speed=800):
217    """Perform swipe gesture on the element.
218
219    Args:
220      selector: A CSS selector describing the element.
221      text: The element must contains this exact text.
222      element_function: A JavaScript function (as string) that is used
223          to retrieve the element. For example:
224          'function() { return foo.element; }'.
225      left_start_ratio: The horizontal starting coordinate of the
226          gesture, as a ratio of the visible bounding rectangle for
227          the element.
228      top_start_ratio: The vertical starting coordinate of the
229          gesture, as a ratio of the visible bounding rectangle for
230          the element.
231      direction: The direction of swipe, either 'left', 'right',
232          'up', or 'down'
233      distance: The distance to swipe (in pixel).
234      speed: The speed of the gesture.
235    """
236    self.RunAction(SwipeAction(
237        selector=selector, text=text, element_function=element_function,
238        left_start_ratio=left_start_ratio, top_start_ratio=top_start_ratio,
239        direction=direction, distance=distance, speed=speed))
240
241  def ForceGarbageCollection(self):
242    """Forces JavaScript garbage collection on the page."""
243    self._tab.CollectGarbage()
244
245  def PauseInteractive(self):
246    """Pause the page execution and wait for terminal interaction.
247
248    This is typically used for debugging. You can use this to pause
249    the page execution and inspect the browser state before
250    continuing.
251    """
252    raw_input("Interacting... Press Enter to continue.")
253
254
255class Interaction(object):
256
257  def __init__(self, action_runner, label, flags):
258    assert action_runner
259    assert label
260    assert isinstance(flags, list)
261
262    self._action_runner = action_runner
263    self._label = label
264    self._flags = flags
265    self._started = False
266
267  def Begin(self):
268    assert not self._started
269    self._started = True
270    self._action_runner.ExecuteJavaScript('console.time("%s");' %
271        tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
272            self._label, self._flags))
273
274  def End(self):
275    assert self._started
276    self._started = False
277    self._action_runner.ExecuteJavaScript('console.timeEnd("%s");' %
278        tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
279            self._label, self._flags))
280