def RunAction(self, tab): if not self.HasElementSelector(): self._element_function = 'document.body' gesture_source_type = 'chrome.gpuBenchmarking.TOUCH_INPUT' if (page_action.IsGestureSourceTypeSupported(tab, 'mouse') and not self._use_touch): gesture_source_type = 'chrome.gpuBenchmarking.MOUSE_INPUT' code = js_template.Render( """ function(element, info) { if (!element) { throw Error('Cannot find element: ' + info); } window.__dragAction.start({ element: element, left_start_ratio: {{ left_start_ratio }}, top_start_ratio: {{ top_start_ratio }}, left_end_ratio: {{ left_end_ratio }}, top_end_ratio: {{ top_end_ratio }}, speed: {{ speed }}, gesture_source_type: {{ @gesture_source_type }} }); }""", left_start_ratio=self._left_start_ratio, top_start_ratio=self._top_start_ratio, left_end_ratio=self._left_end_ratio, top_end_ratio=self._top_end_ratio, speed=self._speed, gesture_source_type=gesture_source_type) self.EvaluateCallback(tab, code) tab.WaitForJavaScriptCondition('window.__dragActionDone', timeout=60)
def RunAction(self, tab): code = js_template.Render( """ function(element, info) { if (!element) { throw Error('Cannot find element: ' + info); } window.__scrollBounceAction.start({ element: element, left_start_ratio: {{ left_start_ratio }}, top_start_ratio: {{ top_start_ratio }}, direction: {{ direction }}, distance: {{ distance }}, overscroll: {{ overscroll }}, repeat_count: {{ repeat_count }}, speed: {{ speed }} }); }""", left_start_ratio=self._left_start_ratio, top_start_ratio=self._top_start_ratio, direction=self._direction, distance=self._distance, overscroll=self._overscroll, repeat_count=self._repeat_count, speed=self._speed) page_action.EvaluateCallbackWithElement( tab, code, selector=self._selector, text=self._text, element_function=self._element_function) tab.WaitForJavaScriptCondition( 'window.__scrollBounceActionDone', timeout=60)
def __init__(self, selector=None, text=None, element_function=None, left_start_ratio=0.5, top_start_ratio=0.5, direction='down', distance=None, distance_expr=None, speed_in_pixels_per_second=800, use_touch=False, synthetic_gesture_source=page_action.GESTURE_SOURCE_DEFAULT): super(ScrollAction, self).__init__() if direction not in ('down', 'up', 'left', 'right', 'downleft', 'downright', 'upleft', 'upright'): raise page_action.PageActionNotSupported( 'Invalid scroll direction: %s' % self.direction) self._selector = selector self._text = text self._element_function = element_function self._left_start_ratio = left_start_ratio self._top_start_ratio = top_start_ratio self._direction = direction self._speed = speed_in_pixels_per_second self._use_touch = use_touch self._synthetic_gesture_source = ('chrome.gpuBenchmarking.%s_INPUT' % synthetic_gesture_source) self._distance_func = js_template.RenderValue(None) if distance: assert not distance_expr distance_expr = str(distance) if distance_expr: self._distance_func = js_template.Render( 'function() { return 0 + {{ @expr }}; }', expr=distance_expr)
def RunAction(self, tab): if (self._selector is None and self._text is None and self._element_function is None): self._element_function = '(document.scrollingElement || document.body)' code = js_template.Render(""" function(element, info) { if (!element) { throw Error('Cannot find element: ' + info); } window.__swipeAction.start({ element: element, left_start_ratio: {{ left_start_ratio }}, top_start_ratio: {{ top_start_ratio }}, direction: {{ direction }}, distance: {{ distance }}, speed: {{ speed }} }); }""", left_start_ratio=self._left_start_ratio, top_start_ratio=self._top_start_ratio, direction=self._direction, distance=self._distance, speed=self._speed) page_action.EvaluateCallbackWithElement( tab, code, selector=self._selector, text=self._text, element_function=self._element_function) tab.WaitForJavaScriptCondition('window.__swipeActionDone', timeout=60)
def WillRunAction(self, tab): if self._selector: element = js_template.Render( 'document.querySelector({{ selector }})', selector=self._selector) else: element = self._element_function self._distance = tab.EvaluateJavaScript(''' (function(elem){ var rect = elem.getBoundingClientRect(); if (rect.bottom < 0) { // The bottom of the element is above the viewport. // Scroll up until the top of the element is on screen. return rect.top - (window.innerHeight / 2); } if (rect.top - window.innerHeight >= 0) { // rect.top provides the pixel offset of the element from the // top of the page. Because that exceeds the viewport's height, // we know that the element is below the viewport. return rect.top - (window.innerHeight / 2); } return 0; })({{ @element }}); ''', element=element) self._direction = 'down' if self._distance > 0 else 'up' self._distance = abs(self._distance) self._scroller = ScrollAction( direction=self._direction, selector=self._container_selector, element_function=self._container_element_function, distance=self._distance, speed_in_pixels_per_second=self._speed)
def RunAction(self, tab): if not self.HasElementSelector(): self._element_function = '(document.scrollingElement || document.body)' gesture_source_type = self._synthetic_gesture_source if self._use_touch: gesture_source_type = 'chrome.gpuBenchmarking.TOUCH_INPUT' code = js_template.Render(""" function(element, info) { if (!element) { throw Error('Cannot find element: ' + info); } window.__scrollAction.start({ element: element, left_start_ratio: {{ left_start_ratio }}, top_start_ratio: {{ top_start_ratio }}, direction: {{ direction }}, speed: {{ speed }}, gesture_source_type: {{ @gesture_source_type }} }); }""", left_start_ratio=self._left_start_ratio, top_start_ratio=self._top_start_ratio, direction=self._direction, speed=self._speed, gesture_source_type=gesture_source_type) self.EvaluateCallback(tab, code) tab.WaitForJavaScriptCondition('window.__scrollActionDone', timeout=self.timeout)
def RunAction(self, tab): scale_factor = (self._scale_factor if self._scale_factor else PinchAction._GetDefaultScaleFactorForPage(tab)) code = js_template.Render(''' function(element, info) { if (!element) { throw Error('Cannot find element: ' + info); } window.__pinchAction.start({ element: element, left_anchor_ratio: {{ left_anchor_ratio }}, top_anchor_ratio: {{ top_anchor_ratio }}, scale_factor: {{ scale_factor }}, speed: {{ speed }} }); }''', left_anchor_ratio=self._left_anchor_ratio, top_anchor_ratio=self._top_anchor_ratio, scale_factor=scale_factor, speed=self._speed) page_action.EvaluateCallbackWithElement( tab, code, selector=self._selector, text=self._text, element_function=self._element_function) tab.WaitForJavaScriptExpression('window.__pinchActionDone', 60)
def EvaluateJavaScript(self, expression, **kwargs): """Returns the result of evaluating a given JavaScript expression. Example: runner.ExecuteJavaScript('document.location.href'); Args: expression: The expression to execute (provided as a string). Optional keyword args: timeout: The number of seconds to wait for the expression to evaluate. context_id: The id of an iframe where to execute the code; the main page has context_id=1, the first iframe context_id=2, etc. user_gesture: Whether execution should be treated as initiated by user in the UI. Code that plays media or requests fullscreen may not take effects without user_gesture set to True. Additional keyword arguments provide values to be interpolated within the expression. See telemetry.util.js_template for details. Raises: py_utils.TimeoutException exceptions.EvaluationException exceptions.WebSocketException exceptions.DevtoolsTargetCrashException """ # Use the default both when timeout=None or the option is ommited. timeout = kwargs.pop('timeout', None) or 60 context_id = kwargs.pop('context_id', None) user_gesture = kwargs.pop('user_gesture', None) or False expression = js_template.Render(expression, **kwargs) return self._EvaluateJavaScript(expression, context_id, timeout, user_gesture=user_gesture)
def _DidLoadDocument(self, action_runner): action_runner.Wait(2) action_runner.ScrollPage() action_runner.Wait(2) action_runner.ScrollPage(direction='up') # Refine search query in the search box. # TODO(nednguyen): replace this with input text gesture to make it more # realistic. action_runner.ExecuteJavaScript( js_template.Render( 'document.querySelector({{ selector }}).value += "वितरण";', selector=self._SEARCH_BOX_SELECTOR)) action_runner.Wait(2) action_runner.ClickElement(selector=self._SEARCH_BUTTON_SELECTOR) # Scroll down & click next search result page. action_runner.Wait(2) action_runner.ScrollPageToElement( selector=self._SEARCH_PAGE_2_SELECTOR) action_runner.Wait(2) action_runner.ClickElement(selector=self._SEARCH_PAGE_2_SELECTOR) action_runner.Wait(2) action_runner.ScrollPage()
def EvaluateJavaScript(self, expression, **kwargs): """Returns the result of evaluating a given JavaScript expression. Example: runner.ExecuteJavaScript('document.location.href'); Args: expression: The expression to execute (provided as a string). Optional keyword args: timeout: The number of seconds to wait for the expression to evaluate. context_id: The id of an iframe where to execute the code; the main page has context_id=1, the first iframe context_id=2, etc. Additional keyword arguments provide values to be interpolated within the expression. See telemetry.util.js_template for details. Raises: py_utils.TimeoutException exceptions.EvaluationException exceptions.WebSocketException exceptions.DevtoolsTargetCrashException """ # Use the default both when timeout=None or the option is ommited. timeout = kwargs.pop('timeout', None) or 60 context_id = kwargs.pop('context_id', None) expression = js_template.Render(expression, **kwargs) return self._EvaluateJavaScript(expression, context_id, timeout)
def ExecuteJavaScript(self, statement, **kwargs): """Executes a given JavaScript statement. Does not return the result. Example: runner.ExecuteJavaScript('var foo = {{ value }};', value='hi'); Args: statement: The statement to execute (provided as a string). Optional keyword args: timeout: The number of seconds to wait for the statement to execute. context_id: The id of an iframe where to execute the code; the main page has context_id=1, the first iframe context_id=2, etc. Additional keyword arguments provide values to be interpolated within the statement. See telemetry.util.js_template for details. Raises: py_utils.TimeoutException exceptions.EvaluationException exceptions.WebSocketException exceptions.DevtoolsTargetCrashException """ # Use the default both when timeout=None or the option is ommited. timeout = kwargs.pop('timeout', None) or 60 context_id = kwargs.pop('context_id', None) statement = js_template.Render(statement, **kwargs) self._runtime.Execute(statement, context_id, timeout)
def testRenderWithSpecialCharts(self): self.assertEquals( js_template.Render( 'function(elem) { return elem.find({{ selector }}); }', selector='.r > a[href*="wikipedia"]'), r'function(elem) { return elem.find(".r > a[href*=\"wikipedia\"]"); }' )
def RunAction(self, tab): if (self._selector is None and self._text is None and self._element_function is None): self._element_function = '(document.scrollingElement || document.body)' gesture_source_type = self._synthetic_gesture_source if self._use_touch: gesture_source_type = 'chrome.gpuBenchmarking.TOUCH_INPUT' code = js_template.Render(''' function(element, info) { if (!element) { throw Error('Cannot find element: ' + info); } window.__scrollAction.start({ element: element, left_start_ratio: {{ left_start_ratio }}, top_start_ratio: {{ top_start_ratio }}, direction: {{ direction }}, speed: {{ speed }}, gesture_source_type: {{ @gesture_source_type }} }); }''', left_start_ratio=self._left_start_ratio, top_start_ratio=self._top_start_ratio, direction=self._direction, speed=self._speed, gesture_source_type=gesture_source_type) page_action.EvaluateCallbackWithElement( tab, code, selector=self._selector, text=self._text, element_function=self._element_function) tab.WaitForJavaScriptExpression('window.__scrollActionDone', 60)
def RunAction(self, tab): if not self.HasElementSelector(): self._element_function = 'document.body' code = js_template.Render( """ function(element, errorMsg) { if (!element) { throw Error('Cannot find element: ' + errorMsg); } window.__tapAction.start({ element: element, left_position_percentage: {{ left_position_percentage }}, top_position_percentage: {{ top_position_percentage }}, duration_ms: {{ duration_ms }}, gesture_source_type: {{ @gesture_source_type }} }); }""", left_position_percentage=self._left_position_percentage, top_position_percentage=self._top_position_percentage, duration_ms=self._duration_ms, gesture_source_type=self._synthetic_gesture_source) self.EvaluateCallback(tab, code) # The second disjunct handles the case where the tap action leads to an # immediate navigation (in which case the expression below might already be # evaluated on the new page). tab.WaitForJavaScriptCondition( 'window.__tapActionDone || window.__tapAction === undefined', timeout=60)
def eventFired(self, selector, event): # TODO(catapult:#3028): Render in JavaScript method when supported by API. code = js_template.Render( 'window.__hasEventCompleted({{ selector }}, {{ event }});', selector=selector, event=event) return self._tab.EvaluateJavaScript(code)
def DoActionOnWidgetType(self, action_runner, widget_type, action_function): # Find all widgets of this type, but skip any that are disabled or are # currently active as they typically don't produce animation frames. element_list_query = js_template.Render( '{{ @iframe }}.querySelectorAll({{ selector }})', iframe=self.iframe_js, selector='body %s:not([disabled]):not([active])' % widget_type) roles_count_query = element_list_query + '.length' for i in range(action_runner.EvaluateJavaScript(roles_count_query)): element_query = js_template.Render( '{{ @query }}[{{ i }}]', query=element_list_query, i=i) if action_runner.EvaluateJavaScript( element_query + '.offsetParent != null'): # Only try to tap on visible elements (offsetParent != null) action_runner.ExecuteJavaScript(element_query + '.scrollIntoView()') action_runner.Wait(1) # wait for page to settle after scrolling action_function(action_runner, element_query)
def __init__(self, url, page_set, name): super(TodoMVCPage, self).__init__( url=url, page_set=page_set, name=name, shared_page_state_class=shared_page_state.SharedDesktopPageState) # TODO(jochen): This interaction does not include the # WindowProxy::initialize portion before the commit. To fix this, we'll # have to migrate to TBMv2. self.script_to_evaluate_on_commit = js_template.Render( 'console.time({{ label }});', label=INTERACTION_NAME)
def _DidLoadDocument(self, action_runner): # Click on the amp news link and then just wait for it to load. element_function = js_template.Render( 'document.querySelectorAll({{ selector }})[{{ index }}]', selector=self.ITEM_SELECTOR, index=0) action_runner.WaitForElement(element_function=element_function) action_runner.ClickElement(element_function=element_function) action_runner.Wait(2)
def __init__(self, story_set, take_memory_measurement): super(_FacebookDesktopStory, self).__init__(story_set, take_memory_measurement) self.script_to_evaluate_on_commit += "\n" self.script_to_evaluate_on_commit += js_template.Render( '''{{@events_reported_by_page}} {{@performance_measure}}''', events_reported_by_page=self.EVENTS_REPORTED_BY_PAGE, performance_measure=self.PERFORMANCE_MEASURE_PATCH)
def __init__(self, page_set): super(AdwordCampaignDesktopPage, self).__init__( url='https://adwords.google.com/cm/CampaignMgmt', page_set=page_set, name='AdwordsCampaign', credentials_path='data/credentials.json', shared_page_state_class=shared_page_state.SharedDesktopPageState) self.script_to_evaluate_on_commit = js_template.Render( 'console.time({{ label }});', label=INTERACTION_NAME)
def WaitForJavaScriptCondition(self, condition, **kwargs): """Wait for a JavaScript condition to become truthy. Example: runner.WaitForJavaScriptCondition('window.foo == 10'); Args: condition: The JavaScript condition (provided as string). Optional keyword args: timeout: The number in seconds to wait for the condition to become True (default to 60). context_id: The id of an iframe where to execute the code; the main page has context_id=1, the first iframe context_id=2, etc. Additional keyword arguments provide values to be interpolated within the expression. See telemetry.util.js_template for details. Returns: The value returned by the JavaScript condition that got interpreted as true. Raises: py_utils.TimeoutException exceptions.EvaluationException exceptions.WebSocketException exceptions.DevtoolsTargetCrashException """ # Use the default both when timeout=None or the option is ommited. timeout = kwargs.pop('timeout', None) or 60 context_id = kwargs.pop('context_id', None) condition = js_template.Render(condition, **kwargs) def IsJavaScriptExpressionTrue(): try: return self._EvaluateJavaScript(condition, context_id, timeout) except exceptions.EvaluationException: # Eval may throw due to e.g. navigation. return False try: return py_utils.WaitFor(IsJavaScriptExpressionTrue, timeout) except py_utils.TimeoutException as e: # Try to make timeouts a little more actionable by dumping console output. debug_message = None try: debug_message = ( 'Console output:\n%s' % self.GetCurrentConsoleOutputBuffer()) except Exception as e: # pylint: disable=broad-except debug_message = ( 'Exception thrown when trying to capture console output: %s' % repr(e)) # Rethrow with the original stack trace for better debugging. raise py_utils.TimeoutException, \ py_utils.TimeoutException( 'Timeout after %ss while waiting for JavaScript:' % timeout + condition + '\n' + e.message + '\n' + debug_message), \ sys.exc_info()[2]
def _NavigateToItem(self, action_runner, index): item_selector = js_template.Render( 'document.querySelectorAll({{ selector }})[{{ index }}]', selector=self.ITEM_SELECTOR, index=index) # Only scrolls if element is not currently in viewport. action_runner.WaitForElement(element_function=item_selector) action_runner.ScrollPageToElement( element_function=item_selector, container_selector=self.CONTAINER_SELECTOR) self._ClickLink(action_runner, item_selector)
def RunPageInteractions(self, action_runner): sink_name = self._GetOSEnviron('RECEIVER_NAME') # Wait for 5s after Chrome is opened in order to get consistent results. action_runner.Wait(5) with action_runner.CreateInteraction('flinging'): self._WaitForResult( action_runner, lambda: action_runner.EvaluateJavaScript('initialized'), 'Failed to initialize', timeout=30) self.CloseExistingRoute(action_runner, sink_name) # Start session action_runner.TapElement(selector='#start_session_button') self._WaitForResult( action_runner, lambda: len(action_runner.tab.browser.tabs) >= 2, 'MR dialog never showed up.') for tab in action_runner.tab.browser.tabs: # Choose sink if tab.url == 'chrome://media-router/': self.WaitUntilDialogLoaded(action_runner, tab) self.ChooseSink(tab, sink_name) self._WaitForResult( action_runner, lambda: action_runner.EvaluateJavaScript('currentSession'), 'Failed to start session', timeout=10) # Load Media self.ExecuteAsyncJavaScript( action_runner, js_template.Render('loadMedia({{ url }});', url=self._GetOSEnviron('VIDEO_URL')), lambda: action_runner.EvaluateJavaScript('currentMedia'), 'Failed to load media', timeout=120) action_runner.Wait(5) action_runner.ExecuteJavaScript('collectPerfData();') action_runner.Wait(SESSION_TIME) # Stop session self.ExecuteAsyncJavaScript( action_runner, 'stopSession();', lambda: not action_runner.EvaluateJavaScript('currentSession'), 'Failed to stop session', timeout=60, retry=3)
def RunPageInteractions(self, action_runner): sink_name = self._GetOSEnviron('RECEIVER_NAME') # Enable Cast and start to discover all sinks. action_runner.tab.EnableCast() # Wait for 5s after Chrome is opened in order to get consistent results. action_runner.Wait(5) with action_runner.CreateInteraction('flinging'): action_runner.tab.StopCasting(sink_name) self._WaitForResult( action_runner, lambda: action_runner.EvaluateJavaScript('initialized'), 'Failed to initialize', timeout=30) # Wait for the sinks to appear. self.WaitForSink( action_runner, sink_name, 'Targeted receiver "%s" did not showed up. Sink List: %s' % (sink_name, str(action_runner.tab.GetCastSinks()))) action_runner.tab.SetCastSinkToUse(sink_name) # Start session action_runner.TapElement(selector='#start_session_button') action_runner.Wait(WAIT_TIME_SEC) self._WaitForResult( action_runner, lambda: action_runner.EvaluateJavaScript('currentSession'), 'Failed to start session', timeout=WAIT_TIME_SEC) # Load Media self.ExecuteAsyncJavaScript( action_runner, js_template.Render('loadMedia({{ url }});', url=self._GetOSEnviron('VIDEO_URL')), lambda: action_runner.EvaluateJavaScript('currentMedia'), 'Failed to load media', timeout=120) action_runner.Wait(5) action_runner.ExecuteJavaScript('collectPerfData();') action_runner.Wait(SESSION_WAIT_TIME) # Stop session self.ExecuteAsyncJavaScript( action_runner, 'stopSession();', lambda: not action_runner.EvaluateJavaScript('currentSession'), 'Failed to stop session', timeout=60, retry=3)
def HasEventCompletedOrError(self, tab, selector, event_name): # TODO(catapult:#3028): Render in JavaScript method when supported by API. code = js_template.Render( 'window.__hasEventCompleted({{ selector }}, {{ event_name }});', selector=selector, event_name=event_name) if tab.EvaluateJavaScript(code): return True error = tab.EvaluateJavaScript('window.__error') if error: logging.error('Detected media error while waiting for %s: %s', event_name, error) return True return False
def _DidLoadDocument(self, action_runner): # Waiting manually for the search results to load here and below. # Telemetry's action_runner.WaitForNavigate has some difficulty with amp # pages as it waits for a frameId without a parent id. action_runner.Wait(2) # Click on the yahoo amp link and then just wait for it to load. element_function = js_template.Render( 'document.querySelectorAll({{ selector }})[{{ index }}]', selector=self.ITEM_SELECTOR, index=0) action_runner.WaitForElement(element_function=element_function) action_runner.ClickElement(element_function=element_function) # Waiting for the document to fully render action_runner.Wait(2)
def ExecuteJavaScript(self, statement, **kwargs): """Executes a given JavaScript expression. Does not return the result. Example: runner.ExecuteJavaScript('var foo = {{ value }};', value=1); Args: statement: The statement to execute (provided as string). **kwargs: Additional keyword arguments are interpolated within the statement. See telemetry.util.js_template for details. Raises: EvaluationException: The statement failed to execute. """ self._tab.ExecuteJavaScript(js_template.Render(statement, **kwargs))
def RunAction(self, tab): # TODO(catapult:#3028): Render in JavaScript method when supported by API. code = js_template.Render( 'window.__loadMediaAndAwait({{ selector }}, {{ event }});', selector=self._selector, event=self._event_to_await) try: tab.ExecuteJavaScript(code) if self._timeout_in_seconds > 0: self.WaitForEvent(tab, self._selector, self._event_to_await, self._timeout_in_seconds) except exceptions.EvaluateException: raise page_action.PageActionFailed('Failed waiting for event "%s" on ' 'elements with selector = %s.' % (self._event_to_await, self._selector))
def RunAction(self, tab): # TODO(catapult:#3028): Render in JavaScript method when supported by API. code = js_template.Render( 'window.__loopMedia({{ selector }}, {{ loop_count }});', selector=self._selector, loop_count=self._loop_count) try: tab.ExecuteJavaScript(code) if self._timeout_in_seconds > 0: self.WaitForEvent(tab, self._selector, 'loop', self._timeout_in_seconds) except exceptions.EvaluateException: raise page_action.PageActionFailed( 'Cannot loop media element(s) with ' 'selector = %s.' % self._selector)
def WaitForJavaScriptCondition(self, condition, **kwargs): """Wait for a JavaScript condition to become true. Example: runner.WaitForJavaScriptCondition('window.foo == 10'); Args: condition: The JavaScript condition (as string). timeout_in_seconds: The timeout in seconds (default to 60). **kwargs: Additional keyword arguments are interpolated within the statement. See telemetry.util.js_template for details. """ timeout = kwargs.get('timeout_in_seconds', 60) self._tab.WaitForJavaScriptExpression(js_template.Render( condition, **kwargs), timeout=timeout)