Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # encoding: utf-8 | |
| 2 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 3 # 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 |
| 4 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 5 | 4 |
| 6 from page_sets.system_health import platforms | 5 from page_sets.system_health import platforms |
| 7 from page_sets.system_health import story_tags | 6 from page_sets.system_health import story_tags |
| 8 from page_sets.system_health import system_health_story | 7 from page_sets.system_health import system_health_story |
| 9 | 8 |
| 10 from page_sets.login_helpers import pinterest_login | |
| 11 | |
| 12 from telemetry import decorators | 9 from telemetry import decorators |
| 13 from telemetry.util import js_template | |
| 14 | 10 |
| 15 | 11 |
| 16 class _BrowsingStory(system_health_story.SystemHealthStory): | 12 class BrowsingStory(system_health_story.SystemHealthStory): |
| 17 """Abstract base class for browsing stories. | 13 """Abstract base class for browsing stories. |
| 18 | 14 |
| 19 A browsing story visits items on the main page. Subclasses provide | 15 A browsing story visits items on the main page. Subclasses provide |
| 20 CSS selector to identify the items and implement interaction using | 16 CSS selector to identify the items and implement interaction using |
| 21 the helper methods of this class. | 17 the helper methods of this class. |
| 22 """ | 18 """ |
| 23 | 19 |
| 24 IS_SINGLE_PAGE_APP = False | 20 IS_SINGLE_PAGE_APP = False |
| 25 ITEM_SELECTOR = NotImplemented | 21 ITEM_SELECTOR = NotImplemented |
| 26 # Defaults to using the body element if not set. | 22 # Defaults to using the body element if not set. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 44 def _ClickLink(self, action_runner, element_function): | 40 def _ClickLink(self, action_runner, element_function): |
| 45 action_runner.WaitForElement(element_function=element_function) | 41 action_runner.WaitForElement(element_function=element_function) |
| 46 action_runner.ClickElement(element_function=element_function) | 42 action_runner.ClickElement(element_function=element_function) |
| 47 self._WaitForNavigation(action_runner) | 43 self._WaitForNavigation(action_runner) |
| 48 | 44 |
| 49 def _NavigateBack(self, action_runner): | 45 def _NavigateBack(self, action_runner): |
| 50 action_runner.NavigateBack() | 46 action_runner.NavigateBack() |
| 51 self._WaitForNavigation(action_runner) | 47 self._WaitForNavigation(action_runner) |
| 52 | 48 |
| 53 | 49 |
| 54 ############################################################################## | 50 class ArticleBrowsingStory(BrowsingStory): |
| 55 # News browsing stories. | 51 """Abstract base class for user stories browsing news / shopping articles. |
| 56 ############################################################################## | |
| 57 | 52 |
| 58 | 53 An article browsing story imitates browsing a articles: |
| 59 class _NewsBrowsingStory(_BrowsingStory): | |
| 60 """Abstract base class for news user stories. | |
| 61 | |
| 62 A news story imitates browsing a news website: | |
| 63 1. Load the main page. | 54 1. Load the main page. |
| 64 2. Open and scroll the first news item. | 55 2. Open and scroll the first article. |
| 65 3. Go back to the main page and scroll it. | 56 3. Go back to the main page and scroll it. |
| 66 4. Open and scroll the second news item. | 57 4. Open and scroll the second article. |
| 67 5. Go back to the main page and scroll it. | 58 5. Go back to the main page and scroll it. |
| 68 6. etc. | 59 6. etc. |
| 69 """ | 60 """ |
| 70 | 61 |
| 71 ITEM_READ_TIME_IN_SECONDS = 3 | 62 ITEM_READ_TIME_IN_SECONDS = 3 |
| 72 ITEM_SCROLL_REPEAT = 2 | 63 ITEM_SCROLL_REPEAT = 2 |
| 73 ITEMS_TO_VISIT = 4 | 64 ITEMS_TO_VISIT = 4 |
| 74 MAIN_PAGE_SCROLL_REPEAT = 0 | 65 MAIN_PAGE_SCROLL_REPEAT = 0 |
| 75 ABSTRACT_STORY = True | 66 ABSTRACT_STORY = True |
| 76 | 67 |
| 77 def _DidLoadDocument(self, action_runner): | 68 def _DidLoadDocument(self, action_runner): |
| 78 for i in xrange(self.ITEMS_TO_VISIT): | 69 for i in xrange(self.ITEMS_TO_VISIT): |
| 79 self._NavigateToItem(action_runner, i) | 70 self._NavigateToItem(action_runner, i) |
| 80 self._ReadNewsItem(action_runner) | 71 self._ReadNextArticle(action_runner) |
| 81 self._NavigateBack(action_runner) | 72 self._NavigateBack(action_runner) |
| 82 self._ScrollMainPage(action_runner) | 73 self._ScrollMainPage(action_runner) |
| 83 | 74 |
| 84 def _ReadNewsItem(self, action_runner): | 75 def _ReadNextArticle(self, action_runner): |
| 85 action_runner.tab.WaitForDocumentReadyStateToBeComplete() | 76 action_runner.tab.WaitForDocumentReadyStateToBeComplete() |
| 86 action_runner.Wait(self.ITEM_READ_TIME_IN_SECONDS/2.0) | 77 action_runner.Wait(self.ITEM_READ_TIME_IN_SECONDS/2.0) |
| 87 action_runner.RepeatableBrowserDrivenScroll( | 78 action_runner.RepeatableBrowserDrivenScroll( |
| 88 repeat_count=self.ITEM_SCROLL_REPEAT) | 79 repeat_count=self.ITEM_SCROLL_REPEAT) |
| 89 action_runner.Wait(self.ITEM_READ_TIME_IN_SECONDS/2.0) | 80 action_runner.Wait(self.ITEM_READ_TIME_IN_SECONDS/2.0) |
| 90 | 81 |
| 91 def _ScrollMainPage(self, action_runner): | 82 def _ScrollMainPage(self, action_runner): |
| 92 action_runner.tab.WaitForDocumentReadyStateToBeComplete() | 83 action_runner.tab.WaitForDocumentReadyStateToBeComplete() |
| 93 action_runner.RepeatableBrowserDrivenScroll( | 84 action_runner.RepeatableBrowserDrivenScroll( |
| 94 repeat_count=self.MAIN_PAGE_SCROLL_REPEAT) | 85 repeat_count=self.MAIN_PAGE_SCROLL_REPEAT) |
| 95 | 86 |
| 96 | 87 |
| 97 class CnnStory(_NewsBrowsingStory): | 88 ############################################################################## |
| 89 # News browsing stories. | |
| 90 ############################################################################## | |
| 91 | |
| 92 | |
| 93 class CnnStory(ArticleBrowsingStory): | |
| 98 """The second top website in http://www.alexa.com/topsites/category/News""" | 94 """The second top website in http://www.alexa.com/topsites/category/News""" |
| 99 NAME = 'browse:news:cnn' | 95 NAME = 'browse:news:cnn' |
| 100 URL = 'http://edition.cnn.com/' | 96 URL = 'http://edition.cnn.com/' |
| 101 ITEM_SELECTOR = '.cd__content > h3 > a' | 97 ITEM_SELECTOR = '.cd__content > h3 > a' |
| 102 ITEMS_TO_VISIT = 2 | 98 ITEMS_TO_VISIT = 2 |
| 103 TAGS = [story_tags.JAVASCRIPT_HEAVY] | 99 TAGS = [story_tags.JAVASCRIPT_HEAVY] |
| 104 | 100 |
| 105 | 101 |
| 106 class FacebookMobileStory(_NewsBrowsingStory): | 102 class FacebookMobileStory(ArticleBrowsingStory): |
| 107 NAME = 'browse:social:facebook' | 103 NAME = 'browse:social:facebook' |
| 108 URL = 'https://www.facebook.com/rihanna' | 104 URL = 'https://www.facebook.com/rihanna' |
| 109 ITEM_SELECTOR = 'article ._5msj' | 105 ITEM_SELECTOR = 'article ._5msj' |
| 110 # We scroll further than usual so that Facebook fetches enough items | 106 # We scroll further than usual so that Facebook fetches enough items |
| 111 # (crbug.com/631022) | 107 # (crbug.com/631022) |
| 112 MAIN_PAGE_SCROLL_REPEAT = 1 | 108 MAIN_PAGE_SCROLL_REPEAT = 1 |
| 113 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | 109 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 114 | 110 |
| 115 | 111 |
| 116 class FacebookDesktopStory(_NewsBrowsingStory): | 112 class FacebookDesktopStory(ArticleBrowsingStory): |
| 117 NAME = 'browse:social:facebook' | 113 NAME = 'browse:social:facebook' |
| 118 URL = 'https://www.facebook.com/rihanna' | 114 URL = 'https://www.facebook.com/rihanna' |
| 119 ITEM_SELECTOR = '._4-eo' | 115 ITEM_SELECTOR = '._4-eo' |
| 120 IS_SINGLE_PAGE_APP = True | 116 IS_SINGLE_PAGE_APP = True |
| 121 # Web-page-replay does not work for this website: | 117 # Web-page-replay does not work for this website: |
| 122 # https://github.com/chromium/web-page-replay/issues/79. | 118 # https://github.com/chromium/web-page-replay/issues/79. |
| 123 SUPPORTED_PLATFORMS = platforms.NO_PLATFORMS | 119 SUPPORTED_PLATFORMS = platforms.NO_PLATFORMS |
| 124 | 120 |
| 125 | 121 |
| 126 class FlipboardMobileStory(_NewsBrowsingStory): | 122 class FlipboardMobileStory(ArticleBrowsingStory): |
| 127 NAME = 'browse:news:flipboard' | 123 NAME = 'browse:news:flipboard' |
| 128 URL = 'https://flipboard.com/explore' | 124 URL = 'https://flipboard.com/explore' |
| 129 IS_SINGLE_PAGE_APP = True | 125 IS_SINGLE_PAGE_APP = True |
| 130 ITEM_SELECTOR = '.grad-top' | 126 ITEM_SELECTOR = '.grad-top' |
| 131 ITEM_SCROLL_REPEAT = 4 | 127 ITEM_SCROLL_REPEAT = 4 |
| 132 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | 128 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 133 | 129 |
| 134 @classmethod | 130 @classmethod |
| 135 def ShouldDisable(cls, possible_browser): | 131 def ShouldDisable(cls, possible_browser): |
| 136 return possible_browser.platform.IsSvelte() # crbug.com/668097 | 132 return possible_browser.platform.IsSvelte() # crbug.com/668097 |
| 137 | 133 |
| 138 | 134 |
| 139 class FlipboardDesktopStory(_NewsBrowsingStory): | 135 class FlipboardDesktopStory(ArticleBrowsingStory): |
| 140 NAME = 'browse:news:flipboard' | 136 NAME = 'browse:news:flipboard' |
| 141 URL = 'https://flipboard.com/explore' | 137 URL = 'https://flipboard.com/explore' |
| 142 IS_SINGLE_PAGE_APP = True | 138 IS_SINGLE_PAGE_APP = True |
| 143 ITEM_SELECTOR = '.cover-image' | 139 ITEM_SELECTOR = '.cover-image' |
| 144 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | 140 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 145 | 141 |
| 146 | 142 |
| 147 # crbug.com/657665 for win and mac | 143 # crbug.com/657665 for win and mac |
| 148 @decorators.Disabled('win', 'mac') | 144 @decorators.Disabled('win', 'mac') |
| 149 class HackerNewsStory(_NewsBrowsingStory): | 145 class HackerNewsStory(ArticleBrowsingStory): |
| 150 NAME = 'browse:news:hackernews' | 146 NAME = 'browse:news:hackernews' |
| 151 URL = 'https://news.ycombinator.com' | 147 URL = 'https://news.ycombinator.com' |
| 152 ITEM_SELECTOR = '.athing .title > a' | 148 ITEM_SELECTOR = '.athing .title > a' |
| 153 | 149 |
| 154 | 150 |
| 155 class NytimesMobileStory(_NewsBrowsingStory): | 151 class NytimesMobileStory(ArticleBrowsingStory): |
| 156 """The third top website in http://www.alexa.com/topsites/category/News""" | 152 """The third top website in http://www.alexa.com/topsites/category/News""" |
| 157 NAME = 'browse:news:nytimes' | 153 NAME = 'browse:news:nytimes' |
| 158 URL = 'http://mobile.nytimes.com' | 154 URL = 'http://mobile.nytimes.com' |
| 159 ITEM_SELECTOR = '.sfgAsset-link' | 155 ITEM_SELECTOR = '.sfgAsset-link' |
| 160 # Visiting more items causes OOM. | 156 # Visiting more items causes OOM. |
| 161 ITEMS_TO_VISIT = 2 | 157 ITEMS_TO_VISIT = 2 |
| 162 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | 158 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 163 | 159 |
| 164 | 160 |
| 165 class NytimesDesktopStory(_NewsBrowsingStory): | 161 class NytimesDesktopStory(ArticleBrowsingStory): |
| 166 """The third top website in http://www.alexa.com/topsites/category/News""" | 162 """The third top website in http://www.alexa.com/topsites/category/News""" |
| 167 NAME = 'browse:news:nytimes' | 163 NAME = 'browse:news:nytimes' |
| 168 URL = 'http://www.nytimes.com' | 164 URL = 'http://www.nytimes.com' |
| 169 ITEM_SELECTOR = '.story-heading > a' | 165 ITEM_SELECTOR = '.story-heading > a' |
| 170 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | 166 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 171 | 167 |
| 172 | 168 |
| 173 # Desktop qq.com opens a news item in a separate tab, for which the back button | 169 # Desktop qq.com opens a news item in a separate tab, for which the back button |
| 174 # does not work. | 170 # does not work. |
| 175 class QqMobileStory(_NewsBrowsingStory): | 171 class QqMobileStory(ArticleBrowsingStory): |
| 176 NAME = 'browse:news:qq' | 172 NAME = 'browse:news:qq' |
| 177 URL = 'http://news.qq.com' | 173 URL = 'http://news.qq.com' |
| 178 ITEM_SELECTOR = '.list .full a' | 174 ITEM_SELECTOR = '.list .full a' |
| 179 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | 175 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 180 TAGS = [story_tags.INTERNATIONAL] | 176 TAGS = [story_tags.INTERNATIONAL] |
| 181 | 177 |
| 182 | 178 |
| 183 class RedditDesktopStory(_NewsBrowsingStory): | 179 class RedditDesktopStory(ArticleBrowsingStory): |
| 184 """The top website in http://www.alexa.com/topsites/category/News""" | 180 """The top website in http://www.alexa.com/topsites/category/News""" |
| 185 NAME = 'browse:news:reddit' | 181 NAME = 'browse:news:reddit' |
| 186 URL = 'https://www.reddit.com/r/news/top/?sort=top&t=week' | 182 URL = 'https://www.reddit.com/r/news/top/?sort=top&t=week' |
| 187 ITEM_SELECTOR = '.thing .title > a' | 183 ITEM_SELECTOR = '.thing .title > a' |
| 188 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | 184 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 189 | 185 |
| 190 | 186 |
| 191 class RedditMobileStory(_NewsBrowsingStory): | 187 class RedditMobileStory(ArticleBrowsingStory): |
| 192 """The top website in http://www.alexa.com/topsites/category/News""" | 188 """The top website in http://www.alexa.com/topsites/category/News""" |
| 193 NAME = 'browse:news:reddit' | 189 NAME = 'browse:news:reddit' |
| 194 URL = 'https://www.reddit.com/r/news/top/?sort=top&t=week' | 190 URL = 'https://www.reddit.com/r/news/top/?sort=top&t=week' |
| 195 IS_SINGLE_PAGE_APP = True | 191 IS_SINGLE_PAGE_APP = True |
| 196 ITEM_SELECTOR = '.PostHeader__post-title-line' | 192 ITEM_SELECTOR = '.PostHeader__post-title-line' |
| 197 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | 193 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 198 | 194 |
| 199 | 195 |
| 200 class TwitterMobileStory(_NewsBrowsingStory): | 196 class TwitterMobileStory(ArticleBrowsingStory): |
| 201 NAME = 'browse:social:twitter' | 197 NAME = 'browse:social:twitter' |
| 202 URL = 'https://www.twitter.com/nasa' | 198 URL = 'https://www.twitter.com/nasa' |
| 203 ITEM_SELECTOR = '.Tweet-text' | 199 ITEM_SELECTOR = '.Tweet-text' |
| 204 CONTAINER_SELECTOR = '.NavigationSheet' | 200 CONTAINER_SELECTOR = '.NavigationSheet' |
| 205 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | 201 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 206 | 202 |
| 207 | 203 |
| 208 @decorators.Disabled('win') # crbug.com/662971 | 204 @decorators.Disabled('win') # crbug.com/662971 |
| 209 class TwitterDesktopStory(_NewsBrowsingStory): | 205 class TwitterDesktopStory(ArticleBrowsingStory): |
| 210 NAME = 'browse:social:twitter' | 206 NAME = 'browse:social:twitter' |
| 211 URL = 'https://www.twitter.com/nasa' | 207 URL = 'https://www.twitter.com/nasa' |
| 212 IS_SINGLE_PAGE_APP = True | 208 IS_SINGLE_PAGE_APP = True |
| 213 ITEM_SELECTOR = '.tweet-text' | 209 ITEM_SELECTOR = '.tweet-text' |
| 214 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | 210 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
| 215 | 211 |
| 216 | 212 |
| 217 class WashingtonPostMobileStory(_NewsBrowsingStory): | 213 class WashingtonPostMobileStory(ArticleBrowsingStory): |
| 218 """Progressive website""" | 214 """Progressive website""" |
| 219 NAME = 'browse:news:washingtonpost' | 215 NAME = 'browse:news:washingtonpost' |
| 220 URL = 'https://www.washingtonpost.com/pwa' | 216 URL = 'https://www.washingtonpost.com/pwa' |
| 221 IS_SINGLE_PAGE_APP = True | 217 IS_SINGLE_PAGE_APP = True |
| 222 ITEM_SELECTOR = '.hed > a' | 218 ITEM_SELECTOR = '.hed > a' |
| 223 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | 219 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 224 _CLOSE_BUTTON_SELECTOR = '.close' | 220 _CLOSE_BUTTON_SELECTOR = '.close' |
| 225 | 221 |
| 226 def _DidLoadDocument(self, action_runner): | 222 def _DidLoadDocument(self, action_runner): |
| 227 # Close the popup window. On Nexus 9 (and probably other tables) the popup | 223 # Close the popup window. On Nexus 9 (and probably other tables) the popup |
| 228 # window does not have a "Close" button, instead it has only a "Send link | 224 # window does not have a "Close" button, instead it has only a "Send link |
| 229 # to phone" button. So on tablets we run with the popup window open. The | 225 # to phone" button. So on tablets we run with the popup window open. The |
| 230 # popup is transparent, so this is mostly an aesthetical issue. | 226 # popup is transparent, so this is mostly an aesthetical issue. |
| 231 has_button = action_runner.EvaluateJavaScript( | 227 has_button = action_runner.EvaluateJavaScript( |
| 232 '!!document.querySelector({{ selector }})', | 228 '!!document.querySelector({{ selector }})', |
| 233 selector=self._CLOSE_BUTTON_SELECTOR) | 229 selector=self._CLOSE_BUTTON_SELECTOR) |
| 234 if has_button: | 230 if has_button: |
| 235 action_runner.ClickElement(selector=self._CLOSE_BUTTON_SELECTOR) | 231 action_runner.ClickElement(selector=self._CLOSE_BUTTON_SELECTOR) |
| 236 super(WashingtonPostMobileStory, self)._DidLoadDocument(action_runner) | 232 super(WashingtonPostMobileStory, self)._DidLoadDocument(action_runner) |
| 237 | 233 |
| 238 | 234 |
| 239 ############################################################################## | 235 ############################################################################## |
| 240 # Search browsing stories. | 236 # Emerging market browsing stories. |
| 241 ############################################################################## | 237 ############################################################################## |
| 242 | 238 |
| 243 | 239 |
| 244 @decorators.Disabled('win') # crbug.com/673775 | 240 class BrowseFlipKartMobileStory(ArticleBrowsingStory): |
| 245 class GoogleDesktopStory(_NewsBrowsingStory): | 241 NAME = 'browse:shopping:flipkart' |
| 246 """ | 242 URL = 'https://flipkart.com/search?q=Mobile%20phone' |
| 247 A typical google search story: | 243 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 248 _ Start at https://www.google.com/search?q=flower | 244 TAGS = [story_tags.EMERGING_MARKET] |
| 249 _ Click on the wikipedia link & navigate to | |
| 250 https://en.wikipedia.org/wiki/Flower | |
| 251 _ Scroll down the wikipedia page about flower. | |
| 252 _ Back to the search main page. | |
| 253 _ Refine the search query to 'flower delivery'. | |
| 254 _ Scroll down the page. | |
| 255 _ Click the next page result of 'flower delivery'. | |
| 256 _ Scroll the search page. | |
| 257 | 245 |
| 258 """ | 246 ITEM_SELECTOR = '.mEOukM' |
| 259 NAME = 'browse:search:google' | 247 BACK_SELECTOR = '._3NH1qf' |
| 260 URL = 'https://www.google.com/search?q=flower' | 248 ITEMS_TO_VISIT = 4 |
| 261 _SEARCH_BOX_SELECTOR = 'input[aria-label="Search"]' | 249 IS_SINGLE_PAGE_APP = True |
| 262 _SEARCH_PAGE_2_SELECTOR = 'a[aria-label=\'Page 2\']' | |
| 263 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 264 | 250 |
| 265 def _DidLoadDocument(self, action_runner): | 251 def _NavigateBack(self, action_runner): |
| 266 # Click on flower Wikipedia link. | 252 action_runner.ClickElement(selector=self.BACK_SELECTOR) |
| 267 action_runner.Wait(2) | |
| 268 action_runner.ClickElement(text='Flower - Wikipedia') | |
| 269 action_runner.WaitForNavigate() | |
| 270 | |
| 271 # Scroll the flower Wikipedia page, then navigate back. | |
| 272 action_runner.Wait(2) | |
| 273 action_runner.ScrollPage() | |
| 274 action_runner.Wait(2) | |
| 275 action_runner.NavigateBack() | |
| 276 | |
| 277 # Click on the search box. | |
| 278 action_runner.WaitForElement(selector=self._SEARCH_BOX_SELECTOR) | |
| 279 action_runner.ClickElement(selector=self._SEARCH_BOX_SELECTOR) | |
| 280 action_runner.Wait(2) | |
| 281 | |
| 282 # Submit search query. | |
| 283 action_runner.EnterText(' delivery') | |
| 284 action_runner.Wait(0.5) | |
| 285 action_runner.PressKey('Return') | |
| 286 | |
| 287 # Scroll down & click next search result page. | |
| 288 action_runner.Wait(2) | |
| 289 action_runner.ScrollPageToElement(selector=self._SEARCH_PAGE_2_SELECTOR) | |
| 290 action_runner.Wait(2) | |
| 291 action_runner.ClickElement(selector=self._SEARCH_PAGE_2_SELECTOR) | |
| 292 action_runner.Wait(2) | |
| 293 action_runner.ScrollPage() | |
| 294 | 253 |
| 295 | 254 |
| 296 class GoogleIndiaDesktopStory(_NewsBrowsingStory): | 255 class BrowseAmazonMobileStory(ArticleBrowsingStory): |
| 297 """ | 256 NAME = 'browse:shopping:amazon' |
| 298 A typical google search story in India: | 257 URL = 'https://www.amazon.co.in/s/?field-keywords=Mobile' |
| 299 1. Start at https://www.google.co.in/search?q=%E0%A4%AB%E0%A5%82%E0%A4%B2` | 258 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 300 2. Scroll down the page. | 259 TAGS = [story_tags.EMERGING_MARKET] |
| 301 3. Refine the query & click search box, which navigates to | |
| 302 https://www.google.co.in/search?q=%E0%A4%AB%E0%A5%82%E0%A4%B2&rct=j#q=%E0%A4 %AB%E0%A5%82%E0%A4%B2+%E0%A4%B5%E0%A4%BF%E0%A4%A4%E0%A4%B0%E0%A4%A3 | |
| 303 4. Scroll down the page. | |
| 304 5. Click the next page result | |
| 305 6. Scroll the search result page. | |
| 306 | 260 |
| 307 """ | 261 ITEM_SELECTOR = ('[class=\\"a-spacing-none a-link-normal sx-table-product ' |
| 308 NAME = 'browse:search:google_india' | 262 'aw-search-results\\"]') |
|
perezju
2017/04/10 10:13:56
I'm not expert on CSS selectors, but is there a wa
ssid
2017/04/11 03:55:57
Cool. Didn't know this was possible.
| |
| 309 URL = 'https://www.google.co.in/search?q=%E0%A4%AB%E0%A5%82%E0%A4%B2' | 263 ITEMS_TO_VISIT = 4 |
| 310 _SEARCH_BOX_SELECTOR = 'input[aria-label="Search"]' | |
| 311 _SEARCH_BUTTON_SELECTOR = 'button[aria-label="Google Search"]' | |
| 312 _SEARCH_PAGE_2_SELECTOR = 'a[aria-label=\'Page 2\']' | |
| 313 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 314 TAGS = [story_tags.INTERNATIONAL] | |
| 315 | 264 |
| 316 def _DidLoadDocument(self, action_runner): | |
| 317 action_runner.Wait(2) | |
| 318 action_runner.ScrollPage() | |
| 319 action_runner.Wait(2) | |
| 320 | 265 |
| 321 action_runner.ScrollPage(direction='up') | 266 class BrowseLazadaMobileStory(ArticleBrowsingStory): |
| 267 NAME = 'browse:shopping:lazada' | |
| 268 URL = 'https://www.lazada.co.id/catalog/?q=Wrist+watch' | |
| 269 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 270 TAGS = [story_tags.EMERGING_MARKET] | |
| 322 | 271 |
| 323 # Refine search query in the search box. | 272 ITEM_SELECTOR = '.merchandise__link' |
| 324 # TODO(nednguyen): replace this with input text gesture to make it more | 273 ITEMS_TO_VISIT = 1 |
| 325 # realistic. | |
| 326 action_runner.ExecuteJavaScript( | |
| 327 js_template.Render( | |
| 328 'document.querySelector({{ selector }}).value += "वितरण";', | |
| 329 selector=self._SEARCH_BOX_SELECTOR)) | |
| 330 action_runner.Wait(2) | |
| 331 action_runner.ClickElement(selector=self._SEARCH_BUTTON_SELECTOR) | |
| 332 | 274 |
| 333 # Scroll down & click next search result page. | 275 |
| 334 action_runner.Wait(2) | 276 class BrowseTOIMobileStory(ArticleBrowsingStory): |
| 335 action_runner.ScrollPageToElement(selector=self._SEARCH_PAGE_2_SELECTOR) | 277 NAME = 'browse:news:toi' |
| 336 action_runner.Wait(2) | 278 URL = 'http://m.timesofindia.com' |
| 337 action_runner.ClickElement(selector=self._SEARCH_PAGE_2_SELECTOR) | 279 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
| 338 action_runner.Wait(2) | 280 TAGS = [story_tags.EMERGING_MARKET] |
| 339 action_runner.ScrollPage() | 281 |
| 282 ITEMS_TO_VISIT = 4 | |
| 283 ITEM_SELECTOR = '[onerror=\\"this.style.display=\'none\'\\"]' | |
|
perezju
2017/04/10 10:13:56
:( I guess there is no better way to match these i
ssid
2017/04/11 03:55:57
There is this other way. But i thought dummy_img l
| |
| 340 | 284 |
| 341 | 285 |
| 342 ############################################################################## | 286 ############################################################################## |
| 343 # Media browsing stories. | 287 # Maps browsing stories. |
| 344 ############################################################################## | 288 ############################################################################## |
| 345 | 289 |
| 346 | 290 |
| 347 class _MediaBrowsingStory(_BrowsingStory): | 291 class GoogleMapsMobileStory(ArticleBrowsingStory): |
|
perezju
2017/04/10 10:13:56
does this really need to subclass ArticleBrowsingS
ssid
2017/04/11 03:55:57
Sorry fixed.
| |
| 348 """Abstract base class for media user stories | 292 NAME = 'browse:tools:maps' |
| 293 URL = 'https://maps.google.com/' | |
| 294 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 295 TAGS = [story_tags.EMERGING_MARKET] | |
| 349 | 296 |
| 350 A media story imitates browsing a website with photo or video content: | 297 _MAPS_SEARCH_BOX_SELECTOR = '.ml-searchbox-placeholder' |
| 351 1. Load a page showing a media item | 298 _RESTAURANTS_LOADED = '.ml-panes-categorical-list-results' |
| 352 2. Click on the next link to go to the next media item | 299 _SEARCH_NEW_AREA_SELECTOR = '.ml-reissue-search-button-inner' |
| 353 3. etc. | 300 _RESTAURANTS_LINK = '.ml-entity-list-item-info' |
| 354 """ | 301 _DIRECTIONS_LINK = '[class="ml-button ml-inner-button-directions-fab"]' |
| 355 | 302 _DIRECTIONS_LOADED = ('[class="ml-fab-inner ' |
| 356 ABSTRACT_STORY = True | 303 'ml-button ml-button-navigation-fab"]') |
| 357 ITEM_VIEW_TIME_IN_SECONDS = 3 | 304 _MAP_LAYER = '.ml-map' |
| 358 ITEMS_TO_VISIT = 15 | |
| 359 ITEM_SELECTOR_INDEX = 0 | |
| 360 INCREMENT_INDEX_AFTER_EACH_ITEM = False | |
| 361 | 305 |
| 362 def _DidLoadDocument(self, action_runner): | 306 def _DidLoadDocument(self, action_runner): |
| 363 index = self.ITEM_SELECTOR_INDEX | 307 # Submit search query. |
| 364 for _ in xrange(self.ITEMS_TO_VISIT): | 308 self._ClickLink(self._MAPS_SEARCH_BOX_SELECTOR, action_runner) |
| 365 self._NavigateToItem(action_runner, index) | 309 action_runner.EnterText('restaurants near me') |
| 366 self._ViewMediaItem(action_runner, index) | 310 action_runner.PressKey('Return') |
| 367 if self.INCREMENT_INDEX_AFTER_EACH_ITEM: | 311 action_runner.WaitForElement(selector=self._RESTAURANTS_LOADED) |
| 368 index += 1 | 312 action_runner.WaitForNetworkQuiescence() |
| 313 action_runner.Wait(4) # User looking at restaurants | |
| 369 | 314 |
| 315 # Open the restaurant list and select the first. | |
| 316 self._ClickLink(self._RESTAURANTS_LOADED, action_runner) | |
| 317 action_runner.WaitForElement(selector=self._RESTAURANTS_LINK) | |
| 318 action_runner.Wait(3) # User reads about restaurant | |
| 319 self._ClickLink(self._RESTAURANTS_LINK, action_runner) | |
| 320 action_runner.Wait(1) # Reading description | |
| 370 | 321 |
| 371 def _ViewMediaItem(self, action_runner, index): | 322 # Open directions to the restaurant from Google. |
| 372 del index # Unused. | 323 self._ClickLink(self._DIRECTIONS_LINK, action_runner) |
| 373 action_runner.tab.WaitForDocumentReadyStateToBeComplete() | 324 action_runner.Wait(0.5) |
| 374 action_runner.Wait(self.ITEM_VIEW_TIME_IN_SECONDS) | 325 action_runner.EnterText('Google Mountain View') |
| 326 action_runner.PressKey('Return') | |
| 327 action_runner.WaitForElement(selector=self._DIRECTIONS_LOADED) | |
| 328 action_runner.PinchElement(selector=self._MAP_LAYER) | |
| 329 action_runner.WaitForNetworkQuiescence() | |
| 330 action_runner.Wait(2) # Seeing direction | |
| 375 | 331 |
| 376 | 332 def _ClickLink(self, selector, action_runner): |
| 377 class ImgurMobileStory(_MediaBrowsingStory): | 333 action_runner.WaitForElement(selector=selector) |
| 378 NAME = 'browse:media:imgur' | 334 action_runner.ClickElement(selector=selector) |
| 379 URL = 'http://imgur.com/gallery/5UlBN' | |
| 380 ITEM_SELECTOR = '.Navbar-customAction' | |
| 381 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 382 IS_SINGLE_PAGE_APP = True | |
| 383 | |
| 384 | |
| 385 # crbug.com/704197 for win and mac | |
| 386 @decorators.Disabled('win', 'mac') | |
| 387 class ImgurDesktopStory(_MediaBrowsingStory): | |
| 388 NAME = 'browse:media:imgur' | |
| 389 URL = 'http://imgur.com/gallery/5UlBN' | |
| 390 ITEM_SELECTOR = '.navNext' | |
| 391 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 392 IS_SINGLE_PAGE_APP = True | |
| 393 | |
| 394 | |
| 395 class YouTubeMobileStory(_MediaBrowsingStory): | |
| 396 NAME = 'browse:media:youtube' | |
| 397 URL = 'https://m.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false' | |
| 398 ITEM_SELECTOR = '._mhgb > a' | |
| 399 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 400 IS_SINGLE_PAGE_APP = True | |
| 401 ITEM_SELECTOR_INDEX = 3 | |
| 402 TAGS = [story_tags.JAVASCRIPT_HEAVY] | |
| 403 | |
| 404 | |
| 405 class YouTubeDesktopStory(_MediaBrowsingStory): | |
| 406 NAME = 'browse:media:youtube' | |
| 407 URL = 'https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false' | |
| 408 ITEM_SELECTOR = '.yt-uix-simple-thumb-related' | |
| 409 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 410 IS_SINGLE_PAGE_APP = True | |
| 411 # A longer view time allows videos to load and play. | |
| 412 ITEM_VIEW_TIME_IN_SECONDS = 5 | |
| 413 ITEMS_TO_VISIT = 8 | |
| 414 ITEM_SELECTOR_INDEX = 3 | |
| 415 PLATFORM_SPECIFIC = True | |
| 416 TAGS = [story_tags.JAVASCRIPT_HEAVY] | |
| 417 | |
| 418 | |
| 419 class FacebookPhotosMobileStory(_MediaBrowsingStory): | |
| 420 NAME = 'browse:media:facebook_photos' | |
| 421 URL = ( | |
| 422 'https://m.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/1 0153911739606676/?type=3&source=54&ref=page_internal') | |
| 423 ITEM_SELECTOR = '._57-r.touchable' | |
| 424 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 425 IS_SINGLE_PAGE_APP = True | |
| 426 ITEM_SELECTOR_INDEX = 0 | |
| 427 | |
| 428 | |
| 429 class FacebookPhotosDesktopStory(_MediaBrowsingStory): | |
| 430 NAME = 'browse:media:facebook_photos' | |
| 431 URL = ( | |
| 432 'https://www.facebook.com/rihanna/photos/a.207477806675.138795.10092511675 /10153911739606676/?type=3&theater') | |
| 433 ITEM_SELECTOR = '.snowliftPager.next' | |
| 434 # Recording currently does not work. The page gets stuck in the | |
| 435 # theater viewer. | |
| 436 SUPPORTED_PLATFORMS = platforms.NO_PLATFORMS | |
| 437 IS_SINGLE_PAGE_APP = True | |
| 438 | |
| 439 | |
| 440 class TumblrDesktopStory(_MediaBrowsingStory): | |
| 441 NAME = 'browse:media:tumblr' | |
| 442 URL = 'https://tumblr.com/search/gifs' | |
| 443 ITEM_SELECTOR = '.photo' | |
| 444 IS_SINGLE_PAGE_APP = True | |
| 445 ITEMS_TO_VISIT = 8 | |
| 446 INCREMENT_INDEX_AFTER_EACH_ITEM = True | |
| 447 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 448 | |
| 449 def _ViewMediaItem(self, action_runner, index): | |
| 450 super(TumblrDesktopStory, self)._ViewMediaItem(action_runner, index) | |
| 451 action_runner.MouseClick(selector='#tumblr_lightbox_center_image') | |
| 452 action_runner.Wait(1) # To make browsing more realistic. | |
| 453 | |
| 454 class PinterestDesktopStory(_MediaBrowsingStory): | |
| 455 NAME = 'browse:media:pinterest' | |
| 456 URL = 'https://pinterest.com' | |
| 457 ITEM_SELECTOR = '.pinImageDim' | |
| 458 IS_SINGLE_PAGE_APP = True | |
| 459 ITEMS_TO_VISIT = 8 | |
| 460 INCREMENT_INDEX_AFTER_EACH_ITEM = True | |
| 461 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 462 | |
| 463 def _Login(self, action_runner): | |
| 464 pinterest_login.LoginDesktopAccount(action_runner, 'googletest', | |
| 465 self.credentials_path) | |
| 466 | |
| 467 def _ViewMediaItem(self, action_runner, index): | |
| 468 super(PinterestDesktopStory, self)._ViewMediaItem(action_runner, index) | |
| 469 # To imitate real user interaction, we do not want to pin every post. | |
| 470 # We will only pin every other post. | |
| 471 if index % 2 == 0: | |
| 472 # Pin the selection. | |
| 473 save_function = ('document.querySelector(' | |
| 474 '".Button.Module.ShowModalButton.btn.hasIcon.hasText.' | |
| 475 'isBrioFlat.medium.primary.primaryOnHover.repin.' | |
| 476 'pinActionBarButton.isBrioFlat.rounded")') | |
| 477 action_runner.ClickElement(element_function=save_function) | |
| 478 action_runner.Wait(1) # Wait to make navigation realistic. | |
| 479 # Select which board to pin to. | |
| 480 inner_save_function = 'document.querySelector(".nameAndIcons")' | |
| 481 action_runner.WaitForElement(element_function=inner_save_function) | |
| 482 action_runner.ClickElement(element_function=inner_save_function) | |
| 483 action_runner.Wait(1) # Wait to make navigation realistic. | |
| 484 | |
| 485 # Close selection. | |
| 486 x_element_function = ('document.querySelector(' | |
| 487 '".Button.borderless.close.visible")') | |
| 488 action_runner.ClickElement(element_function=x_element_function) | |
| 489 action_runner.Wait(1) # Wait to make navigation realistic. | |
| OLD | NEW |