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.
4from telemetry.page import page as page_module
5from telemetry.page import page_set as page_set_module
6
7class PolymerPage(page_module.Page):
8
9  def __init__(self, url, page_set):
10    super(PolymerPage, self).__init__(
11      url=url,
12      page_set=page_set)
13    self.script_to_evaluate_on_commit = '''
14      document.addEventListener("polymer-ready", function() {
15        window.__polymer_ready = true;
16      });
17    '''
18
19  def RunNavigateSteps(self, action_runner):
20    action_runner.NavigateToPage(self)
21    action_runner.WaitForJavaScriptCondition(
22        'window.__polymer_ready')
23
24
25class PolymerCalculatorPage(PolymerPage):
26
27  def __init__(self, page_set):
28    super(PolymerCalculatorPage, self).__init__(
29      url=('http://www.polymer-project.org/components/paper-calculator/'
30          'demo.html'),
31      page_set=page_set)
32
33  def RunSmoothness(self, action_runner):
34    self.TapButton(action_runner)
35    self.SlidePanel(action_runner)
36
37  def TapButton(self, action_runner):
38    interaction = action_runner.BeginInteraction(
39        'Action_TapAction', is_smooth=True)
40    action_runner.TapElement(element_function='''
41        document.querySelector(
42            'body /deep/ #outerPanels'
43        ).querySelector(
44            '#standard'
45        ).shadowRoot.querySelector(
46            'paper-calculator-key[label="5"]'
47        )''')
48    action_runner.Wait(2)
49    interaction.End()
50
51  def SlidePanel(self, action_runner):
52    # only bother with this interaction if the drawer is hidden
53    opened = action_runner.EvaluateJavaScript('''
54        (function() {
55          var outer = document.querySelector("body /deep/ #outerPanels");
56          return outer.opened || outer.wideMode;
57          }());''')
58    if not opened:
59      interaction = action_runner.BeginInteraction(
60          'Action_SwipeAction', is_smooth=True)
61      action_runner.SwipeElement(
62          left_start_ratio=0.1, top_start_ratio=0.2,
63          direction='left', distance=300, speed_in_pixels_per_second=5000,
64          element_function='''
65              document.querySelector(
66                'body /deep/ #outerPanels'
67              ).querySelector(
68                '#advanced'
69              ).shadowRoot.querySelector(
70                '.handle-bar'
71              )''')
72      action_runner.WaitForJavaScriptCondition('''
73          var outer = document.querySelector("body /deep/ #outerPanels");
74          outer.opened || outer.wideMode;''')
75      interaction.End()
76
77
78class PolymerShadowPage(PolymerPage):
79
80  def __init__(self, page_set):
81    super(PolymerShadowPage, self).__init__(
82      url='http://www.polymer-project.org/components/paper-shadow/demo.html',
83      page_set=page_set)
84
85  def RunSmoothness(self, action_runner):
86    action_runner.ExecuteJavaScript(
87        "document.getElementById('fab').scrollIntoView()")
88    action_runner.Wait(5)
89    self.AnimateShadow(action_runner, 'card')
90    #FIXME(wiltzius) disabling until this issue is fixed:
91    # https://github.com/Polymer/paper-shadow/issues/12
92    #self.AnimateShadow(action_runner, 'fab')
93
94  def AnimateShadow(self, action_runner, eid):
95    for i in range(1, 6):
96      action_runner.ExecuteJavaScript(
97          'document.getElementById("{0}").z = {1}'.format(eid, i))
98      action_runner.Wait(1)
99
100
101class PolymerSampler(PolymerPage):
102
103  def __init__(self, page_set, anchor, scrolling_page=False):
104    """Page exercising interactions with a single Paper Sampler subpage.
105
106    Args:
107      page_set: Page set to inforporate this page into.
108      anchor: string indicating which subpage to load (matches the element
109          type that page is displaying)
110      scrolling_page: Whether scrolling the content pane is relevant to this
111          content page or not.
112    """
113    super(PolymerSampler, self).__init__(
114      url=('http://www.polymer-project.org/components/%s/demo.html' % anchor),
115      page_set=page_set)
116    self.scrolling_page = scrolling_page
117    self.iframe_js = 'document'
118
119  def RunNavigateSteps(self, action_runner):
120    super(PolymerSampler, self).RunNavigateSteps(action_runner)
121    waitForLoadJS = """
122      window.Polymer.whenPolymerReady(function() {
123        %s.contentWindow.Polymer.whenPolymerReady(function() {
124          window.__polymer_ready = true;
125        })
126      });
127      """ % self.iframe_js
128    action_runner.ExecuteJavaScript(waitForLoadJS)
129    action_runner.WaitForJavaScriptCondition(
130        'window.__polymer_ready')
131
132  def RunSmoothness(self, action_runner):
133    #TODO(wiltzius) Add interactions for input elements and shadow pages
134    if self.scrolling_page:
135      # Only bother scrolling the page if its been marked as worthwhile
136      self.ScrollContentPane(action_runner)
137    self.TouchEverything(action_runner)
138
139  def ScrollContentPane(self, action_runner):
140    element_function = (self.iframe_js + '.querySelector('
141        '"core-scroll-header-panel").$.mainContainer')
142    interaction = action_runner.BeginInteraction('Scroll_Page', is_smooth=True)
143    action_runner.ScrollElement(use_touch=True,
144                                direction='down',
145                                distance='900',
146                                element_function=element_function)
147    interaction.End()
148    interaction = action_runner.BeginInteraction('Scroll_Page', is_smooth=True)
149    action_runner.ScrollElement(use_touch=True,
150                                direction='up',
151                                distance='900',
152                                element_function=element_function)
153    interaction.End()
154
155  def TouchEverything(self, action_runner):
156    tappable_types = [
157        'paper-button',
158        'paper-checkbox',
159        'paper-fab',
160        'paper-icon-button',
161        # crbug.com/394756
162        # 'paper-radio-button',
163        'paper-tab',
164        'paper-toggle-button',
165        'x-shadow',
166        ]
167    for tappable_type in tappable_types:
168      self.DoActionOnWidgetType(action_runner, tappable_type, self.TapWidget)
169    swipeable_types = ['paper-slider']
170    for swipeable_type in swipeable_types:
171      self.DoActionOnWidgetType(action_runner, swipeable_type, self.SwipeWidget)
172
173  def DoActionOnWidgetType(self, action_runner, widget_type, action_function):
174    # Find all widgets of this type, but skip any that are disabled or are
175    # currently active as they typically don't produce animation frames.
176    element_list_query = (self.iframe_js +
177        ('.querySelectorAll("body %s:not([disabled]):'
178         'not([active])")' % widget_type))
179    roles_count_query = element_list_query + '.length'
180    for i in range(action_runner.EvaluateJavaScript(roles_count_query)):
181      element_query = element_list_query + ("[%d]" % i)
182      if action_runner.EvaluateJavaScript(
183          element_query + '.offsetParent != null'):
184        # Only try to tap on visible elements (offsetParent != null)
185        action_runner.ExecuteJavaScript(element_query + '.scrollIntoView()')
186        action_runner.Wait(1) # wait for page to settle after scrolling
187        action_function(action_runner, element_query)
188
189  def TapWidget(self, action_runner, element_function):
190    interaction = action_runner.BeginInteraction(
191        'Tap_Widget', is_smooth=True)
192    action_runner.TapElement(element_function=element_function)
193    action_runner.Wait(1) # wait for e.g. animations on the widget
194    interaction.End()
195
196  def SwipeWidget(self, action_runner, element_function):
197    interaction = action_runner.BeginInteraction(
198        'Swipe_Widget', is_smooth=True)
199    action_runner.SwipeElement(element_function=element_function,
200                               left_start_ratio=0.75,
201                               speed_in_pixels_per_second=300)
202    interaction.End()
203
204
205class PolymerPageSet(page_set_module.PageSet):
206
207  def __init__(self):
208    super(PolymerPageSet, self).__init__(
209      user_agent_type='mobile',
210      archive_data_file='data/polymer.json',
211      bucket=page_set_module.PUBLIC_BUCKET)
212
213    self.AddPage(PolymerCalculatorPage(self))
214    self.AddPage(PolymerShadowPage(self))
215
216    # Polymer Sampler subpages that are interesting to tap / swipe elements on
217    TAPPABLE_PAGES = [
218        'paper-button',
219        'paper-checkbox',
220        'paper-fab',
221        'paper-icon-button',
222        # crbug.com/394756
223        # 'paper-radio-button',
224        #FIXME(wiltzius) Disabling x-shadow until this issue is fixed:
225        # https://github.com/Polymer/paper-shadow/issues/12
226        #'paper-shadow',
227        'paper-tabs',
228        'paper-toggle-button',
229        ]
230    for p in TAPPABLE_PAGES:
231      self.AddPage(PolymerSampler(self, p))
232
233    # Polymer Sampler subpages that are interesting to scroll
234    SCROLLABLE_PAGES = [
235        'core-scroll-header-panel',
236        ]
237    for p in SCROLLABLE_PAGES:
238      self.AddPage(PolymerSampler(self, p, scrolling_page=True))
239