OLD | NEW |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 | 4 |
5 from page_sets.system_health import platforms | 5 from page_sets.system_health import platforms |
| 6 from page_sets.system_health import story_tags |
6 from page_sets.system_health import system_health_story | 7 from page_sets.system_health import system_health_story |
| 8 from page_sets.system_health import browsing_stories |
7 | 9 |
8 from page_sets.login_helpers import google_login | 10 from page_sets.login_helpers import google_login |
9 from page_sets.login_helpers import pandora_login | 11 from page_sets.login_helpers import pandora_login |
| 12 from page_sets.login_helpers import pinterest_login |
10 | 13 |
11 from telemetry import benchmark | 14 from telemetry import benchmark |
12 from telemetry import decorators | 15 from telemetry import decorators |
13 | 16 |
14 | 17 |
15 class _MediaStory(system_health_story.SystemHealthStory): | 18 ################################################################################ |
| 19 # Audio and Video stories. |
| 20 ################################################################################ |
| 21 |
| 22 |
| 23 class _PlayMediaStory(system_health_story.SystemHealthStory): |
16 """Abstract base class for media System Health user stories.""" | 24 """Abstract base class for media System Health user stories.""" |
17 | 25 |
18 ABSTRACT_STORY = True | 26 ABSTRACT_STORY = True |
19 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | 27 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
20 PLAY_DURATION = 20 | 28 PLAY_DURATION = 20 |
21 PLAY_SELECTOR = NotImplemented | 29 PLAY_SELECTOR = NotImplemented |
22 STOP_SELECTOR = NotImplemented | 30 STOP_SELECTOR = NotImplemented |
23 TIME_SELECTOR = NotImplemented | 31 TIME_SELECTOR = NotImplemented |
24 | 32 |
25 def RunPageInteractions(self, action_runner): | 33 def RunPageInteractions(self, action_runner): |
(...skipping 18 matching lines...) Expand all Loading... |
44 action_runner.Wait( | 52 action_runner.Wait( |
45 self.PLAY_DURATION - self._GetTimeInSeconds(action_runner)) | 53 self.PLAY_DURATION - self._GetTimeInSeconds(action_runner)) |
46 | 54 |
47 def _GetTimeInSeconds(self, action_runner): | 55 def _GetTimeInSeconds(self, action_runner): |
48 minutes, seconds = action_runner.EvaluateJavaScript( | 56 minutes, seconds = action_runner.EvaluateJavaScript( |
49 'document.querySelector({{ selector }}).textContent', | 57 'document.querySelector({{ selector }}).textContent', |
50 selector=self.TIME_SELECTOR).split(':') | 58 selector=self.TIME_SELECTOR).split(':') |
51 return int(minutes * 60 + seconds) | 59 return int(minutes * 60 + seconds) |
52 | 60 |
53 | 61 |
54 ################################################################################ | 62 # TODO(ssid): Rename the play stories to browse stories crbug.com/708300. |
55 # Audio stories. | |
56 ################################################################################ | |
57 | |
58 | |
59 @benchmark.Disabled('all') # crbug.com/649392 | 63 @benchmark.Disabled('all') # crbug.com/649392 |
60 class GooglePlayMusicDesktopStory(_MediaStory): | 64 class GooglePlayMusicDesktopStory(_PlayMediaStory): |
61 NAME = 'play:media:google_play_music' | 65 NAME = 'play:media:google_play_music' |
62 URL = 'https://music.google.com' | 66 URL = 'https://music.google.com' |
63 | 67 |
64 PLAY_SELECTOR = '.x-scope.paper-fab-0' | 68 PLAY_SELECTOR = '.x-scope.paper-fab-0' |
65 STOP_SELECTOR = '.style-scope.sj-play-button' | 69 STOP_SELECTOR = '.style-scope.sj-play-button' |
66 TIME_SELECTOR = '#time-container-current' | 70 TIME_SELECTOR = '#time-container-current' |
67 SEARCH_SELECTOR = '.title.fade-out.tooltip' | 71 SEARCH_SELECTOR = '.title.fade-out.tooltip' |
68 NAVIGATE_SELECTOR = '.description.tooltip.fade-out' | 72 NAVIGATE_SELECTOR = '.description.tooltip.fade-out' |
69 | 73 |
70 def _Login(self, action_runner): | 74 def _Login(self, action_runner): |
71 google_login.LoginGoogleAccount(action_runner, 'googletest', | 75 google_login.LoginGoogleAccount(action_runner, 'googletest', |
72 self.credentials_path) | 76 self.credentials_path) |
73 | 77 |
74 def _NavigateToMedia(self, action_runner): | 78 def _NavigateToMedia(self, action_runner): |
75 # Clicks on Today's top hits. | 79 # Clicks on Today's top hits. |
76 action_runner.Wait(1) # Add 1 second wait to make the browsing realistic. | 80 action_runner.Wait(1) # Add 1 second wait to make the browsing realistic. |
77 self._WaitForAndClickElementBySelector(action_runner, self.SEARCH_SELECTOR) | 81 self._WaitForAndClickElementBySelector(action_runner, self.SEARCH_SELECTOR) |
78 # Clicks on playlist. | 82 # Clicks on playlist. |
79 action_runner.Wait(1) # Add 1 second wait to make the browsing realistic. | 83 action_runner.Wait(1) # Add 1 second wait to make the browsing realistic. |
80 self._WaitForAndClickElementBySelector(action_runner, | 84 self._WaitForAndClickElementBySelector(action_runner, |
81 self.NAVIGATE_SELECTOR) | 85 self.NAVIGATE_SELECTOR) |
82 | 86 |
83 | 87 |
84 @benchmark.Disabled('win') # crbug.com/649392 | 88 @benchmark.Disabled('win') # crbug.com/649392 |
85 class SoundCloudDesktopStory(_MediaStory): | 89 class SoundCloudDesktopStory(_PlayMediaStory): |
86 NAME = 'play:media:soundcloud' | 90 NAME = 'play:media:soundcloud' |
87 URL = 'https://soundcloud.com' | 91 URL = 'https://soundcloud.com' |
88 | 92 |
89 PLAY_SELECTOR = '.sc-button-play.playButton.sc-button.sc-button-xlarge' | 93 PLAY_SELECTOR = '.sc-button-play.playButton.sc-button.sc-button-xlarge' |
90 STOP_SELECTOR = '.playControl.playControls__icon.sc-ir.playing' | 94 STOP_SELECTOR = '.playControl.playControls__icon.sc-ir.playing' |
91 TIME_SELECTOR = '.playbackTimeline__timePassed>span[aria-hidden=true]' | 95 TIME_SELECTOR = '.playbackTimeline__timePassed>span[aria-hidden=true]' |
92 SEARCH_SELECTOR = '.headerSearch' | 96 SEARCH_SELECTOR = '.headerSearch' |
93 SEARCH_QUERY = 'SSmooth Jazz' # First S for some reason gets ommited. | 97 SEARCH_QUERY = 'SSmooth Jazz' # First S for some reason gets ommited. |
94 | 98 |
95 def _NavigateToMedia(self, action_runner): | 99 def _NavigateToMedia(self, action_runner): |
96 self._WaitForAndClickElementBySelector(action_runner, self.SEARCH_SELECTOR) | 100 self._WaitForAndClickElementBySelector(action_runner, self.SEARCH_SELECTOR) |
97 action_runner.Wait(1) # Add 1 second wait to make the browsing realistic. | 101 action_runner.Wait(1) # Add 1 second wait to make the browsing realistic. |
98 action_runner.EnterText(self.SEARCH_QUERY) | 102 action_runner.EnterText(self.SEARCH_QUERY) |
99 action_runner.PressKey('Return') | 103 action_runner.PressKey('Return') |
100 | 104 |
101 | 105 |
102 @decorators.Disabled('all') # crbug.com/649392 | 106 @decorators.Disabled('all') # crbug.com/649392 |
103 class PandoraDesktopStory(_MediaStory): | 107 class PandoraDesktopStory(_PlayMediaStory): |
104 NAME = 'play:media:pandora' | 108 NAME = 'play:media:pandora' |
105 URL = 'https://pandora.com' | 109 URL = 'https://pandora.com' |
106 | 110 |
107 PLAY_SELECTOR = None | 111 PLAY_SELECTOR = None |
108 STOP_SELECTOR = '.pauseButton' | 112 STOP_SELECTOR = '.pauseButton' |
109 TIME_SELECTOR = '.elapsedTime' | 113 TIME_SELECTOR = '.elapsedTime' |
110 SEARCH_SELECTOR = '.searchInput' | 114 SEARCH_SELECTOR = '.searchInput' |
111 | 115 |
112 def _Login(self, action_runner): | 116 def _Login(self, action_runner): |
113 pandora_login.LoginAccount(action_runner, 'pandora', self.credentials_path) | 117 pandora_login.LoginAccount(action_runner, 'pandora', self.credentials_path) |
114 | 118 |
115 def _NavigateToMedia(self, action_runner): | 119 def _NavigateToMedia(self, action_runner): |
116 pass # Audio autoplays on Pandora, no need to search. | 120 pass # Audio autoplays on Pandora, no need to search. |
| 121 |
| 122 |
| 123 class YoutubeMobileStory(_PlayMediaStory): |
| 124 NAME = 'play:media:youtube' |
| 125 URL = 'https://m.youtube.in/watch?v=OnhXkCPMeMc' |
| 126 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 127 TAGS = [story_tags.EMERGING_MARKET] |
| 128 |
| 129 PLAYER_FUNCTION = 'document.getElementById("player")' |
| 130 STOP_FUNCTION = 'document.getElementsByTagName("video")[0].pause()' |
| 131 TIME_FUNCTION = 'document.getElementsByTagName("video")[0].currentTime' |
| 132 |
| 133 def RunPageInteractions(self, action_runner): |
| 134 app_ui = action_runner.tab.browser.app_ui |
| 135 action_runner.WaitForElement(element_function=self.PLAYER_FUNCTION) |
| 136 |
| 137 # Simulate user click in system ui since youtube play can be initialied only |
| 138 # by user gesture. |
| 139 renderer_view_id = 'compositor_view_holder' |
| 140 app_ui.WaitForUiNode(resource_id=renderer_view_id) |
| 141 renderer_view = app_ui.GetUiNode(resource_id=renderer_view_id) |
| 142 # Click on the top half of the renderer view to start video. |
| 143 shifted_center = 0.5 * ( |
| 144 renderer_view.bounds.center + renderer_view.bounds.top_left) |
| 145 renderer_view.Tap(point=shifted_center) |
| 146 |
| 147 self._WaitForPlayTime(action_runner) |
| 148 action_runner.EvaluateJavaScript(self.STOP_FUNCTION) |
| 149 self._Measure(action_runner) |
| 150 |
| 151 |
| 152 def _GetTimeInSeconds(self, action_runner): |
| 153 return int(action_runner.EvaluateJavaScript(self.TIME_FUNCTION)) |
| 154 |
| 155 def _NavigateToMedia(self, action_runner): |
| 156 pass # Users usually open youtube links directly, skip searching. |
| 157 |
| 158 |
| 159 ################################################################################ |
| 160 # Photos browsing stories. |
| 161 ################################################################################ |
| 162 |
| 163 |
| 164 class _PhotoBrowsingStory(browsing_stories.BrowsingStory): |
| 165 """Abstract base class for media user stories |
| 166 |
| 167 A media story imitates browsing a website with photo or video content: |
| 168 1. Load a page showing a media item |
| 169 2. Click on the next link to go to the next media item |
| 170 3. etc. |
| 171 """ |
| 172 |
| 173 ABSTRACT_STORY = True |
| 174 ITEM_VIEW_TIME_IN_SECONDS = 3 |
| 175 ITEMS_TO_VISIT = 15 |
| 176 ITEM_SELECTOR_INDEX = 0 |
| 177 INCREMENT_INDEX_AFTER_EACH_ITEM = False |
| 178 |
| 179 def _DidLoadDocument(self, action_runner): |
| 180 index = self.ITEM_SELECTOR_INDEX |
| 181 for _ in xrange(self.ITEMS_TO_VISIT): |
| 182 self._NavigateToItem(action_runner, index) |
| 183 self._ViewMediaItem(action_runner, index) |
| 184 if self.INCREMENT_INDEX_AFTER_EACH_ITEM: |
| 185 index += 1 |
| 186 |
| 187 |
| 188 def _ViewMediaItem(self, action_runner, index): |
| 189 del index # Unused. |
| 190 action_runner.tab.WaitForDocumentReadyStateToBeComplete() |
| 191 action_runner.Wait(self.ITEM_VIEW_TIME_IN_SECONDS) |
| 192 |
| 193 |
| 194 class ImgurMobileStory(_PhotoBrowsingStory): |
| 195 NAME = 'browse:media:imgur' |
| 196 URL = 'http://imgur.com/gallery/5UlBN' |
| 197 ITEM_SELECTOR = '.Navbar-customAction' |
| 198 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 199 IS_SINGLE_PAGE_APP = True |
| 200 TAGS = [story_tags.EMERGING_MARKET] |
| 201 |
| 202 |
| 203 # crbug.com/704197 for win and mac |
| 204 @decorators.Disabled('win', 'mac') |
| 205 class ImgurDesktopStory(_PhotoBrowsingStory): |
| 206 NAME = 'browse:media:imgur' |
| 207 URL = 'http://imgur.com/gallery/5UlBN' |
| 208 ITEM_SELECTOR = '.navNext' |
| 209 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 210 IS_SINGLE_PAGE_APP = True |
| 211 |
| 212 |
| 213 # TODO(ssid): Remove this story since we have play youtube story |
| 214 # crbug.com/708300. |
| 215 class YouTubeMobileStory(_PhotoBrowsingStory): |
| 216 NAME = 'browse:media:youtube' |
| 217 URL = 'https://m.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false' |
| 218 ITEM_SELECTOR = '._mhgb > a' |
| 219 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 220 IS_SINGLE_PAGE_APP = True |
| 221 ITEM_SELECTOR_INDEX = 3 |
| 222 TAGS = [story_tags.JAVASCRIPT_HEAVY] |
| 223 |
| 224 |
| 225 class YouTubeDesktopStory(_PhotoBrowsingStory): |
| 226 NAME = 'browse:media:youtube' |
| 227 URL = 'https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false' |
| 228 ITEM_SELECTOR = '.yt-uix-simple-thumb-related' |
| 229 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 230 IS_SINGLE_PAGE_APP = True |
| 231 # A longer view time allows videos to load and play. |
| 232 ITEM_VIEW_TIME_IN_SECONDS = 5 |
| 233 ITEMS_TO_VISIT = 8 |
| 234 ITEM_SELECTOR_INDEX = 3 |
| 235 PLATFORM_SPECIFIC = True |
| 236 TAGS = [story_tags.JAVASCRIPT_HEAVY] |
| 237 |
| 238 |
| 239 class FacebookPhotosMobileStory(_PhotoBrowsingStory): |
| 240 NAME = 'browse:media:facebook_photos' |
| 241 URL = ( |
| 242 'https://m.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/1
0153911739606676/?type=3&source=54&ref=page_internal') |
| 243 ITEM_SELECTOR = '._57-r.touchable' |
| 244 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 245 IS_SINGLE_PAGE_APP = True |
| 246 ITEM_SELECTOR_INDEX = 0 |
| 247 TAGS = [story_tags.EMERGING_MARKET] |
| 248 |
| 249 |
| 250 class FacebookPhotosDesktopStory(_PhotoBrowsingStory): |
| 251 NAME = 'browse:media:facebook_photos' |
| 252 URL = ( |
| 253 'https://www.facebook.com/rihanna/photos/a.207477806675.138795.10092511675
/10153911739606676/?type=3&theater') |
| 254 ITEM_SELECTOR = '.snowliftPager.next' |
| 255 # Recording currently does not work. The page gets stuck in the |
| 256 # theater viewer. |
| 257 SUPPORTED_PLATFORMS = platforms.NO_PLATFORMS |
| 258 IS_SINGLE_PAGE_APP = True |
| 259 |
| 260 |
| 261 class TumblrDesktopStory(_PhotoBrowsingStory): |
| 262 NAME = 'browse:media:tumblr' |
| 263 URL = 'https://tumblr.com/search/gifs' |
| 264 ITEM_SELECTOR = '.photo' |
| 265 IS_SINGLE_PAGE_APP = True |
| 266 ITEMS_TO_VISIT = 8 |
| 267 INCREMENT_INDEX_AFTER_EACH_ITEM = True |
| 268 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 269 |
| 270 def _ViewMediaItem(self, action_runner, index): |
| 271 super(TumblrDesktopStory, self)._ViewMediaItem(action_runner, index) |
| 272 action_runner.MouseClick(selector='#tumblr_lightbox_center_image') |
| 273 action_runner.Wait(1) # To make browsing more realistic. |
| 274 |
| 275 |
| 276 class PinterestDesktopStory(_PhotoBrowsingStory): |
| 277 NAME = 'browse:media:pinterest' |
| 278 URL = 'https://pinterest.com' |
| 279 ITEM_SELECTOR = '.pinImageDim' |
| 280 IS_SINGLE_PAGE_APP = True |
| 281 ITEMS_TO_VISIT = 8 |
| 282 INCREMENT_INDEX_AFTER_EACH_ITEM = True |
| 283 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 284 |
| 285 def _Login(self, action_runner): |
| 286 pinterest_login.LoginDesktopAccount(action_runner, 'googletest', |
| 287 self.credentials_path) |
| 288 |
| 289 def _ViewMediaItem(self, action_runner, index): |
| 290 super(PinterestDesktopStory, self)._ViewMediaItem(action_runner, index) |
| 291 # To imitate real user interaction, we do not want to pin every post. |
| 292 # We will only pin every other post. |
| 293 if index % 2 == 0: |
| 294 # Pin the selection. |
| 295 save_function = ('document.querySelector(' |
| 296 '".Button.Module.ShowModalButton.btn.hasIcon.hasText.' |
| 297 'isBrioFlat.medium.primary.primaryOnHover.repin.' |
| 298 'pinActionBarButton.isBrioFlat.rounded")') |
| 299 action_runner.ClickElement(element_function=save_function) |
| 300 action_runner.Wait(1) # Wait to make navigation realistic. |
| 301 # Select which board to pin to. |
| 302 inner_save_function = 'document.querySelector(".nameAndIcons")' |
| 303 action_runner.WaitForElement(element_function=inner_save_function) |
| 304 action_runner.ClickElement(element_function=inner_save_function) |
| 305 action_runner.Wait(1) # Wait to make navigation realistic. |
| 306 |
| 307 # Close selection. |
| 308 x_element_function = ('document.querySelector(' |
| 309 '".Button.borderless.close.visible")') |
| 310 action_runner.ClickElement(element_function=x_element_function) |
| 311 action_runner.Wait(1) # Wait to make navigation realistic. |
| 312 |
| 313 |
| 314 # Instagram requires navigate back to view next photo So, use |
| 315 # ArticleBrowsingStory. |
| 316 class InstagramMobileStory(browsing_stories.ArticleBrowsingStory): |
| 317 NAME = 'browse:media:instagram' |
| 318 URL = 'https://www.instagram.com/badgalriri/' |
| 319 ITEM_SELECTOR = '[class=\\"_8mlbc _vbtk2 _t5r8b\\"]' |
| 320 ITEMS_TO_VISIT = 8 |
| 321 IS_SINGLE_PAGE_APP = True |
| 322 |
| 323 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 324 TAGS = [story_tags.EMERGING_MARKET] |
OLD | NEW |