OLD | NEW |
---|---|
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2017 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 from telemetry.page import page as page_module | 4 |
5 import sys | |
6 | |
7 from page_sets.login_helpers import facebook_login | |
8 from page_sets.system_health import platforms | |
9 from telemetry.core import discover | |
10 from telemetry.page import page | |
5 from telemetry.page import shared_page_state | 11 from telemetry.page import shared_page_state |
6 from telemetry import story | 12 from telemetry import story |
7 | 13 |
8 TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS = 5 | 14 class _InfiniteScrollStory(page.Page): |
9 SCROLL_TIMEOUT_IN_SECONDS = 120 | 15 """ Base class for infinite scroll stories.""" |
10 | 16 |
11 # TODO(ulan): Remove this once crbug.com/541508 is fixed. | 17 NAME = NotImplemented |
12 STARTUP_SCRIPT = ''' | 18 URL = NotImplemented |
13 window.WebSocket = undefined; | 19 SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS |
14 window.Worker = undefined; | |
15 window.performance = undefined;''' | |
16 | 20 |
21 SCROLL_DISTANCE = 25000 | |
22 SCROLL_STEP = 1000 | |
23 MAX_SCROLL_RETRIES = 3 | |
24 TIME_BEFORE_SCROLL_RETRY_IN_SECONDS = 1 | |
25 TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS = 5 | |
17 | 26 |
18 class InfiniteScrollPage(page_module.Page): | 27 def __init__(self, story_set): |
19 def __init__(self, url, page_set, name, scroll_amount, delay, repeat, | 28 super(_InfiniteScrollStory, self).__init__( |
20 credentials=None): | 29 page_set=story_set, url=self.URL, name=self.NAME, |
21 super(InfiniteScrollPage, self).__init__( | |
22 url=url, page_set=page_set, name=name, | |
23 shared_page_state_class=shared_page_state.SharedPageState, | 30 shared_page_state_class=shared_page_state.SharedPageState, |
24 credentials_path='data/credentials.json') | 31 credentials_path='data/credentials.json') |
25 self.credentials = credentials | 32 # TODO(ulan): Remove this once crbug.com/541508 is fixed. |
26 self.script_to_evaluate_on_commit = STARTUP_SCRIPT | 33 self.script_to_evaluate_on_commit = ''' |
27 self.scroll_amount = scroll_amount | 34 window.WebSocket = undefined; |
28 self.delay = delay | 35 window.Worker = undefined; |
29 self.repeat = repeat | 36 window.performance = undefined;''' |
nednguyen
2017/03/30 13:09:46
Does this make any of the page's JS fail? Seems a
ulan
2017/03/30 14:35:09
This part did not change with this CL. At the time
| |
30 | 37 |
31 def RunPageInteractions(self, action_runner): | 38 def RunPageInteractions(self, action_runner): |
32 self._WaitAction(action_runner) | |
33 self._ScrollAction(action_runner, self.scroll_amount, self.delay, | |
34 self.repeat) | |
35 | |
36 def _ScrollAction(self, action_runner, scroll_amount, delay, repeat): | |
37 with action_runner.CreateInteraction('Begin'): | |
38 action_runner.tab.browser.DumpMemory() | |
39 with action_runner.CreateInteraction('Scrolling'): | |
40 action_runner.RepeatableBrowserDrivenScroll( | |
41 y_scroll_distance_ratio=scroll_amount, | |
42 repeat_delay_ms=delay, | |
43 repeat_count=repeat, | |
44 timeout=SCROLL_TIMEOUT_IN_SECONDS) | |
45 with action_runner.CreateInteraction('End'): | |
46 action_runner.tab.browser.DumpMemory() | |
47 | |
48 def _WaitAction(self, action_runner): | |
49 with action_runner.CreateInteraction('Load'): | 39 with action_runner.CreateInteraction('Load'): |
50 action_runner.WaitForJavaScriptCondition( | 40 action_runner.WaitForJavaScriptCondition( |
51 'document.body != null && ' | 41 'document.body != null && ' |
52 'document.body.scrollHeight > window.innerHeight && ' | 42 'document.body.scrollHeight > window.innerHeight && ' |
53 '!document.body.addEventListener("touchstart", function() {})') | 43 '!document.body.addEventListener("touchstart", function() {})') |
54 with action_runner.CreateInteraction('Wait'): | 44 with action_runner.CreateInteraction('Wait'): |
55 action_runner.Wait(TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS) | 45 action_runner.Wait(self.TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS) |
56 with action_runner.CreateInteraction('GC'): | 46 with action_runner.CreateInteraction('GC'): |
57 action_runner.ForceGarbageCollection() | 47 action_runner.ForceGarbageCollection() |
48 with action_runner.CreateInteraction('Begin'): | |
nednguyen
2017/03/30 13:09:46
not in this CL but these interactions are only nee
ulan
2017/03/30 14:35:08
Yep, will do in separete CL.
| |
49 action_runner.tab.browser.DumpMemory() | |
50 with action_runner.CreateInteraction('Scrolling'): | |
51 self._Scroll(action_runner, self.SCROLL_DISTANCE, self.SCROLL_STEP) | |
52 with action_runner.CreateInteraction('End'): | |
53 action_runner.tab.browser.DumpMemory() | |
58 | 54 |
55 def _Scroll(self, action_runner, distance, step_size): | |
nednguyen
2017/03/30 13:09:46
this method seems useful & common enough to be an
ulan
2017/03/30 14:35:09
OK. I would wait until it is needed by another pag
| |
56 """ This function scrolls the webpage by the given scroll distance in | |
57 multiple steps, where each step (except the last one) has the given size. | |
59 | 58 |
60 class InfiniteScrollPageSet(story.StorySet): | 59 If scrolling gets stuck, the functions retries scrolling MAX_SCROLL_RETRIES |
61 """ Top pages that can be scrolled for many pages. """ | 60 times waiting TIME_BEFORE_SCROLL_RETRY_IN_SECONDS seconds between retries. |
61 """ | |
62 remaining = distance - action_runner.EvaluateJavaScript('window.scrollY') | |
63 retry_count = 0 | |
64 # Scroll until the window.scrollY is within 1 pixel of the target distance. | |
65 while remaining > 1: | |
66 action_runner.ScrollPage(distance=min(remaining, step_size) + 1) | |
67 new_remaining = (distance - | |
68 action_runner.EvaluateJavaScript('window.scrollY')) | |
69 if remaining == new_remaining: | |
70 # Scrolling is stuck. This can happen if the page is loading | |
71 # resources. Give the page some time and retry scrolling. | |
72 if retry_count == self.MAX_SCROLL_RETRIES: | |
73 raise Exception('Scrolling stuck at %d' % remaining) | |
74 retry_count += 1 | |
75 action_runner.Wait(self.TIME_BEFORE_SCROLL_RETRY_IN_SECONDS) | |
76 else: | |
77 retry_count = 0 | |
78 remaining = new_remaining | |
79 | |
80 class DiscourseDesktopStory(_InfiniteScrollStory): | |
81 NAME = 'discourse' | |
82 URL = ('https://meta.discourse.org/t/the-official-discourse-tags-plugin' + | |
83 '-discourse-tagging/26482') | |
84 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
85 | |
86 class DiscourseMobileStory(_InfiniteScrollStory): | |
87 NAME = 'discourse' | |
88 URL = ('https://meta.discourse.org/t/the-official-discourse-tags-plugin' + | |
89 '-discourse-tagging/26482') | |
90 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
91 SCROLL_DISTANCE = 15000 | |
92 | |
93 class FacebookDesktopStory(_InfiniteScrollStory): | |
94 NAME = 'facebook' | |
95 URL = 'https://www.facebook.com/shakira' | |
96 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
97 | |
98 class FacebookMobileStory(_InfiniteScrollStory): | |
99 NAME = 'facebook' | |
100 URL = 'https://m.facebook.com/shakira' | |
101 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
102 def RunNavigateSteps(self, action_runner): | |
103 facebook_login.LoginWithMobileSite( | |
104 action_runner, 'facebook3', self.credentials_path) | |
105 super(FacebookMobileStory, self).RunNavigateSteps(action_runner) | |
106 | |
107 class FlickrDesktopStory(_InfiniteScrollStory): | |
108 NAME = 'flickr' | |
109 URL = 'https://www.flickr.com/explore' | |
110 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
111 | |
112 class FlickrMobileStory(_InfiniteScrollStory): | |
113 NAME = 'flickr' | |
114 URL = 'https://www.flickr.com/explore' | |
115 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
116 SCROLL_DISTANCE = 10000 | |
117 | |
118 class PinterestMobileStory(_InfiniteScrollStory): | |
119 NAME = 'pinterest' | |
120 URL = 'https://www.pinterest.com/all' | |
121 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
122 | |
123 class TumblrStory(_InfiniteScrollStory): | |
124 NAME = 'tumblr' | |
125 URL = 'http://techcrunch.tumblr.com/' | |
126 | |
127 class TwitterDesktopStory(_InfiniteScrollStory): | |
128 NAME = 'twitter' | |
129 URL = 'https://twitter.com/taylorswift13' | |
130 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
131 | |
132 class InfiniteScrollStorySet(story.StorySet): | |
133 """ Desktop story set. """ | |
62 def __init__(self): | 134 def __init__(self): |
63 super(InfiniteScrollPageSet, self).__init__( | 135 super(InfiniteScrollStorySet, self).__init__( |
64 archive_data_file='data/infinite_scroll.json', | 136 archive_data_file='data/infinite_scroll.json', |
65 cloud_storage_bucket=story.PARTNER_BUCKET) | 137 cloud_storage_bucket=story.PARTNER_BUCKET) |
66 # The scroll distance is chosen such that the page can be scrolled | 138 for story_class in _FindInfiniteScrollStoryClasses(platforms.DESKTOP): |
67 # continuously through the test without hitting the end of the page. | 139 self.AddStory(story_class(self)) |
68 SCROLL_FAR = 60 | 140 |
69 SCROLL_PAGE = 1 | 141 class MobileInfiniteScrollStorySet(story.StorySet): |
70 pages = [ | 142 """ Mobile story set. """ |
71 ('https://www.facebook.com/shakira', 'facebook', SCROLL_FAR, 0, 0), | 143 def __init__(self): |
72 ('https://twitter.com/taylorswift13', 'twitter', SCROLL_PAGE, 10, 30), | 144 super(MobileInfiniteScrollStorySet, self).__init__( |
73 ('http://techcrunch.tumblr.com/', 'tumblr', SCROLL_FAR, 0, 0), | 145 archive_data_file='data/mobile_infinite_scroll.json', |
74 ('https://www.flickr.com/explore', 'flickr', SCROLL_FAR, 0, 0), | 146 cloud_storage_bucket=story.PARTNER_BUCKET) |
75 ('https://meta.discourse.org/t/the-official-discourse-tags-plugin-discou rse-tagging/26482', | 147 for story_class in _FindInfiniteScrollStoryClasses(platforms.MOBILE): |
76 'discourse', SCROLL_PAGE, 10, 30) | 148 self.AddStory(story_class(self)) |
77 ] | 149 |
78 for (url, name, scroll_amount, delay, repeat) in pages: | 150 def _FindInfiniteScrollStoryClasses(platform): |
79 self.AddStory( | 151 # Sort the classes by their names so that their order is stable and |
80 InfiniteScrollPage(url, self, name, scroll_amount, delay, repeat)) | 152 # deterministic. |
153 for unused_cls_name, cls in sorted(discover.DiscoverClassesInModule( | |
154 module=sys.modules[__name__], base_class=_InfiniteScrollStory, | |
155 index_by_class_name=True).iteritems()): | |
156 if platform in cls.SUPPORTED_PLATFORMS: | |
157 yield cls | |
OLD | NEW |