diff options
author | dyu@chromium.org <dyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-31 02:15:41 +0000 |
---|---|---|
committer | dyu@chromium.org <dyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-31 02:15:41 +0000 |
commit | 23b95dc052caad716cc07db46919e288de05232e (patch) | |
tree | 229215195d8c9e54d1f9278608aaf6f87ff6e0fe | |
parent | 9ebb367f4f25f184784a06dfaad810832d332ff8 (diff) | |
download | chromium_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.html | 17 | ||||
-rw-r--r-- | chrome/test/functional/PYAUTO_TESTS | 3 | ||||
-rwxr-xr-x | chrome/test/functional/prefs.py | 87 | ||||
-rw-r--r-- | chrome/test/functional/prefs_ui.py | 171 | ||||
-rw-r--r-- | chrome/test/functional/webdriver_pages/settings.py | 281 |
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') |