Make hitting "Enter" submit the add/change profile dialog.
[chromium-blink-merge.git] / chrome / test / functional / extensions.py
blob0fa3bafaaf0e33990e9a51f2e23d85e3e4f0ebd5
1 #!/usr/bin/env python
2 # Copyright (c) 2011 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.
6 """
7 This module is a simple qa tool that installs extensions and tests whether the
8 browser crashes while visiting a list of urls.
10 Usage: python extensions.py -v
12 Note: This assumes that there is a directory of extensions called
13 'extensions-tool' and that there is a file of newline-separated urls to visit
14 called 'urls.txt' in the data directory.
15 """
17 import glob
18 import logging
19 import os
20 import sys
22 import pyauto_functional # must be imported before pyauto
23 import pyauto
26 class ExtensionsPage(object):
27 """Access options in extensions page (chrome://extensions-frame)."""
29 _URL = 'chrome://extensions-frame'
31 def __init__(self, driver):
32 self._driver = driver
33 self._driver.get(ExtensionsPage._URL)
35 def CheckExtensionVisible(self, ext_id):
36 """Returns True if |ext_id| exists on page."""
37 return len(self._driver.find_elements_by_id(ext_id)) == 1
39 def SetEnabled(self, ext_id, enabled):
40 """Clicks on 'Enabled' checkbox for specified extension.
42 Args:
43 ext_id: Extension ID to be enabled or disabled.
44 enabled: Boolean indicating whether |ext_id| is to be enabled or disabled.
45 """
46 checkbox = self._driver.find_element_by_xpath(
47 '//*[@id="%s"]//*[@class="enable-controls"]//*[@type="checkbox"]' %
48 ext_id)
49 if checkbox != enabled:
50 checkbox.click()
51 # Reload page to ensure that the UI is recreated.
52 self._driver.get(ExtensionsPage._URL)
54 def SetAllowInIncognito(self, ext_id, allowed):
55 """Clicks on 'Allow in incognito' checkbox for specified extension.
57 Args:
58 ext_id: Extension ID to be enabled or disabled.
59 allowed: Boolean indicating whether |ext_id| is to be allowed or
60 disallowed in incognito.
61 """
62 checkbox = self._driver.find_element_by_xpath(
63 '//*[@id="%s"]//*[@class="incognito-control"]//*[@type="checkbox"]' %
64 ext_id)
65 if checkbox.is_selected() != allowed:
66 checkbox.click()
67 # Reload page to ensure that the UI is recreated.
68 self._driver.get(ExtensionsPage._URL)
70 def SetAllowAccessFileURLs(self, ext_id, allowed):
71 """Clicks on 'Allow access to file URLs' checkbox for specified extension.
73 Args:
74 ext_id: Extension ID to be enabled or disabled.
75 allowed: Boolean indicating whether |ext_id| is to be allowed access to
76 file URLs.
77 """
78 checkbox = self._driver.find_element_by_xpath(
79 '//*[@id="%s"]//*[@class="file-access-control"]//*[@type="checkbox"]' %
80 ext_id)
81 if checkbox.is_selected() != allowed:
82 checkbox.click()
85 class ExtensionsTest(pyauto.PyUITest):
86 """Test of extensions."""
88 def Debug(self):
89 """Test method for experimentation.
91 This method is not run automatically.
92 """
93 while True:
94 raw_input('Interact with the browser and hit <enter> to dump history.')
95 print '*' * 20
96 self.pprint(self.GetExtensionsInfo())
98 def _GetInstalledExtensionIds(self):
99 return [extension['id'] for extension in self.GetExtensionsInfo()]
101 def _ReturnCrashingExtensions(self, extensions, group_size, top_urls):
102 """Returns the group of extensions that crashes (if any).
104 Install the given extensions in groups of group_size and return the
105 group of extensions that crashes (if any).
107 Args:
108 extensions: A list of extensions to install.
109 group_size: The number of extensions to install at one time.
110 top_urls: The list of top urls to visit.
112 Returns:
113 The extensions in the crashing group or None if there is no crash.
115 curr_extension = 0
116 num_extensions = len(extensions)
117 self.RestartBrowser()
118 orig_extension_ids = self._GetInstalledExtensionIds()
120 while curr_extension < num_extensions:
121 logging.debug('New group of %d extensions.', group_size)
122 group_end = curr_extension + group_size
123 for extension in extensions[curr_extension:group_end]:
124 logging.debug('Installing extension: %s', extension)
125 self.InstallExtension(extension)
127 for url in top_urls:
128 self.NavigateToURL(url)
130 def _LogAndReturnCrashing():
131 crashing_extensions = extensions[curr_extension:group_end]
132 logging.debug('Crashing extensions: %s', crashing_extensions)
133 return crashing_extensions
135 # If the browser has crashed, return the extensions in the failing group.
136 try:
137 num_browser_windows = self.GetBrowserWindowCount()
138 except:
139 return _LogAndReturnCrashing()
140 else:
141 if not num_browser_windows:
142 return _LogAndReturnCrashing()
143 else:
144 # Uninstall all extensions that aren't installed by default.
145 new_extension_ids = [id for id in self._GetInstalledExtensionIds()
146 if id not in orig_extension_ids]
147 for extension_id in new_extension_ids:
148 self.UninstallExtensionById(extension_id)
150 curr_extension = group_end
152 # None of the extensions crashed.
153 return None
155 def _GetExtensionInfoById(self, extensions, id):
156 for x in extensions:
157 if x['id'] == id:
158 return x
159 return None
161 def ExtensionCrashes(self):
162 """Add top extensions; confirm browser stays up when visiting top urls."""
163 # TODO: provide a way in pyauto to pass args to a test - take these as args
164 extensions_dir = os.path.join(self.DataDir(), 'extensions-tool')
165 urls_file = os.path.join(self.DataDir(), 'urls.txt')
167 error_msg = 'The dir "%s" must exist' % os.path.abspath(extensions_dir)
168 assert os.path.exists(extensions_dir), error_msg
169 error_msg = 'The file "%s" must exist' % os.path.abspath(urls_file)
170 assert os.path.exists(urls_file), error_msg
172 num_urls_to_visit = 100
173 extensions_group_size = 20
175 top_urls = [l.rstrip() for l in
176 open(urls_file).readlines()[:num_urls_to_visit]]
178 failed_extensions = glob.glob(os.path.join(extensions_dir, '*.crx'))
179 group_size = extensions_group_size
181 while (group_size and failed_extensions):
182 failed_extensions = self._ReturnCrashingExtensions(
183 failed_extensions, group_size, top_urls)
184 group_size = group_size // 2
186 self.assertFalse(failed_extensions,
187 'Extension(s) in failing group: %s' % failed_extensions)
189 def _InstallExtensionCheckDefaults(self, crx_file):
190 """Installs extension at extensions/|crx_file| and checks default status.
192 Checks that the installed extension is enabled and not allowed in incognito.
194 Args:
195 crx_file: Relative path from self.DataDir()/extensions to .crx extension
196 to be installed.
198 Returns:
199 The extension ID.
201 crx_file_path = os.path.abspath(
202 os.path.join(self.DataDir(), 'extensions', crx_file))
203 ext_id = self.InstallExtension(crx_file_path)
204 extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
205 self.assertTrue(extension['is_enabled'],
206 msg='Extension was not enabled on installation')
207 self.assertFalse(extension['allowed_in_incognito'],
208 msg='Extension was allowed in incognito on installation.')
210 return ext_id
212 def _ExtensionValue(self, ext_id, key):
213 """Returns the value of |key| for |ext_id|.
215 Args:
216 ext_id: The extension ID.
217 key: The key for which the extensions info value is required.
219 Returns:
220 The value of extensions info |key| for |ext_id|.
222 return self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)[key]
224 def _FileAccess(self, ext_id):
225 """Returns the value of newAllowFileAccess for |ext_id|.
227 Args:
228 ext_id: The extension ID.
230 Returns:
231 The value of extensions settings newAllowFileAccess for |ext_id|.
233 extension_settings = self.GetPrefsInfo().Prefs()['extensions']['settings']
234 return extension_settings[ext_id]['newAllowFileAccess']
236 def testGetExtensionPermissions(self):
237 """Ensures we can retrieve the host/api permissions for an extension.
239 This test assumes that the 'Bookmark Manager' extension exists in a fresh
240 profile.
242 extensions_info = self.GetExtensionsInfo()
243 bm_exts = [x for x in extensions_info if x['name'] == 'Bookmark Manager']
244 self.assertTrue(bm_exts,
245 msg='Could not find info for the Bookmark Manager '
246 'extension.')
247 ext = bm_exts[0]
249 permissions_host = ext['host_permissions']
250 self.assertTrue(len(permissions_host) == 2 and
251 'chrome://favicon/*' in permissions_host and
252 'chrome://resources/*' in permissions_host,
253 msg='Unexpected host permissions information.')
255 permissions_api = ext['api_permissions']
256 print permissions_api
257 self.assertTrue(len(permissions_api) == 4 and
258 'bookmarks' in permissions_api and
259 'bookmarkManagerPrivate' in permissions_api and
260 'systemPrivate' in permissions_api and
261 'tabs' in permissions_api,
262 msg='Unexpected API permissions information.')
264 def testSetExtensionStates(self):
265 """Test setting different extension states."""
266 ext_id = self._InstallExtensionCheckDefaults('google_talk.crx')
268 # Disable the extension and verify.
269 self.SetExtensionStateById(ext_id, enable=False, allow_in_incognito=False)
270 extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
271 self.assertFalse(extension['is_enabled'])
273 # Enable extension and verify.
274 self.SetExtensionStateById(ext_id, enable=True, allow_in_incognito=False)
275 extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
276 self.assertTrue(extension['is_enabled'])
278 # Allow extension in incognito mode and verify.
279 self.SetExtensionStateById(ext_id, enable=True, allow_in_incognito=True)
280 extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
281 self.assertTrue(extension['allowed_in_incognito'])
283 # Disallow extension in incognito mode and verify.
284 self.SetExtensionStateById(ext_id, enable=True, allow_in_incognito=False)
285 extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
286 self.assertFalse(extension['allowed_in_incognito'])
288 def testTriggerBrowserAction(self):
289 """Test triggering browser action."""
290 dir_path = os.path.abspath(
291 os.path.join(self.DataDir(), 'extensions', 'trigger_actions',
292 'browser_action'))
293 ext_id = self.InstallExtension(dir_path)
295 self.NavigateToURL(self.GetFileURLForDataPath('simple.html'))
297 self.TriggerBrowserActionById(ext_id)
299 # Verify that the browser action turned the background red.
300 self.assertTrue(self.WaitUntil(
301 lambda: self.GetDOMValue('document.body.style.backgroundColor'),
302 expect_retval='red'),
303 msg='Browser action was not triggered.')
305 def testTriggerBrowserActionWithPopup(self):
306 """Test triggering browser action that shows a popup."""
307 # Fails on Vista Chromium bot only. crbug.com/106620
308 if (self.IsWinVista() and
309 self.GetBrowserInfo()['properties']['branding'] == 'Chromium'):
310 return
311 dir_path = os.path.abspath(
312 os.path.join(self.DataDir(), 'extensions', 'trigger_actions',
313 'browser_action_popup'))
314 ext_id = self.InstallExtension(dir_path)
316 self.TriggerBrowserActionById(ext_id)
318 # Verify that the extension popup is displayed.
319 popup = self.WaitUntilExtensionViewLoaded(
320 view_type='EXTENSION_POPUP')
321 self.assertTrue(popup,
322 msg='Browser action failed to display the popup (views=%s).' %
323 self.GetBrowserInfo()['extension_views'])
325 def testTriggerPageAction(self):
326 """Test triggering page action."""
327 dir_path = os.path.abspath(
328 os.path.join(self.DataDir(), 'extensions', 'trigger_actions',
329 'page_action'))
330 ext_id = self.InstallExtension(dir_path)
332 # Page action icon is displayed when a tab is created.
333 self.NavigateToURL(self.GetFileURLForDataPath('simple.html'))
334 self.AppendTab(pyauto.GURL('chrome://newtab'))
335 self.ActivateTab(0)
336 self.assertTrue(self.WaitUntil(
337 lambda: ext_id in
338 self.GetBrowserInfo()['windows'][0]['visible_page_actions']),
339 msg='Page action icon is not visible.')
341 self.TriggerPageActionById(ext_id)
343 # Verify that page action turned the background red.
344 self.assertTrue(self.WaitUntil(
345 lambda: self.GetDOMValue('document.body.style.backgroundColor'),
346 expect_retval='red'),
347 msg='Page action was not triggered.')
349 def testTriggerPageActionWithPopup(self):
350 """Test triggering page action that shows a popup."""
351 # Fails on Vista Chromium bot only. crbug.com/106620
352 if (self.IsWinVista() and
353 self.GetBrowserInfo()['properties']['branding'] == 'Chromium'):
354 return
355 dir_path = os.path.abspath(
356 os.path.join(self.DataDir(), 'extensions', 'trigger_actions',
357 'page_action_popup'))
358 ext_id = self.InstallExtension(dir_path)
360 # Page action icon is displayed when a tab is created.
361 self.AppendTab(pyauto.GURL('chrome://newtab'))
362 self.ActivateTab(0)
363 self.assertTrue(self.WaitUntil(
364 lambda: ext_id in
365 self.GetBrowserInfo()['windows'][0]['visible_page_actions']),
366 msg='Page action icon is not visible.')
368 self.TriggerPageActionById(ext_id)
370 # Verify that the extension popup is displayed.
371 popup = self.WaitUntilExtensionViewLoaded(
372 view_type='EXTENSION_POPUP')
373 self.assertTrue(popup,
374 msg='Page action failed to display the popup (views=%s).' %
375 self.GetBrowserInfo()['extension_views'])
377 def testAdblockExtensionCrash(self):
378 """Test AdBlock extension does not cause a browser crash."""
379 ext_id = self._InstallExtensionCheckDefaults('adblock.crx')
381 self.RestartBrowser(clear_profile=False)
382 extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
383 self.assertTrue(extension['is_enabled'])
384 self.assertFalse(extension['allowed_in_incognito'])
386 def testDisableEnableExtension(self):
387 """Tests that an extension can be disabled and enabled with the UI."""
388 ext_id = self._InstallExtensionCheckDefaults('good.crx')
390 # Disable extension.
391 driver = self.NewWebDriver()
392 ext_page = ExtensionsPage(driver)
393 self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
394 ext_page.SetEnabled(ext_id, False)
395 self.WaitUntil(self._ExtensionValue, args=[ext_id, 'is_enabled'],
396 expect_retval=False)
397 self.assertFalse(self._ExtensionValue(ext_id, 'is_enabled'),
398 msg='Extension did not get disabled.')
400 # Enable extension.
401 self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
402 ext_page.SetEnabled(ext_id, True)
403 self.WaitUntil(self._ExtensionValue, args=[ext_id, 'is_enabled'],
404 expect_retval=True)
405 self.assertTrue(self._ExtensionValue(ext_id, 'is_enabled'),
406 msg='Extension did not get enabled.')
408 def testAllowIncognitoExtension(self):
409 """Tests allowing and disallowing an extension in incognito mode."""
410 ext_id = self._InstallExtensionCheckDefaults('good.crx')
412 # Allow in incognito.
413 driver = self.NewWebDriver()
414 ext_page = ExtensionsPage(driver)
415 self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
416 ext_page.SetAllowInIncognito(ext_id, True)
418 # Check extension now allowed in incognito.
419 self.WaitUntil(self._ExtensionValue, args=[ext_id, 'allowed_in_incognito'],
420 expect_retval=True)
421 self.assertTrue(self._ExtensionValue(ext_id, 'allowed_in_incognito'),
422 msg='Extension did not get allowed in incognito.')
424 # Disallow in incognito.
425 self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
426 ext_page.SetAllowInIncognito(ext_id, False)
428 # Check extension now disallowed in incognito.
429 self.WaitUntil(self._ExtensionValue, args=[ext_id, 'allowed_in_incognito'],
430 expect_retval=False)
431 self.assertFalse(self._ExtensionValue(ext_id, 'allowed_in_incognito'),
432 msg='Extension did not get disallowed in incognito.')
434 def testAllowAccessFileURLs(self):
435 """Tests disallowing and allowing and extension access to file URLs."""
436 ext_id = self._InstallExtensionCheckDefaults(os.path.join('permissions',
437 'files'))
439 # Check extension allowed access to file URLs by default.
440 extension_settings = self.GetPrefsInfo().Prefs()['extensions']['settings']
441 self.assertTrue(extension_settings[ext_id]['newAllowFileAccess'],
442 msg='Extension was not allowed access to file URLs on '
443 'installation')
445 # Disallow access to file URLs.
446 driver = self.NewWebDriver()
447 ext_page = ExtensionsPage(driver)
448 self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
449 ext_page.SetAllowAccessFileURLs(ext_id, False)
451 # Check that extension does not have access to file URLs.
452 self.WaitUntil(self._FileAccess, args=[ext_id], expect_retval=False)
453 self.assertFalse(self._FileAccess(ext_id),
454 msg='Extension did not have access to file URLs denied.')
456 # Allow access to file URLs.
457 self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
458 ext_page.SetAllowAccessFileURLs(ext_id, True)
460 # Check that extension now has access to file URLs.
461 self.WaitUntil(self._FileAccess, args=[ext_id], expect_retval=True)
462 self.assertTrue(self._FileAccess(ext_id),
463 msg='Extension did not have access to file URLs granted.')
466 if __name__ == '__main__':
467 pyauto_functional.Main()