1# Copyright 2012 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
5from py_trace_event import trace_event
6
7from telemetry import decorators
8from telemetry.util import js_template
9
10
11GESTURE_SOURCE_DEFAULT = 'DEFAULT'
12GESTURE_SOURCE_MOUSE = 'MOUSE'
13GESTURE_SOURCE_TOUCH = 'TOUCH'
14SUPPORTED_GESTURE_SOURCES = (GESTURE_SOURCE_DEFAULT,
15                             GESTURE_SOURCE_MOUSE,
16                             GESTURE_SOURCE_TOUCH)
17
18class PageActionNotSupported(Exception):
19  pass
20
21class PageActionFailed(Exception):
22  pass
23
24
25class PageAction(object):
26  """Represents an action that a user might try to perform to a page."""
27
28  __metaclass__ = trace_event.TracedMetaClass
29
30  def WillRunAction(self, tab):
31    """Override to do action-specific setup before
32    Test.WillRunAction is called."""
33    pass
34
35  def RunAction(self, tab):
36    raise NotImplementedError()
37
38  def CleanUp(self, tab):
39    pass
40
41def EvaluateCallbackWithElement(
42    tab, callback_js, selector=None, text=None, element_function=None,
43    wait=False, timeout_in_seconds=60):
44  """Evaluates the JavaScript callback with the given element.
45
46  The element may be selected via selector, text, or element_function.
47  Only one of these arguments must be specified.
48
49  Returns:
50    The callback's return value, if any. The return value must be
51    convertible to JSON.
52
53  Args:
54    tab: A telemetry.core.Tab object.
55    callback_js: The JavaScript callback to call (as string).
56        The callback receive 2 parameters: the element, and information
57        string about what method was used to retrieve the element.
58        Example: '''
59          function(element, info) {
60            if (!element) {
61              throw Error('Can not find element: ' + info);
62            }
63            element.click()
64          }'''
65    selector: A CSS selector describing the element.
66    text: The element must contains this exact text.
67    element_function: A JavaScript function (as string) that is used
68        to retrieve the element. For example:
69        '(function() { return foo.element; })()'.
70    wait: Whether to wait for the return value to be true.
71    timeout_in_seconds: The timeout for wait (if waiting).
72  """
73  count = 0
74  info_msg = ''
75  if element_function is not None:
76    count = count + 1
77    info_msg = js_template.Render(
78        'using element_function: {{ @code }}', code=element_function)
79  if selector is not None:
80    count = count + 1
81    info_msg = js_template.Render(
82        'using selector {{ selector }}', selector=selector)
83    element_function = js_template.Render(
84        'document.querySelector({{ selector }})', selector=selector)
85  if text is not None:
86    count = count + 1
87    info_msg = js_template.Render(
88        'using exact text match {{ text }}', text=text)
89    element_function = js_template.Render('''
90        (function() {
91          function _findElement(element, text) {
92            if (element.innerHTML == text) {
93              return element;
94            }
95
96            var childNodes = element.childNodes;
97            for (var i = 0, len = childNodes.length; i < len; ++i) {
98              var found = _findElement(childNodes[i], text);
99              if (found) {
100                return found;
101              }
102            }
103            return null;
104          }
105          return _findElement(document, {{ text }});
106        })()''',
107        text=text)
108
109  if count != 1:
110    raise PageActionFailed(
111        'Must specify 1 way to retrieve element, but %s was specified.' % count)
112
113  code = js_template.Render('''
114      (function() {
115        var element = {{ @element_function }};
116        var callback = {{ @callback_js }};
117        return callback(element, {{ info_msg }});
118      })()''',
119      element_function=element_function,
120      callback_js=callback_js,
121      info_msg=info_msg)
122
123  if wait:
124    tab.WaitForJavaScriptCondition(code, timeout=timeout_in_seconds)
125    return True
126  else:
127    return tab.EvaluateJavaScript(code)
128
129
130@decorators.Cache
131def IsGestureSourceTypeSupported(tab, gesture_source_type):
132  # TODO(dominikg): remove once support for
133  #                 'chrome.gpuBenchmarking.gestureSourceTypeSupported' has
134  #                 been rolled into reference build.
135  if tab.EvaluateJavaScript("""
136      typeof chrome.gpuBenchmarking.gestureSourceTypeSupported ===
137          'undefined'"""):
138    return (tab.browser.platform.GetOSName() != 'mac' or
139            gesture_source_type.lower() != 'touch')
140
141  return tab.EvaluateJavaScript("""
142      chrome.gpuBenchmarking.gestureSourceTypeSupported(
143          chrome.gpuBenchmarking.{{ @gesture_source_type }}_INPUT)""",
144      gesture_source_type=gesture_source_type.upper())
145