146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)# Copyright 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import re
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom telemetry import decorators
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class PageActionNotSupported(Exception):
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pass
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class PageActionFailed(Exception):
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pass
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class PageAction(object):
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Represents an action that a user might try to perform to a page."""
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def WillRunAction(self, tab):
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Override to do action-specific setup before
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Test.WillRunAction is called."""
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pass
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def RunAction(self, tab):
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    raise NotImplementedError()
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def CleanUp(self, tab):
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pass
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def EvaluateCallbackWithElement(
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    tab, callback_js, selector=None, text=None, element_function=None,
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    wait=False, timeout_in_seconds=60):
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  """Evaluates the JavaScript callback with the given element.
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  The element may be selected via selector, text, or element_function.
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Only one of these arguments must be specified.
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Returns:
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    The callback's return value, if any. The return value must be
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    convertible to JSON.
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Args:
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    tab: A telemetry.core.Tab object.
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    callback_js: The JavaScript callback to call (as string).
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        The callback receive 2 parameters: the element, and information
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        string about what method was used to retrieve the element.
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        Example: '''
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          function(element, info) {
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            if (!element) {
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              throw Error('Can not find element: ' + info);
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            }
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            element.click()
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          }'''
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    selector: A CSS selector describing the element.
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    text: The element must contains this exact text.
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    element_function: A JavaScript function (as string) that is used
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        to retrieve the element. For example:
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        '(function() { return foo.element; })()'.
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    wait: Whether to wait for the return value to be true.
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    timeout_in_seconds: The timeout for wait (if waiting).
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  """
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  count = 0
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  info_msg = ''
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if element_function is not None:
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    count = count + 1
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    info_msg = 'using element_function "%s"' % re.escape(element_function)
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if selector is not None:
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    count = count + 1
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    info_msg = 'using selector "%s"' % _EscapeSelector(selector)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    element_function = 'document.querySelector(\'%s\')' % _EscapeSelector(
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        selector)
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if text is not None:
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    count = count + 1
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    info_msg = 'using exact text match "%s"' % re.escape(text)
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    element_function = '''
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        (function() {
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          function _findElement(element, text) {
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            if (element.innerHTML == text) {
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              return element;
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            }
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            var childNodes = element.childNodes;
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            for (var i = 0, len = childNodes.length; i < len; ++i) {
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              var found = _findElement(childNodes[i], text);
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              if (found) {
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                return found;
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              }
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            }
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            return null;
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          }
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          return _findElement(document, '%s');
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        })()''' % text
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if count != 1:
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    raise PageActionFailed(
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        'Must specify 1 way to retrieve element, but %s was specified.' % count)
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  code = '''
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      (function() {
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        var element = %s;
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        var callback = %s;
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return callback(element, '%s');
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      })()''' % (element_function, callback_js, info_msg)
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if wait:
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    tab.WaitForJavaScriptExpression(code, timeout_in_seconds)
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return True
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  else:
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return tab.EvaluateJavaScript(code)
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def _EscapeSelector(selector):
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return selector.replace('\'', '\\\'')
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdef GetGestureSourceTypeFromOptions(tab):
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  gesture_source_type = tab.browser.synthetic_gesture_source_type
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return 'chrome.gpuBenchmarking.' + gesture_source_type.upper() + '_INPUT'
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch@decorators.Cache
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdef IsGestureSourceTypeSupported(tab, gesture_source_type):
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  # TODO(dominikg): remove once support for
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  #                 'chrome.gpuBenchmarking.gestureSourceTypeSupported' has
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  #                 been rolled into reference build.
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if tab.EvaluateJavaScript("""
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      typeof chrome.gpuBenchmarking.gestureSourceTypeSupported ===
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          'undefined'"""):
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return (tab.browser.platform.GetOSName() != 'mac' or
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            gesture_source_type.lower() != 'touch')
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return tab.EvaluateJavaScript("""
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      chrome.gpuBenchmarking.gestureSourceTypeSupported(
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          chrome.gpuBenchmarking.%s_INPUT)"""
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      % (gesture_source_type.upper()))
134