OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 import copy | |
7 import os | |
8 | |
9 import pyauto_functional # Must be imported before pyauto | |
10 import pyauto | |
11 import test_utils | |
12 | |
13 | |
14 class NTPTest(pyauto.PyUITest): | |
15 """Test of the NTP.""" | |
16 | |
17 # Default apps are registered in ProfileImpl::RegisterComponentExtensions(). | |
18 _EXPECTED_DEFAULT_APPS = [ | |
19 {u'title': u'Chrome Web Store'}, | |
20 ] | |
21 if pyauto.PyUITest.IsChromeOS(): | |
22 _EXPECTED_DEFAULT_APPS.append({u'title': u'Files'}) | |
23 _EXPECTED_DEFAULT_APPS.append({u'title': u'Chrome'}) | |
24 else: | |
25 _EXPECTED_DEFAULT_APPS.append({u'title': u'Cloud Print'}) | |
26 | |
27 # Default menu and thumbnail mode preferences are set in | |
28 # ShownSectionsHandler::RegisterUserPrefs. | |
29 if pyauto.PyUITest.IsChromeOS(): | |
30 _EXPECTED_DEFAULT_THUMB_INFO = { | |
31 u'apps': True, | |
32 u'most_visited': False | |
33 } | |
34 _EXPECTED_DEFAULT_MENU_INFO = { | |
35 u'apps': False, | |
36 u'most_visited': True, | |
37 u'recently_closed': True | |
38 } | |
39 else: | |
40 _EXPECTED_DEFAULT_THUMB_INFO = { | |
41 u'apps': False, | |
42 u'most_visited': True | |
43 } | |
44 _EXPECTED_DEFAULT_MENU_INFO = { | |
45 u'apps': False, | |
46 u'most_visited': False, | |
47 u'recently_closed': False | |
48 } | |
49 | |
50 def Debug(self): | |
51 """Test method for experimentation. | |
52 | |
53 This method is not run automatically. | |
54 """ | |
55 while True: | |
56 raw_input('Interact with the browser and hit <enter> to dump NTP info...') | |
57 print '*' * 20 | |
58 self.pprint(self._GetNTPInfo()) | |
59 | |
60 def __init__(self, methodName='runTest'): | |
61 super(NTPTest, self).__init__(methodName) | |
62 | |
63 # Create some dummy file urls we can use in the tests. | |
64 filenames = ['title1.html', 'title2.html'] | |
65 titles = [u'', u'Title Of Awesomeness'] | |
66 urls = map(lambda name: self.GetFileURLForDataPath(name), filenames) | |
67 self.PAGES = map(lambda url, title: {'url': url, 'title': title}, | |
68 urls, titles) | |
69 | |
70 def _NTPContainsThumbnail(self, check_thumbnail): | |
71 """Returns whether the NTP's Most Visited section contains the given | |
72 thumbnail.""" | |
73 for thumbnail in self.GetNTPThumbnails(): | |
74 if check_thumbnail['url'] == thumbnail['url']: | |
75 return True | |
76 return False | |
77 | |
78 def testFreshProfile(self): | |
79 """Tests that the NTP with a fresh profile is correct""" | |
80 thumbnails = self.GetNTPThumbnails() | |
81 default_sites = self.GetNTPDefaultSites() | |
82 self.assertEqual(len(default_sites), len(thumbnails)) | |
83 for thumbnail, default_site in zip(thumbnails, default_sites): | |
84 self.assertEqual(thumbnail['url'], default_site) | |
85 self.assertEqual(0, len(self.GetNTPRecentlyClosed())) | |
86 | |
87 def testRemoveDefaultThumbnails(self): | |
88 """Tests that the default thumbnails can be removed""" | |
89 self.RemoveNTPDefaultThumbnails() | |
90 self.assertFalse(self.GetNTPThumbnails()) | |
91 self.RestoreAllNTPThumbnails() | |
92 self.assertEqual(len(self.GetNTPDefaultSites()), | |
93 len(self.GetNTPThumbnails())) | |
94 self.RemoveNTPDefaultThumbnails() | |
95 self.assertFalse(self.GetNTPThumbnails()) | |
96 | |
97 def testOneMostVisitedSite(self): | |
98 """Tests that a site is added to the most visited sites""" | |
99 self.RemoveNTPDefaultThumbnails() | |
100 self.NavigateToURL(self.PAGES[1]['url']) | |
101 thumbnail = self.GetNTPThumbnails()[0] | |
102 self.assertEqual(self.PAGES[1]['url'], thumbnail['url']) | |
103 self.assertEqual(self.PAGES[1]['title'], thumbnail['title']) | |
104 | |
105 def testRemoveThumbnail(self): | |
106 """Tests removing a thumbnail works""" | |
107 self.RemoveNTPDefaultThumbnails() | |
108 for page in self.PAGES: | |
109 self.AppendTab(pyauto.GURL(page['url'])) | |
110 | |
111 thumbnails = self.GetNTPThumbnails() | |
112 for thumbnail in thumbnails: | |
113 self.assertEquals(thumbnail, self.GetNTPThumbnails()[0]) | |
114 self.RemoveNTPThumbnail(thumbnail) | |
115 self.assertFalse(self._NTPContainsThumbnail(thumbnail)) | |
116 self.assertFalse(self.GetNTPThumbnails()) | |
117 | |
118 def testIncognitoNotAppearInMostVisited(self): | |
119 """Tests that visiting a page in incognito mode does cause it to appear in | |
120 the Most Visited section""" | |
121 self.RemoveNTPDefaultThumbnails() | |
122 self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) | |
123 self.NavigateToURL(self.PAGES[0]['url'], 1, 0) | |
124 self.assertFalse(self.GetNTPThumbnails()) | |
125 | |
126 def testDifferentProfileNotAppearInMostVisited(self): | |
127 """Tests that visiting a page in one profile does not cause it to appear in | |
128 the Most Visited section of another.""" | |
129 self.RemoveNTPDefaultThumbnails() | |
130 self.OpenNewBrowserWindowWithNewProfile() | |
131 self.NavigateToURL(self.PAGES[0]['url'], 1, 0) | |
132 self.assertFalse(self.GetNTPThumbnails()) | |
133 | |
134 def testThumbnailPersistence(self): | |
135 """Tests that thumbnails persist across Chrome restarts""" | |
136 self.RemoveNTPDefaultThumbnails() | |
137 for page in self.PAGES: | |
138 self.AppendTab(pyauto.GURL(page['url'])) | |
139 thumbnails = self.GetNTPThumbnails() | |
140 self.RestartBrowser(clear_profile=False) | |
141 self.assertEqual(thumbnails, self.GetNTPThumbnails()) | |
142 | |
143 def testRestoreAllRemovedThumbnails(self): | |
144 """Tests restoring all removed thumbnails""" | |
145 for page in self.PAGES: | |
146 self.AppendTab(pyauto.GURL(page['url'])) | |
147 | |
148 thumbnails = self.GetNTPThumbnails() | |
149 for thumbnail in thumbnails: | |
150 self.RemoveNTPThumbnail(thumbnail) | |
151 | |
152 self.RestoreAllNTPThumbnails() | |
153 self.assertEquals(thumbnails, self.GetNTPThumbnails()) | |
154 | |
155 def testThumbnailRanking(self): | |
156 """Tests that the thumbnails are ordered according to visit count""" | |
157 self.RemoveNTPDefaultThumbnails() | |
158 for page in self.PAGES: | |
159 self.AppendTab(pyauto.GURL(page['url'])) | |
160 thumbnails = self.GetNTPThumbnails() | |
161 self.assertEqual(self.PAGES[0]['url'], self.GetNTPThumbnails()[0]['url']) | |
162 self.AppendTab(pyauto.GURL(self.PAGES[1]['url'])) | |
163 self.assertEqual(self.PAGES[1]['url'], self.GetNTPThumbnails()[0]['url']) | |
164 self.AppendTab(pyauto.GURL(self.PAGES[0]['url'])) | |
165 self.AppendTab(pyauto.GURL(self.PAGES[0]['url'])) | |
166 self.assertEqual(self.PAGES[0]['url'], self.GetNTPThumbnails()[0]['url']) | |
167 | |
168 def testThumbnailTitleChangeAfterPageTitleChange(self): | |
169 """Tests that once a page title changes, the thumbnail title changes too""" | |
170 self.RemoveNTPDefaultThumbnails() | |
171 self.NavigateToURL(self.PAGES[0]['url']) | |
172 self.assertEqual(self.PAGES[0]['title'], | |
173 self.GetNTPThumbnails()[0]['title']) | |
174 self.ExecuteJavascript('window.domAutomationController.send(' + | |
175 'document.title = "new title")') | |
176 self.assertEqual('new title', self.GetNTPThumbnails()[0]['title']) | |
177 | |
178 def testCloseOneTab(self): | |
179 """Tests that closing a tab populates the recently closed list""" | |
180 self.RemoveNTPDefaultThumbnails() | |
181 self.AppendTab(pyauto.GURL(self.PAGES[1]['url'])) | |
182 self.CloseTab(tab_index=1) | |
183 self.assertEqual(self.PAGES[1]['url'], | |
184 self.GetNTPRecentlyClosed()[0]['url']) | |
185 self.assertEqual(self.PAGES[1]['title'], | |
186 self.GetNTPRecentlyClosed()[0]['title']) | |
187 | |
188 def testCloseOneWindow(self): | |
189 """Tests that closing a window populates the recently closed list""" | |
190 self.RemoveNTPDefaultThumbnails() | |
191 self.OpenNewBrowserWindow(True) | |
192 self.NavigateToURL(self.PAGES[0]['url'], 1, 0) | |
193 self.AppendTab(pyauto.GURL(self.PAGES[1]['url']), 1) | |
194 self.CloseBrowserWindow(1) | |
195 expected = [{ u'type': u'window', | |
196 u'tabs': [ | |
197 { u'type': u'tab', | |
198 u'url': self.PAGES[0]['url'], | |
199 u'direction': u'ltr' }, | |
200 { u'type': u'tab', | |
201 u'url': self.PAGES[1]['url']}] | |
202 }] | |
203 self.assertEquals(expected, test_utils.StripUnmatchedKeys( | |
204 self.GetNTPRecentlyClosed(), expected)) | |
205 | |
206 def testCloseMultipleTabs(self): | |
207 """Tests closing multiple tabs populates the Recently Closed section in | |
208 order""" | |
209 self.RemoveNTPDefaultThumbnails() | |
210 self.AppendTab(pyauto.GURL(self.PAGES[0]['url'])) | |
211 self.AppendTab(pyauto.GURL(self.PAGES[1]['url'])) | |
212 self.CloseTab(tab_index=2) | |
213 self.CloseTab(tab_index=1) | |
214 expected = [{ u'type': u'tab', | |
215 u'url': self.PAGES[0]['url'] | |
216 }, | |
217 { u'type': u'tab', | |
218 u'url': self.PAGES[1]['url'] | |
219 }] | |
220 self.assertEquals(expected, test_utils.StripUnmatchedKeys( | |
221 self.GetNTPRecentlyClosed(), expected)) | |
222 | |
223 def testCloseWindowWithOneTab(self): | |
224 """Tests that closing a window with only one tab only shows up as a tab in | |
225 the Recently Closed section""" | |
226 self.RemoveNTPDefaultThumbnails() | |
227 self.OpenNewBrowserWindow(True) | |
228 self.NavigateToURL(self.PAGES[0]['url'], 1, 0) | |
229 self.CloseBrowserWindow(1) | |
230 expected = [{ u'type': u'tab', | |
231 u'url': self.PAGES[0]['url'] | |
232 }] | |
233 self.assertEquals(expected, test_utils.StripUnmatchedKeys( | |
234 self.GetNTPRecentlyClosed(), expected)) | |
235 | |
236 def testCloseMultipleWindows(self): | |
237 """Tests closing multiple windows populates the Recently Closed list""" | |
238 self.RemoveNTPDefaultThumbnails() | |
239 self.OpenNewBrowserWindow(True) | |
240 self.NavigateToURL(self.PAGES[0]['url'], 1, 0) | |
241 self.AppendTab(pyauto.GURL(self.PAGES[1]['url']), 1) | |
242 self.OpenNewBrowserWindow(True) | |
243 self.NavigateToURL(self.PAGES[1]['url'], 2, 0) | |
244 self.AppendTab(pyauto.GURL(self.PAGES[0]['url']), 2) | |
245 self.CloseBrowserWindow(2) | |
246 self.CloseBrowserWindow(1) | |
247 expected = [{ u'type': u'window', | |
248 u'tabs': [ | |
249 { u'type': u'tab', | |
250 u'url': self.PAGES[0]['url'], | |
251 u'direction': u'ltr' }, | |
252 { u'type': u'tab', | |
253 u'url': self.PAGES[1]['url']}] | |
254 }, | |
255 { u'type': u'window', | |
256 u'tabs': [ | |
257 { u'type': u'tab', | |
258 u'url': self.PAGES[1]['url'], | |
259 u'direction': u'ltr' }, | |
260 { u'type': u'tab', | |
261 u'url': self.PAGES[0]['url']}] | |
262 }] | |
263 self.assertEquals(expected, test_utils.StripUnmatchedKeys( | |
264 self.GetNTPRecentlyClosed(), expected)) | |
265 | |
266 def testRecentlyClosedIncognito(self): | |
267 """Tests that we don't record closure of Incognito tabs or windows""" | |
268 #self.RemoveNTPDefaultThumbnails() | |
269 self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) | |
270 self.NavigateToURL(self.PAGES[0]['url'], 1, 0) | |
271 self.AppendTab(pyauto.GURL(self.PAGES[0]['url']), 1) | |
272 self.AppendTab(pyauto.GURL(self.PAGES[1]['url']), 1) | |
273 self.CloseTab(windex=1) | |
274 self.assertFalse(self.GetNTPRecentlyClosed()) | |
275 self.CloseBrowserWindow(1) | |
276 self.assertFalse(self.GetNTPRecentlyClosed()) | |
277 | |
278 def _VerifyAppInfo(self, actual_info, expected_info): | |
279 """Ensures that the actual app info contains the expected app info. | |
280 | |
281 This method assumes that both the actual and expected information for each | |
282 app contains at least the 'title' attribute. Both sets of info are | |
283 considered to match if the actual info contains at least the specified | |
284 expected info (if the actual info contains additional values that are not | |
285 specified in the expected info, that's ok). This function will fail the | |
286 current test if both sets of info don't match. | |
287 | |
288 Args: | |
289 actual_info: A list of dictionaries representing the information from | |
290 all apps that would currently be displayed on the NTP. | |
291 expected_info: A corrresponding list of dictionaries representing the | |
292 information that is expected. | |
293 """ | |
294 # Ensure all app info dictionaries contain at least the 'title' attribute. | |
295 self.assertTrue(all(map(lambda app: 'title' in app, actual_info)) and | |
296 all(map(lambda app: 'title' in app, expected_info)), | |
297 msg='At least one app is missing the "title" attribute.') | |
298 | |
299 # Sort both app lists by title to ensure they're in a known order. | |
300 actual_info = sorted(actual_info, key=lambda app: app['title']) | |
301 expected_info = sorted(expected_info, key=lambda app: app['title']) | |
302 | |
303 # Ensure the expected info matches the actual info. | |
304 self.assertTrue(len(actual_info) == len(expected_info), | |
305 msg='Expected %d app(s) on NTP, but got %d instead.' % ( | |
306 len(expected_info), len(actual_info))) | |
307 for i, expected_app in enumerate(expected_info): | |
308 for attribute in expected_app: | |
309 self.assertTrue(attribute in actual_info[i], | |
310 msg='Expected attribute "%s" not found in app info.' % ( | |
311 attribute)) | |
312 self.assertTrue(expected_app[attribute] == actual_info[i][attribute], | |
313 msg='For attribute "%s", expected value "%s", but got ' | |
314 '"%s".' % (attribute, expected_app[attribute], | |
315 actual_info[i][attribute])) | |
316 | |
317 def _InstallAndVerifySamplePackagedApp(self): | |
318 """Installs a sample packaged app and verifies the install is successful. | |
319 | |
320 Returns: | |
321 The string ID of the installed app. | |
322 """ | |
323 app_crx_file = os.path.abspath(os.path.join( | |
324 self.DataDir(), 'pyauto_private', 'apps', 'countdown.crx')) | |
325 return self.InstallExtension(app_crx_file) | |
326 | |
327 def testGetAppsInNewProfile(self): | |
328 """Ensures that the only app in a new profile is the Web Store app.""" | |
329 app_info = self.GetNTPApps() | |
330 self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS) | |
331 | |
332 def testGetAppsWhenInstallApp(self): | |
333 """Ensures that an installed app is reflected in the app info in the NTP.""" | |
334 self._InstallAndVerifySamplePackagedApp() | |
335 app_info = self.GetNTPApps() | |
336 expected_app_info = [ | |
337 { | |
338 u'title': u'Countdown' | |
339 } | |
340 ] | |
341 expected_app_info.extend(self._EXPECTED_DEFAULT_APPS) | |
342 self._VerifyAppInfo(app_info, expected_app_info) | |
343 | |
344 def testGetAppsWhenInstallNonApps(self): | |
345 """Ensures installed non-apps are not reflected in the NTP app info.""" | |
346 # Install a regular extension and a theme. | |
347 ext_crx_file = os.path.abspath(os.path.join(self.DataDir(), 'extensions', | |
348 'page_action.crx')) | |
349 self.InstallExtension(ext_crx_file) | |
350 theme_crx_file = os.path.abspath(os.path.join(self.DataDir(), 'extensions', | |
351 'theme.crx')) | |
352 self.SetTheme(theme_crx_file) | |
353 # Verify that no apps are listed on the NTP except for the Web Store. | |
354 app_info = self.GetNTPApps() | |
355 self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS) | |
356 | |
357 def testUninstallApp(self): | |
358 """Ensures that an uninstalled app is reflected in the NTP app info.""" | |
359 # First, install an app and verify that it exists in the NTP app info. | |
360 installed_app_id = self._InstallAndVerifySamplePackagedApp() | |
361 app_info = self.GetNTPApps() | |
362 expected_app_info = [ | |
363 { | |
364 u'title': u'Countdown' | |
365 } | |
366 ] | |
367 expected_app_info.extend(self._EXPECTED_DEFAULT_APPS) | |
368 self._VerifyAppInfo(app_info, expected_app_info) | |
369 | |
370 # Next, uninstall the app and verify that it is removed from the NTP. | |
371 self.assertTrue(self.UninstallExtensionById(installed_app_id), | |
372 msg='Call to UninstallExtensionById() returned False.') | |
373 app_info = self.GetNTPApps() | |
374 self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS) | |
375 | |
376 def testCannotUninstallWebStore(self): | |
377 """Ensures that the WebStore app cannot be uninstalled.""" | |
378 # Verify that the WebStore app is already installed in a fresh profile. | |
379 app_info = self.GetNTPApps() | |
380 self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS) | |
381 self.assertTrue(app_info and 'id' in app_info[0], | |
382 msg='Cannot identify ID of WebStore app.') | |
383 webstore_id = app_info[0]['id'] | |
384 | |
385 # Attempt to uninstall the WebStore app and verify that it still exists | |
386 # in the App info of the NTP even after we try to uninstall it. | |
387 self.assertFalse(self.UninstallExtensionById(webstore_id), | |
388 msg='Call to UninstallExtensionById() returned True.') | |
389 self._VerifyAppInfo(self.GetNTPApps(), self._EXPECTED_DEFAULT_APPS) | |
390 | |
391 def testLaunchAppWithDefaultSettings(self): | |
392 """Verifies that an app can be launched with the default settings.""" | |
393 # Install an app. | |
394 installed_app_id = self._InstallAndVerifySamplePackagedApp() | |
395 | |
396 # Launch the app from the NTP. | |
397 self.LaunchApp(installed_app_id) | |
398 | |
399 # Verify that the second tab in the first window is the app launch URL. | |
400 # It should be the second tab, not the first, since the call to LaunchApp | |
401 # should have first opened the NTP in a new tab, and then launched the app | |
402 # from there. | |
403 info = self.GetBrowserInfo() | |
404 actual_tab_url = info['windows'][0]['tabs'][1]['url'] | |
405 expected_app_url_start = 'chrome-extension://' + installed_app_id | |
406 self.assertTrue(actual_tab_url.startswith(expected_app_url_start), | |
407 msg='The app was not launched.') | |
408 | |
409 def testLaunchAppRegularTab(self): | |
410 """Verifies that an app can be launched in a regular tab.""" | |
411 installed_app_id = self._InstallAndVerifySamplePackagedApp() | |
412 | |
413 self.SetAppLaunchType(installed_app_id, 'regular', windex=0) | |
414 self.LaunchApp(installed_app_id) | |
415 | |
416 # Verify that the second tab in the first window is the app launch URL. | |
417 info = self.GetBrowserInfo() | |
418 actual_tab_url = info['windows'][0]['tabs'][1]['url'] | |
419 expected_app_url_start = 'chrome-extension://' + installed_app_id | |
420 self.assertTrue(actual_tab_url.startswith(expected_app_url_start), | |
421 msg='The app was not launched in a regular tab.') | |
422 | |
423 def testLaunchAppPinnedTab(self): | |
424 """Verifies that an app can be launched in a pinned tab.""" | |
425 installed_app_id = self._InstallAndVerifySamplePackagedApp() | |
426 | |
427 self.SetAppLaunchType(installed_app_id, 'pinned', windex=0) | |
428 self.LaunchApp(installed_app_id) | |
429 | |
430 # Verify that the first tab in the first window is the app launch URL, and | |
431 # that it is a pinned tab. | |
432 info = self.GetBrowserInfo() | |
433 actual_tab_url = info['windows'][0]['tabs'][0]['url'] | |
434 expected_app_url_start = 'chrome-extension://' + installed_app_id | |
435 self.assertTrue(actual_tab_url.startswith(expected_app_url_start) and | |
436 info['windows'][0]['tabs'][0]['pinned'], | |
437 msg='The app was not launched in a pinned tab.') | |
438 | |
439 def testLaunchAppFullScreen(self): | |
440 """Verifies that an app can be launched in fullscreen mode.""" | |
441 installed_app_id = self._InstallAndVerifySamplePackagedApp() | |
442 | |
443 self.SetAppLaunchType(installed_app_id, 'fullscreen', windex=0) | |
444 self.LaunchApp(installed_app_id) | |
445 | |
446 # Verify that the second tab in the first window is the app launch URL, and | |
447 # that the window is fullscreen. | |
448 info = self.GetBrowserInfo() | |
449 actual_tab_url = info['windows'][0]['tabs'][1]['url'] | |
450 expected_app_url_start = 'chrome-extension://' + installed_app_id | |
451 self.assertTrue(actual_tab_url.startswith(expected_app_url_start) and | |
452 info['windows'][0]['fullscreen'], | |
453 msg='The app was not launched in fullscreen mode.') | |
454 | |
455 def testLaunchAppNewWindow(self): | |
456 """Verifies that an app can be launched in a new window.""" | |
457 installed_app_id = self._InstallAndVerifySamplePackagedApp() | |
458 | |
459 self.SetAppLaunchType(installed_app_id, 'window', windex=0) | |
460 self.LaunchApp(installed_app_id) | |
461 | |
462 # Verify that a second window exists (at index 1), and that its first tab | |
463 # is the app launch URL. | |
464 info = self.GetBrowserInfo() | |
465 self.assertTrue(len(info['windows']) == 2, | |
466 msg='A second window does not exist.') | |
467 actual_tab_url = info['windows'][1]['tabs'][0]['url'] | |
468 expected_app_url_start = 'chrome-extension://' + installed_app_id | |
469 self.assertTrue(actual_tab_url.startswith(expected_app_url_start), | |
470 msg='The app was not launched in the new window.') | |
471 | |
472 if __name__ == '__main__': | |
473 pyauto_functional.Main() | |
OLD | NEW |