def Start(self, tab): # Start the smooth marker for all actions. runner = action_runner.ActionRunner(tab) if self._enable_auto_issuing_record: self._interaction = runner.CreateInteraction( RUN_SMOOTH_ACTIONS) self._interaction.Begin()
def testPinchByApiCalledWithCorrectArguments(self): self.Navigate('blank.html') if not page_action.IsGestureSourceTypeSupported(self._tab, 'touch'): return action_runner = action_runner_module.ActionRunner(self._tab) action_runner.ExecuteJavaScript(''' chrome.gpuBenchmarking.pinchBy = function( scaleFactor, anchorLeft, anchorTop, callback, speed) { window.__test_scaleFactor = scaleFactor; window.__test_anchorLeft = anchorLeft; window.__test_anchorTop = anchorTop; window.__test_callback = callback; window.__test_speed = speed; window.__pinchActionDone = true; };''') action_runner.PinchPage(scale_factor=2) self.assertEqual( 2, action_runner.EvaluateJavaScript('window.__test_scaleFactor')) self.assertTrue( action_runner.EvaluateJavaScript('!isNaN(window.__test_anchorLeft)')) self.assertTrue( action_runner.EvaluateJavaScript('!isNaN(window.__test_anchorTop)')) self.assertTrue( action_runner.EvaluateJavaScript('!!window.__test_callback')) self.assertEqual( 800, action_runner.EvaluateJavaScript('window.__test_speed'))
def ValidateAndMeasurePage(self, page, tab, results): runner = action_runner.ActionRunner(tab) # timeline_controller requires creation of at least a single interaction # record. service_worker should be refactored to follow the # timeline_based_measurement or it should not re-use timeline_controller # logic for start & stop tracing. with runner.CreateInteraction('_DummyInteraction'): pass tab.WaitForJavaScriptExpression('window.done', 40) self._timeline_controller.Stop(tab, results) # Measure JavaScript-land json = tab.EvaluateJavaScript('window.results || {}') for key, value in json.iteritems(): results.AddValue(scalar.ScalarValue( results.current_page, key, value['units'], value['value'])) # Retrieve TRACE_EVENTs timeline_metric = _ServiceWorkerTimelineMetric() browser_process = self._timeline_controller.model.browser_process filter_text = '(RegisterServiceWorker|'\ 'UnregisterServiceWorker|'\ 'ProcessAllocate|'\ 'FindRegistrationForDocument|'\ 'DispatchFetchEvent)' timeline_metric.AddResultsOfEvents( browser_process, 'IOThread', filter_text , results)
def testScroll(self): if not page_action.IsGestureSourceTypeSupported(self._tab, 'touch'): return self.Navigate('page_with_swipeables.html') action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) action_runner.ScrollElement(selector='#left-right', direction='right', left_start_ratio=0.9) self.assertTrue( action_runner.EvaluateJavaScript( 'document.querySelector("#left-right").scrollLeft') > 75) action_runner.ScrollElement(selector='#top-bottom', direction='down', top_start_ratio=0.9) self.assertTrue( action_runner.EvaluateJavaScript( 'document.querySelector("#top-bottom").scrollTop') > 75) action_runner.ScrollPage(direction='right', left_start_ratio=0.9, distance=100) self.assertTrue( action_runner.EvaluateJavaScript('document.body.scrollLeft') > 75)
def testEvaluateCallbackWithElement(self): self.Navigate('blank.html') runner = action_runner.ActionRunner(self._tab) runner.ExecuteJavaScript(''' (function() { function createElement(id, textContent) { var el = document.createElement("div"); el.id = id; el.textContent = textContent; document.body.appendChild(el); } createElement('test-1', 'foo'); createElement('test-2', 'bar'); createElement('test-3', 'baz'); })();''') self.assertEqual( 'foo', page_action.EvaluateCallbackWithElement( self._tab, 'function(el) { return el.textContent; }', selector='#test-1')) self.assertEqual( 'bar', page_action.EvaluateCallbackWithElement( self._tab, 'function(el) { return el.textContent; }', text='bar')) self.assertEqual( 'baz', page_action.EvaluateCallbackWithElement( self._tab, 'function(el) { return el.textContent; }', element_function='document.getElementById("test-3")')) self.assertEqual( 'baz', page_action.EvaluateCallbackWithElement( self._tab, 'function(el) { return el.textContent; }', element_function=''' (function() { return document.getElementById("test-3"); })()''')) # Test for when the element is not found. self.assertEqual( None, page_action.EvaluateCallbackWithElement( self._tab, 'function(el) { return el; }', element_function='document.getElementById("test-4")')) # Test the info message. self.assertEqual( 'using selector "#test-1"', page_action.EvaluateCallbackWithElement( self._tab, 'function(el, info) { return info; }', selector='#test-1'))
def RunNavigateSteps(self, page, tab): """Navigates the tab to the page URL attribute. Runs the 'navigate_steps' page attribute as a compound action. """ action_runner = action_runner_module.ActionRunner( tab, skip_waits=page.skip_waits) page.RunNavigateSteps(action_runner)
def LoginNeeded(self, tab, credentials_type): if credentials_type not in self._backends: raise CredentialsError('Unrecognized credentials type: %s', credentials_type) if credentials_type not in self._credentials: return False from telemetry.page import action_runner runner = action_runner.ActionRunner(tab) return self._backends[credentials_type].LoginNeeded( tab, runner, self._credentials[credentials_type])
def testMediaRouterDialog(self): self._tab.Navigate(self.UrlOfUnittestFile('cast.html')) self._tab.WaitForDocumentReadyStateToBeComplete() runner = action_runner.ActionRunner(self._tab) runner.TapElement(selector='#start_session_button') # Wait for media router dialog start_time = time.time() while (time.time() - start_time < 5 and len(self.tabs) != 2): time.sleep(1) self.assertEquals(len(self.tabs), 2) self.assertEquals(self.tabs[1].url, 'chrome://media-router/')
def RunPage(self, page, tab, results): # Run actions. interactive = self.options and self.options.interactive action_runner = action_runner_module.ActionRunner( tab, skip_waits=page.skip_waits) self.WillRunActions(page, tab) if interactive: action_runner.PauseInteractive() else: page.RunPageInteractions(action_runner) self.DidRunActions(page, tab) self.ValidateAndMeasurePage(page, tab, results)
def testWaitForNavigate(self): self.Navigate('page_with_link.html') action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) action_runner.ClickElement('#clickme') action_runner.WaitForNavigate() self.assertTrue(self._tab.EvaluateJavaScript( 'document.readyState == "interactive" || ' 'document.readyState == "complete"')) self.assertEqual( self._tab.EvaluateJavaScript('document.location.pathname;'), '/blank.html')
def Run(self, shared_state): current_tab = shared_state.current_tab # Collect garbage from previous run several times to make the results more # stable if needed. if self._collect_garbage_before_run: for _ in xrange(0, 5): current_tab.CollectGarbage() shared_state.page_test.WillNavigateToPage(self, current_tab) shared_state.page_test.RunNavigateSteps(self, current_tab) shared_state.page_test.DidNavigateToPage(self, current_tab) action_runner = action_runner_module.ActionRunner( current_tab, skip_waits=self.skip_waits) self.RunPageInteractions(action_runner)
def testWaitForJavaScriptCondition(self): action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) self.Navigate('blank.html') action_runner.ExecuteJavaScript('window.testing = 219;') action_runner.WaitForJavaScriptCondition('window.testing == 219', timeout_in_seconds=0.1) action_runner.ExecuteJavaScript( 'window.setTimeout(function() { window.testing = 220; }, 50);') action_runner.WaitForJavaScriptCondition('window.testing == 220', timeout_in_seconds=0.1) self.assertEqual(220, self._tab.EvaluateJavaScript('window.testing'))
def testWait(self): action_runner = action_runner_module.ActionRunner(self._tab) self.Navigate('blank.html') action_runner.ExecuteJavaScript( 'window.setTimeout(function() { window.testing = 101; }, 50);') action_runner.Wait(0.1) self.assertEqual(101, self._tab.EvaluateJavaScript('window.testing')) action_runner.ExecuteJavaScript( 'window.setTimeout(function() { window.testing = 102; }, 100);') action_runner.Wait(0.2) self.assertEqual(102, self._tab.EvaluateJavaScript('window.testing'))
def testWaitForElementWithWrongText(self): action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) self.Navigate('blank.html') action_runner.ExecuteJavaScript( '(function() {' ' var el = document.createElement("div");' ' el.id = "test1";' ' el.textContent = "foo";' ' document.body.appendChild(el);' '})()') action_runner.WaitForElement('#test1', timeout_in_seconds=0.2) def WaitForElement(): action_runner.WaitForElement(text='oo', timeout_in_seconds=0.2) self.assertRaises(exceptions.TimeoutException, WaitForElement)
def RunUserStory(self, results): try: self._PreparePage() self._ImplicitPageNavigation() action_runner = action_runner_module.ActionRunner( self._current_tab, skip_waits=self._current_page.skip_waits) self._current_page.RunPageInteractions(action_runner) self._test.ValidateAndMeasurePage( self._current_page, self._current_tab, results) except exceptions.Error: if self._test.is_multi_tab_test: # Avoid trying to recover from an unknown multi-tab state. exception_formatter.PrintFormattedException( msg='Telemetry Error during multi tab test:') raise page_test.MultiTabTestAppCrashError raise
def LoginChromeAccount(action_runner, credential, credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH): """Logs in a Gaia account into Chrome. This function navigates the tab into Chrome's login page and logs in a user using credentials in |credential| part of the |credentials_path| file. Args: action_runner: Action runner responsible for running actions on the page. credential: The credential to retrieve from the credentials file (type string). credentials_path: The string that specifies the path to credential file. Raises: exceptions.Error: See GetWebviewContexts() and ExecuteJavaScript() for a detailed list of possible exceptions. """ account_name, password = login_utils.GetAccountNameAndPassword( credential, credentials_path=credentials_path) action_runner.Navigate('chrome://chrome-signin') # Get the Gaia webview context within the sign in extension to create a Gaia # action_runner. The action runner will then execute JS in the Gaia context. gaia_context = util.WaitFor(lambda: GetGaiaContext(action_runner.tab), 5) if not gaia_context: raise RuntimeError('Can not find GAIA webview context for sign in.') gaia_action_runner = action_runner_module.ActionRunner(gaia_context) new_flow = gaia_action_runner.EvaluateJavaScript( 'document.querySelector("#gaia_firsform") != null') gaia_form_id = 'gaia_firstform' if new_flow else 'gaia_loginform' login_utils.InputForm(gaia_action_runner, account_name, input_id='Email', form_id=gaia_form_id) if new_flow: gaia_action_runner.ClickElement(selector='#%s #next' % gaia_form_id) login_utils.InputForm(gaia_action_runner, password, input_id='Passwd', form_id=gaia_form_id) gaia_action_runner.ClickElement(selector='#signIn') action_runner.WaitForNavigate()
def testTapElement(self): self.Navigate('page_with_clickables.html') action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) action_runner.ExecuteJavaScript('valueSettableByTest = 1;') action_runner.TapElement('#test') self.assertEqual(1, action_runner.EvaluateJavaScript('valueToTest')) action_runner.ExecuteJavaScript('valueSettableByTest = 2;') action_runner.TapElement(text='Click/tap me') self.assertEqual(2, action_runner.EvaluateJavaScript('valueToTest')) action_runner.ExecuteJavaScript('valueSettableByTest = 3;') action_runner.TapElement( element_function='document.body.firstElementChild') self.assertEqual(3, action_runner.EvaluateJavaScript('valueToTest')) def WillFail(): action_runner.TapElement('#notfound') self.assertRaises(exceptions.EvaluateException, WillFail)
def VerifyIssuingInteractionRecords(self, **interaction_kwargs): action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) self.Navigate('interaction_enabled_page.html') action_runner.Wait(1) options = tracing_options.TracingOptions() options.enable_chrome_trace = True self._browser.platform.tracing_controller.Start( options, tracing_category_filter.CreateNoOverheadFilter()) with action_runner.CreateInteraction('InteractionName', **interaction_kwargs): pass trace_data = self._browser.platform.tracing_controller.Stop() records = self.GetInteractionRecords(trace_data) self.assertEqual( 1, len(records), 'Failed to issue the interaction record on the tracing timeline.' ' Trace data:\n%s' % repr(trace_data._raw_data)) self.assertEqual('InteractionName', records[0].label) for attribute_name in interaction_kwargs: self.assertTrue(getattr(records[0], attribute_name))
def ValidateAndMeasurePage(self, page, tab, results): runner = action_runner.ActionRunner(tab) # timeline_controller requires creation of at least a single interaction # record. service_worker should be refactored to follow the # timeline_based_measurement or it should not re-use timeline_controller # logic for start & stop tracing. with runner.CreateInteraction('_DummyInteraction'): pass tab.WaitForDocumentReadyStateToBeComplete(40) self._timeline_controller.Stop(tab, results) # Retrieve TRACE_EVENTs timeline_metric = _ServiceWorkerTimelineMetric() browser_process = self._timeline_controller.model.browser_process filter_text = '(RegisterServiceWorker|'\ 'UnregisterServiceWorker|'\ 'ProcessAllocate|'\ 'FindRegistrationForDocument|'\ 'DispatchFetchEvent)' timeline_metric.AddResultsOfEvents(browser_process, 'IOThread', filter_text, results) # Record Speed Index def SpeedIndexIsFinished(): return self._speed_index.IsFinished(tab) util.WaitFor(SpeedIndexIsFinished, 60) self._speed_index.Stop(page, tab) # Distinguish the first and second load from the subsequent loads url = str(page) chart_prefix = 'page_load' self._page_open_times[url] += 1 if self._page_open_times[url] == 1: chart_prefix += '_1st' elif self._page_open_times[url] == 2: chart_prefix += '_2nd' else: chart_prefix += '_later' self._speed_index.AddResults(tab, results, chart_prefix)
def testWaitForElement(self): action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) self.Navigate('blank.html') action_runner.ExecuteJavaScript( '(function() {' ' var el = document.createElement("div");' ' el.id = "test1";' ' el.textContent = "foo";' ' document.body.appendChild(el);' '})()') action_runner.WaitForElement('#test1', timeout_in_seconds=0.1) action_runner.WaitForElement(text='foo', timeout_in_seconds=0.1) action_runner.WaitForElement( element_function='document.getElementById("test1")') action_runner.ExecuteJavaScript( 'window.setTimeout(function() {' ' var el = document.createElement("div");' ' el.id = "test2";' ' document.body.appendChild(el);' '}, 50)') action_runner.WaitForElement('#test2', timeout_in_seconds=0.1) action_runner.ExecuteJavaScript( 'window.setTimeout(function() {' ' document.getElementById("test2").textContent = "bar";' '}, 50)') action_runner.WaitForElement(text='bar', timeout_in_seconds=0.1) action_runner.ExecuteJavaScript( 'window.setTimeout(function() {' ' var el = document.createElement("div");' ' el.id = "test3";' ' document.body.appendChild(el);' '}, 50)') action_runner.WaitForElement( element_function='document.getElementById("test3")')
def ValidateAndMeasurePage(self, page, tab, results): runner = action_runner.ActionRunner(tab) with runner.CreateInteraction('wait-for-quiescence'): tab.ExecuteJavaScript('console.time("");') try: util.WaitFor(tab.HasReachedQuiescence, 15) except exceptions.TimeoutException: # Some sites never reach quiesence. As this benchmark normalizes/ # categories results, it shouldn't be necessary to reach the same # state on every run. pass tab.ExecuteJavaScript( 'console.time("style-update");' # Occasionally documents will break the APIs we need. 'try {' # Invalidate style for the whole document. ' document && (document.documentElement.lang += "z");' # Force a style update (but not layout). ' getComputedStyle(document.documentElement).color;' '} catch (e) {}' 'console.timeEnd("style-update");') self._controller.Stop(tab, results) renderer = self._controller.model.GetRendererThreadFromTabId(tab.id) markers = [ event for event in renderer.async_slices if event.name == 'style-update' and event.category == 'blink.console' ] assert len(markers) == 1 marker = markers[0] def duration(event): if event.has_thread_timestamps: return event.thread_duration else: return event.duration for event in renderer.all_slices: if (event.name == 'Document::updateStyle' and event.start >= marker.start and event.end <= marker.end): access_count = event.args.get('resolverAccessCount') if access_count is None: # absent in earlier versions continue min_access_count = 50 if access_count >= min_access_count: result = 1000 * (duration(event) / access_count) results.AddValue( scalar.ScalarValue(page, 'update_style', 'ms/1000 elements', result)) class ParserEvent(object): def __init__(self, summary_event, tokenize_event, parse_event): min_sheet_length = 1000 ua_sheet_mode = 5 enormous_token_threshold = 100 large_token_threshold = 5 self.mode = summary_event.args.get('mode') self.length = summary_event.args.get('length') self.tokens = summary_event.args.get('tokenCount') self.tokenize_duration = duration(tokenize_event) self.parse_duration = duration(parse_event) self.chars_per_token = 0 if self.tokens: self.chars_per_token = self.length / float(self.tokens) if self.mode == ua_sheet_mode or self.length < min_sheet_length: self.category = 'ignored' elif self.chars_per_token > enormous_token_threshold: self.category = 'enormous_tokens' elif self.chars_per_token > large_token_threshold: self.category = 'large_tokens' else: self.category = 'regular' parser_events = [ event for event in renderer.all_slices if event.name == 'CSSParserImpl::parseStyleSheet' or event.name == 'CSSParserImpl::parseStyleSheet.tokenize' or event.name == 'CSSParserImpl::parseStyleSheet.parse' ] merged_events = starmap(ParserEvent, zip(*[iter(parser_events)] * 3)) events_by_category = defaultdict(list) for event in merged_events: if event.category != 'ignored': events_by_category[event.category].append(event) for category, events in events_by_category.items(): parse_duration = sum(event.parse_duration for event in events) tokenize_duration = sum(event.tokenize_duration for event in events) tokens = sum(event.tokens for event in events) length = sum(event.length for event in events) results.AddValue( scalar.ScalarValue(page, ('parse_css_%s' % category), 'tokens/s', 1000 / (parse_duration / tokens))) results.AddValue( scalar.ScalarValue(page, ('tokenize_css_%s' % category), 'char/s', 1000 / (tokenize_duration / length)))
def Start(self, tab): # Start the smooth marker for all actions. runner = action_runner.ActionRunner(tab) self._interaction = runner.CreateInteraction( RUN_SMOOTH_ACTIONS) self._interaction.Begin()
def testExecuteJavaScript(self): action_runner = action_runner_module.ActionRunner(self._tab, skip_waits=True) self.Navigate('blank.html') action_runner.ExecuteJavaScript('var testing = 42;') self.assertEqual(42, self._tab.EvaluateJavaScript('testing'))
def RunPage(self, page, tab, results): # Run actions. action_runner = action_runner_module.ActionRunner( tab, skip_waits=page.skip_waits) page.RunPageInteractions(action_runner) self.ValidateAndMeasurePage(page, tab, results)
def DidNavigateToPage(self, page, tab): runner = action_runner.ActionRunner(tab) self._interaction = runner.CreateInteraction(_RUN_SMOOTH_ACTIONS) self._interaction.Begin()