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