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