summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordyu@chromium.org <dyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-31 02:15:41 +0000
committerdyu@chromium.org <dyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-31 02:15:41 +0000
commit23b95dc052caad716cc07db46919e288de05232e (patch)
tree229215195d8c9e54d1f9278608aaf6f87ff6e0fe
parent9ebb367f4f25f184784a06dfaad810832d332ff8 (diff)
downloadchromium_src-23b95dc052caad716cc07db46919e288de05232e.zip
chromium_src-23b95dc052caad716cc07db46919e288de05232e.tar.gz
chromium_src-23b95dc052caad716cc07db46919e288de05232e.tar.bz2
Added page objects for various content settings pages and generalized tests for specefic exceptions pages.
BUG=102892 TEST=none Review URL: https://chromiumcodereview.appspot.com/9147048 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119818 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/test/data/geolocation/geolocation_on_load.html17
-rw-r--r--chrome/test/functional/PYAUTO_TESTS3
-rwxr-xr-xchrome/test/functional/prefs.py87
-rw-r--r--chrome/test/functional/prefs_ui.py171
-rw-r--r--chrome/test/functional/webdriver_pages/settings.py281
5 files changed, 490 insertions, 69 deletions
diff --git a/chrome/test/data/geolocation/geolocation_on_load.html b/chrome/test/data/geolocation/geolocation_on_load.html
index f646a34a0..69b0bb5 100644
--- a/chrome/test/data/geolocation/geolocation_on_load.html
+++ b/chrome/test/data/geolocation/geolocation_on_load.html
@@ -5,9 +5,9 @@
<title>Show Geolocation on page load</title>
<script>
-function triggerGeo() {
+function triggerGeo(onSuccess, onError) {
if (navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(showPosition, onError);
+ navigator.geolocation.getCurrentPosition(onSuccess, onError);
} else {
document.getElementById('lat').innerHTML =
'Error: navigator.geolocation is false';
@@ -15,6 +15,15 @@ function triggerGeo() {
}
}
+
+function triggerGeoWithCallback(callback){
+ triggerGeo(function (position){
+ callback("allow");
+ }, function(positionError){
+ callback("block");
+ });
+}
+
function showPosition(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
@@ -22,7 +31,7 @@ function showPosition(position) {
document.getElementById('lng').innerHTML = lng;
}
-function onError(positionError) {
+function showError(positionError) {
document.getElementById('lat').innerHTML =
positionError.message;
document.getElementById('lng').innerHTML = '';
@@ -31,7 +40,7 @@ function onError(positionError) {
</script>
</head>
-<body onload="triggerGeo()">
+<body onload="triggerGeo(showPosition, showError)">
<b id=lat>-1</b>, <b id=lng>-1</b>
</body>
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
index 079cda7..8c60c1c 100644
--- a/chrome/test/functional/PYAUTO_TESTS
+++ b/chrome/test/functional/PYAUTO_TESTS
@@ -67,6 +67,7 @@
'policy_prefs_ui',
'popups',
'prefs',
+ 'prefs_ui',
'process_count',
'protector',
'pyauto_webdriver',
@@ -342,6 +343,8 @@
'-notifications.NotificationsTest.testOriginPrefsNotSavedInIncognito',
# crbug.com/103379
'-policy.PolicyTest.testDisable3DAPIs',
+ # Chrome driver does not work in Chrome OS.
+ '-prefs_ui',
],
},
diff --git a/chrome/test/functional/prefs.py b/chrome/test/functional/prefs.py
index f9a0080..05c579d 100755
--- a/chrome/test/functional/prefs.py
+++ b/chrome/test/functional/prefs.py
@@ -6,12 +6,9 @@
import logging
import os
import shutil
-import sys
import pyauto_functional # Must be imported before pyauto
import pyauto
-import test_utils
-
class PrefsTest(pyauto.PyUITest):
"""TestCase for Preferences."""
@@ -27,35 +24,21 @@ class PrefsTest(pyauto.PyUITest):
def testSessionRestore(self):
"""Test session restore preference."""
-
- pref_url = 'chrome://settings/browser'
url1 = 'http://www.google.com/'
url2 = 'http://news.google.com/'
-
- self.NavigateToURL(pref_url)
- # Set pref to restore session on startup.
- driver = self.NewWebDriver()
- restore_elem = driver.find_element_by_xpath(
- '//input[@metric="Options_Startup_LastSession"]')
- restore_elem.click()
- self.assertTrue(restore_elem.is_selected())
- self.RestartBrowser(clear_profile=False)
self.NavigateToURL(url1)
self.AppendTab(pyauto.GURL(url2))
num_tabs = self.GetTabCount()
+ # Set pref to restore session on startup.
+ self.SetPrefs(pyauto.kRestoreOnStartup, 1)
+ logging.debug('Setting %s to 1' % pyauto.kRestoreOnStartup)
self.RestartBrowser(clear_profile=False)
- # Verify tabs are properly restored.
self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup), 1)
self.assertEqual(num_tabs, self.GetTabCount())
self.ActivateTab(0)
self.assertEqual(url1, self.GetActiveTabURL().spec())
self.ActivateTab(1)
self.assertEqual(url2, self.GetActiveTabURL().spec())
- # Verify session restore option is still selected.
- self.NavigateToURL(pref_url, 0, 0)
- driver = self.NewWebDriver()
- self.assertTrue(driver.find_element_by_xpath(
- '//input[@metric="Options_Startup_LastSession"]').is_selected())
def testNavigationStateOnSessionRestore(self):
"""Verify navigation state is preserved on session restore."""
@@ -158,6 +141,9 @@ class PrefsTest(pyauto.PyUITest):
Checks for the geolocation infobar.
"""
+ from webdriver_pages import settings
+ from webdriver_pages.settings import Behaviors, ContentTypes
+ driver = self.NewWebDriver()
url = self.GetFileURLForPath(os.path.join( # triggers geolocation
self.DataDir(), 'geolocation', 'geolocation_on_load.html'))
self.assertEqual(3, # default state
@@ -174,8 +160,11 @@ class PrefsTest(pyauto.PyUITest):
if ((self.IsWin7() or self.IsWinVista()) and
self.GetBrowserInfo()['properties']['branding'] == 'Chromium'):
return
- self.assertTrue(self.WaitForInfobarCount(0))
- self.assertFalse(self.GetBrowserInfo()['windows'][0]['tabs'][0]['infobars'])
+ behavior = driver.execute_async_script(
+ 'triggerGeoWithCallback(arguments[arguments.length - 1]);')
+ self.assertEqual(
+ behavior, Behaviors.BLOCK,
+ msg='Behavior is "%s" when it should be BLOCKED.' % behavior)
def testUnderTheHoodPref(self):
"""Verify the security preferences for Under the Hood.
@@ -193,7 +182,6 @@ class PrefsTest(pyauto.PyUITest):
def testJavaScriptEnableDisable(self):
"""Verify enabling disabling javascript prefs work """
-
self.assertTrue(
self.GetPrefsInfo().Prefs(pyauto.kWebKitGlobalJavascriptEnabled))
url = self.GetFileURLForDataPath(
@@ -210,6 +198,59 @@ class PrefsTest(pyauto.PyUITest):
"""Verify that we have some Local State prefs."""
self.assertTrue(self.GetLocalStatePrefsInfo())
+ def testAllowSelectedGeoTracking(self):
+ """Verify hostname pattern and behavior for allowed tracking."""
+ # Default location tracking option "Ask me".
+ self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
+ self.NavigateToURL(
+ self.GetHttpURLForDataPath('geolocation', 'geolocation_on_load.html'))
+ self.assertTrue(self.WaitForInfobarCount(1))
+ self.PerformActionOnInfobar('accept', infobar_index=0) # Allow tracking.
+ # Get the hostname pattern (e.g. http://127.0.0.1:57622).
+ hostname_pattern = (
+ '/'.join(self.GetHttpURLForDataPath('').split('/')[0:3]) + '/')
+ self.assertEqual(
+ {hostname_pattern: {hostname_pattern: 1}}, # Allow the hostname.
+ self.GetPrefsInfo().Prefs(pyauto.kGeolocationContentSettings))
+
+ def testDismissedInfobarSavesNoEntry(self):
+ """Verify dismissing infobar does not save an exception entry."""
+ # Default location tracking option "Ask me".
+ self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
+ self.NavigateToURL(
+ self.GetFileURLForDataPath('geolocation', 'geolocation_on_load.html'))
+ self.assertTrue(self.WaitForInfobarCount(1))
+ self.PerformActionOnInfobar('dismiss', infobar_index=0)
+ self.assertEqual(
+ {}, self.GetPrefsInfo().Prefs(pyauto.kGeolocationContentSettings))
+
+ def testGeolocationBlockedWhenTrackingDenied(self):
+ """Verify geolocations is blocked when tracking is denied.
+
+ The test verifies the blocked hostname pattern entry on the Geolocations
+ exceptions page.
+ """
+ from webdriver_pages import settings
+ from webdriver_pages.settings import Behaviors, ContentTypes
+ driver = self.NewWebDriver()
+ # Ask for permission when site wants to track.
+ self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
+ self.NavigateToURL(
+ self.GetHttpURLForDataPath('geolocation', 'geolocation_on_load.html'))
+ self.assertTrue(self.WaitForInfobarCount(1))
+ self.PerformActionOnInfobar('cancel', infobar_index=0) # Deny tracking.
+ behavior = driver.execute_async_script(
+ 'triggerGeoWithCallback(arguments[arguments.length - 1]);')
+ self.assertEqual(
+ behavior, Behaviors.BLOCK,
+ msg='Behavior is "%s" when it should be BLOCKED.' % behavior)
+ # Get the hostname pattern (e.g. http://127.0.0.1:57622).
+ hostname_pattern = (
+ '/'.join(self.GetHttpURLForDataPath('').split('/')[0:3]) + '/')
+ self.assertEqual(
+ {hostname_pattern: {hostname_pattern: 3}}, # Block the hostname.
+ self.GetPrefsInfo().Prefs(pyauto.kGeolocationContentSettings))
+
if __name__ == '__main__':
pyauto_functional.Main()
diff --git a/chrome/test/functional/prefs_ui.py b/chrome/test/functional/prefs_ui.py
new file mode 100644
index 0000000..20a04d2
--- /dev/null
+++ b/chrome/test/functional/prefs_ui.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import pyauto_functional # Must be imported before pyauto
+import pyauto
+from webdriver_pages import settings
+from webdriver_pages.settings import Behaviors, ContentTypes
+
+
+class PrefsUITest(pyauto.PyUITest):
+ """TestCase for Preferences UI."""
+
+ def setUp(self):
+ pyauto.PyUITest.setUp(self)
+ self._driver = self.NewWebDriver()
+
+ def Debug(self):
+ """Test method for experimentation.
+
+ This method will not run automatically.
+ """
+ driver = self.NewWebDriver()
+ page = settings.ContentSettingsPage.FromNavigation(driver)
+ import pdb
+ pdb.set_trace()
+
+ def _GetGeolocationContentSettingsBehavior(self):
+ """Get the Content Settings behavior for Geolocation.
+
+ Returns:
+ The exceptions behavior for the specified content type.
+ The content type is the available content setting available.
+ """
+ behavior_key = self.GetPrefsInfo().Prefs(
+ pyauto.kGeolocationDefaultContentSetting)
+ behaviors_dict = {1: 'ALLOW', 2: 'BLOCK', 3: 'ASK'}
+ self.assertTrue(
+ behavior_key in behaviors_dict,
+ msg=('Invalid default behavior key "%s" for "geolocation" content' %
+ behavior_key))
+ return behaviors_dict[behavior_key]
+
+ def _VerifyContentExceptionUI(self, content_type, hostname_pattern, behavior):
+ """Find hostname pattern and behavior within UI on content exceptions page.
+
+ Args:
+ content_type: The string content settings type to manage.
+ hostname_pattern: The URL or pattern associated with the behavior.
+ behavior: The exception to allow or block the hostname.
+ """
+ page = settings.ManageExceptionsPage.FromNavigation(
+ self._driver, content_type)
+ self.assertTrue(page.GetExceptions().has_key(hostname_pattern),
+ msg=('No displayed host name matches pattern "%s"'
+ % hostname_pattern))
+ self.assertEqual(behavior, page.GetExceptions()[hostname_pattern],
+ msg=('Displayed behavior "%s" does not match behavior "%s"'
+ % (page.GetExceptions()[hostname_pattern], behavior)))
+
+ def testLocationSettingOptionsUI(self):
+ """Verify the location options setting UI.
+
+ Set the options through the UI using webdriver and verify the settings in
+ pyAuto.
+ """
+ page = settings.ContentSettingsPage.FromNavigation(self._driver)
+ page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.ALLOW)
+ self.assertEqual(
+ 1, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
+ page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.BLOCK)
+ self.assertEqual(
+ 2, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
+ page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.ASK)
+ self.assertEqual(
+ 3, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
+
+ def testBehaviorValueCorrectlyDisplayed(self):
+ """Verify the set behavior value is correctly displayed."""
+ # Block all sites.
+ self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 2)
+ self.assertEqual(
+ self._GetGeolocationContentSettingsBehavior(), Behaviors.BLOCK.upper(),
+ msg='The behavior was incorrectly set.')
+ # Allow all sites.
+ self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 1)
+ self.assertEqual(
+ self._GetGeolocationContentSettingsBehavior(), Behaviors.ALLOW.upper(),
+ msg='The behavior was incorrectly set.')
+ # Ask for permission when site wants to track.
+ self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
+ self.assertEqual(
+ self._GetGeolocationContentSettingsBehavior(), Behaviors.ASK.upper(),
+ msg='The behavior was incorrectly set.')
+
+ def testExceptionsEntryCorrectlyDisplayed(self):
+ """Verify the exceptions line entry is correctly displayed in the UI."""
+ geo_exception = (
+ {'http://maps.google.com:80/': {'http://maps.google.com': 2}})
+ self.SetPrefs(pyauto.kGeolocationContentSettings, geo_exception)
+ self._VerifyContentExceptionUI(
+ ContentTypes.GEOLOCATION, 'http://maps.google.com:80',
+ Behaviors.BLOCK)
+ geo_exception = (
+ {'http://maps.google.com:80/': {'http://maps.google.com:80': 1}})
+ self.SetPrefs(pyauto.kGeolocationContentSettings, geo_exception)
+ self._VerifyContentExceptionUI(
+ ContentTypes.GEOLOCATION, 'http://maps.google.com:80',
+ Behaviors.ALLOW)
+ geo_exception = (
+ {'http://maps.google.com:80/': {'http://maps.google.com:80': 3}})
+ self.SetPrefs(pyauto.kGeolocationContentSettings, geo_exception)
+ self._VerifyContentExceptionUI(
+ ContentTypes.GEOLOCATION, 'http://maps.google.com:80', Behaviors.ASK)
+
+ def testAddNewExceptionUI(self):
+ """Verify new exception added for hostname pattern and behavior in UI."""
+ content_type = ContentTypes.PLUGINS
+ page = settings.ManageExceptionsPage.FromNavigation(
+ self._driver, content_type)
+
+ pattern, behavior = ('bing.com', Behaviors.BLOCK)
+ page.AddNewException(pattern, behavior)
+ self.assertEqual(page.GetExceptions()[pattern], Behaviors.BLOCK,
+ msg='The behavior "%s" was not added for pattern "%s"'
+ % (behavior, pattern))
+
+ def testChangeExceptionBehaviorUI(self):
+ """Verify behavior for hostname pattern is changed in the UI."""
+ content_type = ContentTypes.PLUGINS
+ page = settings.ManageExceptionsPage.FromNavigation(
+ self._driver, content_type)
+
+ pattern, behavior = ('bing.com', Behaviors.BLOCK)
+ page.AddNewException(pattern, behavior)
+ new_behavior = Behaviors.ALLOW
+ page.SetBehaviorForPattern(pattern, new_behavior)
+ self.assertEqual(page.GetExceptions()[pattern], Behaviors.ALLOW,
+ msg='The behavior for "%s" did not change: "%s"'
+ % (pattern, behavior))
+
+ def testDeleteExceptionUI(self):
+ """Verify exception deleted for hostname pattern and behavior in the UI."""
+ content_type = ContentTypes.PLUGINS
+ page = settings.ManageExceptionsPage.FromNavigation(
+ self._driver, content_type)
+
+ pattern, behavior = ('bing.com', Behaviors.BLOCK)
+ raw_input()
+ page.AddNewException(pattern, behavior)
+ self.assertEqual(page.GetExceptions()[pattern], Behaviors.BLOCK,
+ msg='The behavior "%s" was not added for pattern "%s"'
+ % (behavior, pattern))
+ page.DeleteException(pattern)
+ self.assertEqual(page.GetExceptions().get(pattern, KeyError), KeyError,
+ msg='Pattern "%s" was not deleted' % pattern)
+
+ def testNoInitialLineEntryInUI(self):
+ """Verify no initial line entry is displayed in UI."""
+ # Ask for permission when site wants to track.
+ self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
+ self.assertEqual(
+ 3, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
+ page = settings.ManageExceptionsPage.FromNavigation(
+ self._driver, ContentTypes.GEOLOCATION)
+ self.assertEqual(0, len(page.GetExceptions()))
+
+
+if __name__ == '__main__':
+ pyauto_functional.Main()
diff --git a/chrome/test/functional/webdriver_pages/settings.py b/chrome/test/functional/webdriver_pages/settings.py
index e733bf6..3b78f4d 100644
--- a/chrome/test/functional/webdriver_pages/settings.py
+++ b/chrome/test/functional/webdriver_pages/settings.py
@@ -8,6 +8,49 @@ import selenium.common.exceptions
from selenium.webdriver.common.action_chains import ActionChains
+def _FocusField(driver, list_elem, field_elem):
+ """Focuses a field in a dynamic list.
+
+ Note, the item containing the field should not be focused already.
+
+ Typing into a field is tricky because the js automatically focuses and
+ selects the text field after 50ms after it first receives focus. This
+ method focuses the field and waits for the timeout to occur.
+ For more info, see inline_editable_list.js and search for setTimeout.
+ See crbug.com/97369.
+
+ Args:
+ list_elem: An element in the HTML list.
+ field_elem: An element in the HTML text field.
+
+ Raises:
+ RuntimeError: If a timeout occurs when waiting for the focus event.
+ """
+ # To wait properly for the focus, we focus the last text field, and then
+ # add a focus listener to it, so that we return when the element is focused
+ # again after the timeout. We have to focus a different element in between
+ # these steps, otherwise the focus event will not fire since the element
+ # already has focus.
+ # Ideally this should be fixed in the page.
+
+ correct_focus_script = """
+ (function(listElem, itemElem, callback) {
+ if (document.activeElement == itemElem) {
+ callback();
+ return;
+ }
+ itemElem.focus();
+ listElem.focus();
+ itemElem.addEventListener("focus", callback);
+ }).apply(null, arguments);
+ """
+ driver.set_script_timeout(5)
+ try:
+ driver.execute_async_script(correct_focus_script, list_elem, field_elem)
+ except selenium.common.exceptions.TimeoutException:
+ raise RuntimeError('Unable to focus list item ' + field_elem)
+
+
class DynamicList(object):
"""A web element that holds a dynamic list of items.
@@ -51,11 +94,41 @@ class DynamicList(object):
"""The item to be added must have the same number of fields as an item
in the HTML list. Given item '%s' should have %s fields.""" % (
item, len(fields))
- self._FocusField(fields[0])
+ _FocusField(self.driver, self.elem, fields[0])
for field, value in zip(fields, values)[1:-1]:
field.send_keys(value + '\t')
fields[-1].send_keys(values[-1] + '\n')
+ def Remove(self, item):
+ """Removes all item occurrences from the list.
+
+ Args:
+ item: The item to remove from the list.
+ """
+ # There's no close button for the last field.
+ fields = self._GetPlaceholderElem().find_elements_by_tag_name('input')
+ if len(fields) > 1:
+ assert type(item) == types.ListType, \
+ """The item must be a list for a HTML list that has multi-field
+ items. '%s' should be in a list.""" % item
+ values = item
+ else:
+ values = [item]
+
+ assert len(fields) == len(values), \
+ """The item to be added must have the same number of fields as an item
+ in the HTML list. Given item '%s' should have %d fields.""" % (
+ item, len(fields))
+
+ item_list = self.GetCommittedItems()
+ close_button_list = self.elem.find_elements_by_class_name(
+ 'close-button')[:-1]
+ for i in range(len(item_list)):
+ if item_list[i] == item:
+ # Highlight the item, so the close button shows up, then click it.
+ ActionChains(self.driver).move_to_element(
+ close_button_list[i]).click().perform()
+
def RemoveAll(self):
"""Removes all items from the list."""
# There's no close button for the last field.
@@ -82,47 +155,6 @@ class DynamicList(object):
"""Returns the number of items in the list, excluding the placeholder."""
return len(self._GetCommittedItemElems())
- def _FocusField(self, field):
- """Focuses a field in the list.
-
- Note, the item containing the field should not be focused already.
-
- Typing into a field is tricky because the js automatically focuses and
- selects the text field after 50ms after it first receives focus. This
- method focuses the field and waits for the timeout to occur.
- For more info, see inline_editable_list.js and search for setTimeout.
- See crbug.com/97369.
-
- Args:
- field: HTML text field to focus.
-
- Raises:
- RuntimeError: A timeout occurred when waiting for the focus event.
- """
- # To wait properly for the focus, we focus the last text field, and then
- # add a focus listener to it, so that we return when the element is focused
- # again after the timeout. We have to focus a different element in between
- # these steps, otherwise the focus event will not fire since the element
- # already has focus.
- # Ideally this should be fixed in the page.
-
- correct_focus_script = """
- (function(listElem, itemElem, callback) {
- if (document.activeElement == itemElem) {
- callback();
- return;
- }
- itemElem.focus();
- listElem.focus();
- itemElem.addEventListener("focus", callback);
- }).apply(null, arguments);
- """
- self.driver.set_script_timeout(5)
- try:
- self.driver.execute_async_script(correct_focus_script, self.elem, field)
- except selenium.common.exceptions.TimeoutException:
- raise RuntimeError('Unable to focus list item' + value)
-
def _GetCommittedItemElems(self):
return self._GetItemElems()[:-1]
@@ -225,3 +257,168 @@ class AutofillEditAddressDialog(object):
list = DynamicList(
self.driver, self.dialog_elem.find_element_by_id('phone-list'))
return list.GetCommittedItems()
+
+
+class ContentTypes(object):
+ COOKIES = 'cookies'
+ IMAGES = 'images'
+ JAVASCRIPT = 'javascript'
+ HANDLERS = 'handlers'
+ PLUGINS = 'plugins'
+ POPUPS = 'popups'
+ GEOLOCATION = 'location'
+ NOTIFICATIONS = 'notifications'
+
+
+class Behaviors(object):
+ ALLOW = 'allow'
+ SESSION_ONLY = 'session_only'
+ ASK = 'ask'
+ BLOCK = 'block'
+
+
+class ContentSettingsPage(object):
+ """The overlay for managing exceptions on the Content Settings page."""
+
+ _URL = 'chrome://settings/content'
+
+ @staticmethod
+ def FromNavigation(driver):
+ """Creates an instance of the dialog by navigating directly to it."""
+ driver.get(ContentSettingsPage._URL)
+ return ContentSettingsPage(driver)
+
+ def __init__(self, driver):
+ assert self._URL == driver.current_url
+ self.page_elem = driver.find_element_by_id(
+ 'content-settings-page')
+
+ def SetContentTypeOption(self, content_type, option):
+ """Set the option for the specified content type.
+
+ Args:
+ content_type: The content type to manage.
+ option: The option to allow, deny or ask.
+ """
+ self.page_elem.find_element_by_xpath(
+ './/*[@name="%s"][@value="%s"]' % (content_type, option)).click()
+
+
+class ManageExceptionsPage(object):
+ """The overlay for the content exceptions page."""
+
+ @staticmethod
+ def FromNavigation(driver, content_type):
+ """Creates an instance of the dialog by navigating directly to it.
+
+ Args:
+ driver: The remote WebDriver instance to manage some content type.
+ content_type: The content type to manage.
+ """
+ content_url = 'chrome://settings/contentExceptions#%s' % content_type
+ driver.get(content_url)
+ return ManageExceptionsPage(driver, content_type)
+
+ def __init__(self, driver, content_type):
+ content_url = 'chrome://settings/contentExceptions#%s' % content_type
+ assert content_url == driver.current_url
+ self._list_elem = driver.find_element_by_xpath(
+ './/*[@id="content-settings-exceptions-area"]' \
+ '//*[@contenttype="%s"]//list[@role="listbox"]' \
+ '[@class="settings-list"]' % content_type)
+ self._driver = driver
+ self._content_type = content_type
+
+ def _GetExceptionList(self):
+ return DynamicList(self._driver, self._list_elem)
+
+ def _GetPatternList(self):
+ pattern_list = [p.text for p in
+ self._list_elem.find_elements_by_xpath(
+ './/*[contains(@class, "exception-pattern")]'
+ '//*[@class="static-text"]')]
+ return pattern_list
+
+ def AddNewException(self, pattern, behavior):
+ """Add a new pattern and behavior to the Exceptions page.
+
+ Args:
+ pattern: Hostname pattern string.
+ behavior: Setting for the hostname pattern (Allow, Block, Session Only).
+
+ Raises:
+ AssertionError when an exception cannot be added on the content page.
+ """
+ # Select behavior first.
+ try:
+ self._list_elem.find_element_by_xpath(
+ './/*[@class="exception-setting"]'
+ '[not(@displaymode)]//option[@value="%s"]'
+ % behavior).click()
+ except selenium.common.exceptions.NoSuchElementException:
+ raise AssertionError(
+ 'Adding new exception not allowed in "%s" content page'
+ % self._content_type)
+ # Set pattern now.
+ self._GetExceptionList().Add(pattern)
+
+ def DeleteException(self, pattern):
+ """Delete the exception for the selected hostname pattern.
+
+ Args:
+ pattern: Hostname pattern string.
+ """
+ self._GetExceptionList().Remove(pattern)
+
+ def GetExceptions(self):
+ """Returns a dictionary of {pattern: behavior}.
+
+ Example: {'file:///*': 'block'}
+ """
+ pattern_list = self._GetPatternList()
+ behavior_list = self._list_elem.find_elements_by_xpath(
+ './/*[@role="listitem"][@class="deletable-item"]' \
+ '//*[@class="exception-setting"][@displaymode="static"]')
+ assert len(pattern_list) == len(behavior_list), \
+ 'Number of patterns does not match the behaviors.'
+ return dict(zip(pattern_list, [b.text.lower() for b in behavior_list]))
+
+ def GetBehaviorForPattern(self, pattern):
+ """Returns the behavior for a given pattern on the Exceptions page.
+
+ Args:
+ pattern: Hostname pattern string.
+ """
+ assert self.GetExceptions().has_key(pattern), \
+ 'No displayed host name matches pattern "%s"' % pattern
+ return self.GetExceptions()[pattern]
+
+ def SetBehaviorForPattern(self, pattern, behavior):
+ """Set the behavior for the selected pattern on the Exceptions page.
+
+ Args:
+ pattern: Hostname pattern string.
+ behavior: Setting for the hostname pattern (Allow, Block, Session Only).
+
+ Raises:
+ AssertionError when the behavior cannot be changed on the content page.
+ """
+ pattern_list = self._GetPatternList()
+ listitem_list = self._list_elem.find_elements_by_xpath(
+ './/*[@role="listitem"][@class="deletable-item"]')
+ pattern_listitem_dict = dict(zip(pattern_list, listitem_list))
+ # Set focus to appropriate listitem.
+ listitem_elem = pattern_listitem_dict[pattern]
+ listitem_elem.click()
+ # Set behavior.
+ try:
+ listitem_elem.find_element_by_xpath(
+ './/option[@value="%s"]' % behavior).click()
+ except selenium.common.exceptions.ElementNotVisibleException:
+ raise AssertionError(
+ 'Changing the behavior is invalid for pattern '
+ '"%s" in "%s" content page' % (behavior, self._content_type))
+ # Send enter key.
+ pattern_elem = listitem_elem.find_element_by_tag_name('input')
+ _FocusField(self._driver, self._list_elem, pattern_elem)
+ pattern_elem.send_keys('\n')