[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 1 | # Copyright 2014 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. |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 4 | from telemetry.page import page as page_module |
nednguyen | 7f9aa0c | 2015-06-11 20:48:21 | [diff] [blame] | 5 | from telemetry.page import shared_page_state |
nednguyen | b82df29 | 2015-07-01 20:17:15 | [diff] [blame] | 6 | from telemetry import story |
perezju | 80aedca | 2017-01-12 10:03:00 | [diff] [blame] | 7 | from telemetry.util import js_template |
nednguyen | 7f9aa0c | 2015-06-11 20:48:21 | [diff] [blame] | 8 | |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 9 | |
[email protected] | 0d8afa5b | 2014-05-02 16:58:53 | [diff] [blame] | 10 | class PolymerPage(page_module.Page): |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 11 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 12 | def __init__(self, url, page_set, run_no_page_interactions): |
| 13 | """ Base class for all polymer pages. |
| 14 | |
| 15 | Args: |
| 16 | run_no_page_interactions: whether the page will run any interactions after |
| 17 | navigate steps. |
| 18 | """ |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 19 | super(PolymerPage, self).__init__( |
| 20 | url=url, |
nednguyen | 7f9aa0c | 2015-06-11 20:48:21 | [diff] [blame] | 21 | shared_page_state_class=shared_page_state.SharedMobilePageState, |
ashleymarie | 500f75b2 | 2017-06-06 19:24:08 | [diff] [blame] | 22 | page_set=page_set, |
| 23 | name=url) |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 24 | self.script_to_evaluate_on_commit = ''' |
| 25 | document.addEventListener("polymer-ready", function() { |
| 26 | window.__polymer_ready = true; |
| 27 | }); |
| 28 | ''' |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 29 | self._run_no_page_interactions = run_no_page_interactions |
| 30 | |
vmiura | 70e100f2 | 2015-02-18 02:45:28 | [diff] [blame] | 31 | def RunPageInteractions(self, action_runner): |
| 32 | # If a polymer page wants to customize its actions, it should |
| 33 | # override the PerformPageInteractions method instead of this method. |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 34 | if self._run_no_page_interactions: |
| 35 | return |
| 36 | self.PerformPageInteractions(action_runner) |
| 37 | |
| 38 | def PerformPageInteractions(self, action_runner): |
| 39 | """ Override this to perform actions after the page has navigated. """ |
| 40 | pass |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 41 | |
| 42 | def RunNavigateSteps(self, action_runner): |
ariblue | 735db9f | 2015-01-15 20:14:35 | [diff] [blame] | 43 | super(PolymerPage, self).RunNavigateSteps(action_runner) |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 44 | action_runner.WaitForJavaScriptCondition( |
[email protected] | 64bb94f | 2014-06-08 07:00:57 | [diff] [blame] | 45 | 'window.__polymer_ready') |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 46 | |
| 47 | |
| 48 | class PolymerCalculatorPage(PolymerPage): |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 49 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 50 | def __init__(self, page_set, run_no_page_interactions): |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 51 | super(PolymerCalculatorPage, self).__init__( |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 52 | url=('http://www.polymer-project.org/components/paper-calculator/' |
| 53 | 'demo.html'), |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 54 | page_set=page_set, run_no_page_interactions=run_no_page_interactions) |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 55 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 56 | def PerformPageInteractions(self, action_runner): |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 57 | self.TapButton(action_runner) |
| 58 | self.SlidePanel(action_runner) |
| 59 | |
| 60 | def TapButton(self, action_runner): |
nednguyen | eb2eca94 | 2015-04-28 00:08:09 | [diff] [blame] | 61 | with action_runner.CreateInteraction('PolymerAnimation', repeatable=True): |
nednguyen | 9e1bf62a4 | 2015-04-09 22:55:51 | [diff] [blame] | 62 | action_runner.TapElement(element_function=''' |
| 63 | document.querySelector( |
| 64 | 'body /deep/ #outerPanels' |
| 65 | ).querySelector( |
| 66 | '#standard' |
| 67 | ).shadowRoot.querySelector( |
| 68 | 'paper-calculator-key[label="5"]' |
| 69 | )''') |
| 70 | action_runner.Wait(2) |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 71 | |
| 72 | def SlidePanel(self, action_runner): |
[email protected] | d89ff64 | 2014-08-21 20:46:33 | [diff] [blame] | 73 | # only bother with this interaction if the drawer is hidden |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 74 | opened = action_runner.EvaluateJavaScript(''' |
[email protected] | d89ff64 | 2014-08-21 20:46:33 | [diff] [blame] | 75 | (function() { |
| 76 | var outer = document.querySelector("body /deep/ #outerPanels"); |
| 77 | return outer.opened || outer.wideMode; |
| 78 | }());''') |
| 79 | if not opened: |
nednguyen | eb2eca94 | 2015-04-28 00:08:09 | [diff] [blame] | 80 | with action_runner.CreateInteraction('PolymerAnimation', repeatable=True): |
nednguyen | 9e1bf62a4 | 2015-04-09 22:55:51 | [diff] [blame] | 81 | action_runner.SwipeElement( |
| 82 | left_start_ratio=0.1, top_start_ratio=0.2, |
| 83 | direction='left', distance=300, speed_in_pixels_per_second=5000, |
| 84 | element_function=''' |
| 85 | document.querySelector( |
| 86 | 'body /deep/ #outerPanels' |
| 87 | ).querySelector( |
| 88 | '#advanced' |
| 89 | ).shadowRoot.querySelector( |
| 90 | '.handle-bar' |
| 91 | )''') |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 92 | action_runner.WaitForJavaScriptCondition(''' |
nednguyen | 9e1bf62a4 | 2015-04-09 22:55:51 | [diff] [blame] | 93 | var outer = document.querySelector("body /deep/ #outerPanels"); |
| 94 | outer.opened || outer.wideMode;''') |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 95 | |
| 96 | |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 97 | class PolymerShadowPage(PolymerPage): |
| 98 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 99 | def __init__(self, page_set, run_no_page_interactions): |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 100 | super(PolymerShadowPage, self).__init__( |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 101 | url='http://www.polymer-project.org/components/paper-shadow/demo.html', |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 102 | page_set=page_set, run_no_page_interactions=run_no_page_interactions) |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 103 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 104 | def PerformPageInteractions(self, action_runner): |
nednguyen | 0b55812e | 2015-04-22 00:35:52 | [diff] [blame] | 105 | with action_runner.CreateInteraction('ScrollAndShadowAnimation'): |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 106 | action_runner.ExecuteJavaScript( |
nednguyen | 0b55812e | 2015-04-22 00:35:52 | [diff] [blame] | 107 | "document.getElementById('fab').scrollIntoView()") |
| 108 | action_runner.Wait(5) |
| 109 | self.AnimateShadow(action_runner, 'card') |
| 110 | #FIXME(wiltzius) disabling until this issue is fixed: |
| 111 | # https://github.com/Polymer/paper-shadow/issues/12 |
| 112 | #self.AnimateShadow(action_runner, 'fab') |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 113 | |
| 114 | def AnimateShadow(self, action_runner, eid): |
| 115 | for i in range(1, 6): |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 116 | action_runner.ExecuteJavaScript( |
perezju | 80aedca | 2017-01-12 10:03:00 | [diff] [blame] | 117 | 'document.getElementById({{ eid }}).z = {{ i }}', eid=eid, i=i) |
[email protected] | 64bb94f | 2014-06-08 07:00:57 | [diff] [blame] | 118 | action_runner.Wait(1) |
[email protected] | 8cbe070 | 2014-05-02 02:10:07 | [diff] [blame] | 119 | |
| 120 | |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 121 | class PolymerSampler(PolymerPage): |
| 122 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 123 | def __init__(self, page_set, anchor, run_no_page_interactions, |
| 124 | scrolling_page=False): |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 125 | """Page exercising interactions with a single Paper Sampler subpage. |
| 126 | |
| 127 | Args: |
| 128 | page_set: Page set to inforporate this page into. |
| 129 | anchor: string indicating which subpage to load (matches the element |
| 130 | type that page is displaying) |
| 131 | scrolling_page: Whether scrolling the content pane is relevant to this |
| 132 | content page or not. |
| 133 | """ |
| 134 | super(PolymerSampler, self).__init__( |
[email protected] | 04caf73 | 2014-08-19 23:42:49 | [diff] [blame] | 135 | url=('http://www.polymer-project.org/components/%s/demo.html' % anchor), |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 136 | page_set=page_set, run_no_page_interactions=run_no_page_interactions) |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 137 | self.scrolling_page = scrolling_page |
[email protected] | 04caf73 | 2014-08-19 23:42:49 | [diff] [blame] | 138 | self.iframe_js = 'document' |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 139 | |
| 140 | def RunNavigateSteps(self, action_runner): |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 141 | super(PolymerSampler, self).RunNavigateSteps(action_runner) |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 142 | action_runner.ExecuteJavaScript(""" |
perezju | 80aedca | 2017-01-12 10:03:00 | [diff] [blame] | 143 | window.Polymer.whenPolymerReady(function() { |
| 144 | {{ @iframe }}.contentWindow.Polymer.whenPolymerReady(function() { |
| 145 | window.__polymer_ready = true; |
| 146 | }) |
| 147 | }); |
| 148 | """, iframe=self.iframe_js) |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 149 | action_runner.WaitForJavaScriptCondition( |
[email protected] | 9e9bef02 | 2014-08-06 21:31:38 | [diff] [blame] | 150 | 'window.__polymer_ready') |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 151 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 152 | def PerformPageInteractions(self, action_runner): |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 153 | #TODO(wiltzius) Add interactions for input elements and shadow pages |
| 154 | if self.scrolling_page: |
| 155 | # Only bother scrolling the page if its been marked as worthwhile |
| 156 | self.ScrollContentPane(action_runner) |
| 157 | self.TouchEverything(action_runner) |
| 158 | |
| 159 | def ScrollContentPane(self, action_runner): |
[email protected] | 04caf73 | 2014-08-19 23:42:49 | [diff] [blame] | 160 | element_function = (self.iframe_js + '.querySelector(' |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 161 | '"core-scroll-header-panel").$.mainContainer') |
nednguyen | eb2eca94 | 2015-04-28 00:08:09 | [diff] [blame] | 162 | with action_runner.CreateInteraction('Scroll_Page', repeatable=True): |
nednguyen | 9e1bf62a4 | 2015-04-09 22:55:51 | [diff] [blame] | 163 | action_runner.ScrollElement(use_touch=True, |
| 164 | direction='down', |
| 165 | distance='900', |
| 166 | element_function=element_function) |
nednguyen | eb2eca94 | 2015-04-28 00:08:09 | [diff] [blame] | 167 | with action_runner.CreateInteraction('Scroll_Page', repeatable=True): |
nednguyen | 9e1bf62a4 | 2015-04-09 22:55:51 | [diff] [blame] | 168 | action_runner.ScrollElement(use_touch=True, |
| 169 | direction='up', |
| 170 | distance='900', |
| 171 | element_function=element_function) |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 172 | |
| 173 | def TouchEverything(self, action_runner): |
[email protected] | 26b7dfe | 2014-07-17 14:26:56 | [diff] [blame] | 174 | tappable_types = [ |
| 175 | 'paper-button', |
| 176 | 'paper-checkbox', |
| 177 | 'paper-fab', |
| 178 | 'paper-icon-button', |
[email protected] | ad6bcbc3 | 2014-08-06 02:59:53 | [diff] [blame] | 179 | # crbug.com/394756 |
| 180 | # 'paper-radio-button', |
[email protected] | 26b7dfe | 2014-07-17 14:26:56 | [diff] [blame] | 181 | 'paper-tab', |
| 182 | 'paper-toggle-button', |
| 183 | 'x-shadow', |
| 184 | ] |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 185 | for tappable_type in tappable_types: |
| 186 | self.DoActionOnWidgetType(action_runner, tappable_type, self.TapWidget) |
| 187 | swipeable_types = ['paper-slider'] |
| 188 | for swipeable_type in swipeable_types: |
| 189 | self.DoActionOnWidgetType(action_runner, swipeable_type, self.SwipeWidget) |
| 190 | |
| 191 | def DoActionOnWidgetType(self, action_runner, widget_type, action_function): |
| 192 | # Find all widgets of this type, but skip any that are disabled or are |
| 193 | # currently active as they typically don't produce animation frames. |
perezju | 80aedca | 2017-01-12 10:03:00 | [diff] [blame] | 194 | element_list_query = js_template.Render( |
| 195 | '{{ @iframe }}.querySelectorAll({{ selector }})', |
| 196 | iframe=self.iframe_js, |
| 197 | selector='body %s:not([disabled]):not([active])' % widget_type) |
| 198 | |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 199 | roles_count_query = element_list_query + '.length' |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 200 | for i in range(action_runner.EvaluateJavaScript(roles_count_query)): |
perezju | 80aedca | 2017-01-12 10:03:00 | [diff] [blame] | 201 | element_query = js_template.Render( |
| 202 | '{{ @query }}[{{ i }}]', query=element_list_query, i=i) |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 203 | if action_runner.EvaluateJavaScript( |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 204 | element_query + '.offsetParent != null'): |
| 205 | # Only try to tap on visible elements (offsetParent != null) |
perezju | d42421be | 2017-02-28 09:40:20 | [diff] [blame] | 206 | action_runner.ExecuteJavaScript(element_query + '.scrollIntoView()') |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 207 | action_runner.Wait(1) # wait for page to settle after scrolling |
| 208 | action_function(action_runner, element_query) |
| 209 | |
| 210 | def TapWidget(self, action_runner, element_function): |
nednguyen | eb2eca94 | 2015-04-28 00:08:09 | [diff] [blame] | 211 | with action_runner.CreateInteraction('Tap_Widget', repeatable=True): |
nednguyen | 9e1bf62a4 | 2015-04-09 22:55:51 | [diff] [blame] | 212 | action_runner.TapElement(element_function=element_function) |
| 213 | action_runner.Wait(1) # wait for e.g. animations on the widget |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 214 | |
| 215 | def SwipeWidget(self, action_runner, element_function): |
nednguyen | 9e1bf62a4 | 2015-04-09 22:55:51 | [diff] [blame] | 216 | with action_runner.CreateInteraction('Swipe_Widget'): |
| 217 | action_runner.SwipeElement(element_function=element_function, |
| 218 | left_start_ratio=0.75, |
| 219 | speed_in_pixels_per_second=300) |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 220 | |
| 221 | |
nednguyen | b82df29 | 2015-07-01 20:17:15 | [diff] [blame] | 222 | class PolymerPageSet(story.StorySet): |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 223 | |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 224 | def __init__(self, run_no_page_interactions=False): |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 225 | super(PolymerPageSet, self).__init__( |
[email protected] | 41af08a | 2014-06-13 09:05:31 | [diff] [blame] | 226 | archive_data_file='data/polymer.json', |
ashleymarie | c3c82af | 2017-06-14 02:21:54 | [diff] [blame] | 227 | cloud_storage_bucket=story.PUBLIC_BUCKET) |
[email protected] | 58ec0f4 | 2014-04-26 22:41:43 | [diff] [blame] | 228 | |
nednguyen | 98099b8 | 2015-07-06 23:07:24 | [diff] [blame] | 229 | self.AddStory(PolymerCalculatorPage(self, run_no_page_interactions)) |
| 230 | self.AddStory(PolymerShadowPage(self, run_no_page_interactions)) |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 231 | |
| 232 | # Polymer Sampler subpages that are interesting to tap / swipe elements on |
[email protected] | 26b7dfe | 2014-07-17 14:26:56 | [diff] [blame] | 233 | TAPPABLE_PAGES = [ |
| 234 | 'paper-button', |
| 235 | 'paper-checkbox', |
| 236 | 'paper-fab', |
| 237 | 'paper-icon-button', |
[email protected] | ad6bcbc3 | 2014-08-06 02:59:53 | [diff] [blame] | 238 | # crbug.com/394756 |
| 239 | # 'paper-radio-button', |
[email protected] | 04caf73 | 2014-08-19 23:42:49 | [diff] [blame] | 240 | #FIXME(wiltzius) Disabling x-shadow until this issue is fixed: |
| 241 | # https://github.com/Polymer/paper-shadow/issues/12 |
| 242 | #'paper-shadow', |
[email protected] | 26b7dfe | 2014-07-17 14:26:56 | [diff] [blame] | 243 | 'paper-tabs', |
| 244 | 'paper-toggle-button', |
| 245 | ] |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 246 | for p in TAPPABLE_PAGES: |
nednguyen | 98099b8 | 2015-07-06 23:07:24 | [diff] [blame] | 247 | self.AddStory(PolymerSampler( |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 248 | self, p, run_no_page_interactions=run_no_page_interactions)) |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 249 | |
| 250 | # Polymer Sampler subpages that are interesting to scroll |
[email protected] | 781849a0 | 2014-07-18 16:14:44 | [diff] [blame] | 251 | SCROLLABLE_PAGES = [ |
[email protected] | 04caf73 | 2014-08-19 23:42:49 | [diff] [blame] | 252 | 'core-scroll-header-panel', |
[email protected] | 781849a0 | 2014-07-18 16:14:44 | [diff] [blame] | 253 | ] |
[email protected] | 71c9278 | 2014-07-15 18:05:53 | [diff] [blame] | 254 | for p in SCROLLABLE_PAGES: |
nednguyen | 98099b8 | 2015-07-06 23:07:24 | [diff] [blame] | 255 | self.AddStory(PolymerSampler( |
nednguyen | 05140bce | 2015-02-16 17:07:56 | [diff] [blame] | 256 | self, p, run_no_page_interactions=run_no_page_interactions, |
| 257 | scrolling_page=True)) |
| 258 | |
| 259 | for page in self: |
| 260 | assert (page.__class__.RunPageInteractions == |
| 261 | PolymerPage.RunPageInteractions), ( |
| 262 | 'Pages in this page set must not override PolymerPage\' ' |
| 263 | 'RunPageInteractions method.') |