Home | History | Annotate | Download | only in webdriver_pages
      1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import types
      6 
      7 import selenium.common.exceptions
      8 from selenium.webdriver.common.action_chains import ActionChains
      9 from selenium.webdriver.support.ui import WebDriverWait
     10 
     11 
     12 def _FocusField(driver, list_elem, field_elem):
     13   """Focuses a field in a dynamic list.
     14 
     15   Note, the item containing the field should not be focused already.
     16 
     17   Typing into a field is tricky because the js automatically focuses and
     18   selects the text field after 50ms after it first receives focus. This
     19   method focuses the field and waits for the timeout to occur.
     20   For more info, see inline_editable_list.js and search for setTimeout.
     21   See crbug.com/97369.
     22 
     23   Args:
     24     list_elem: An element in the HTML list.
     25     field_elem: An element in the HTML text field.
     26 
     27   Raises:
     28     RuntimeError: If a timeout occurs when waiting for the focus event.
     29   """
     30   # To wait properly for the focus, we focus the last text field, and then
     31   # add a focus listener to it, so that we return when the element is focused
     32   # again after the timeout. We have to focus a different element in between
     33   # these steps, otherwise the focus event will not fire since the element
     34   # already has focus.
     35   # Ideally this should be fixed in the page.
     36 
     37   correct_focus_script = """
     38       (function(listElem, itemElem, callback) {
     39         if (document.activeElement == itemElem) {
     40           callback();
     41           return;
     42         }
     43         itemElem.focus();
     44         listElem.focus();
     45         itemElem.addEventListener("focus", callback);
     46       }).apply(null, arguments);
     47   """
     48   driver.set_script_timeout(5)
     49   try:
     50     driver.execute_async_script(correct_focus_script, list_elem, field_elem)
     51   except selenium.common.exceptions.TimeoutException:
     52     raise RuntimeError('Unable to focus list item ' + field_elem.tag_name)
     53 
     54 
     55 class Item(object):
     56   """A list item web element."""
     57   def __init__(self, elem):
     58     self._elem = elem
     59 
     60   def Remove(self, driver):
     61     button = self._elem.find_element_by_xpath('./button')
     62     ActionChains(driver).move_to_element(button).click().perform()
     63 
     64 
     65 class TextFieldsItem(Item):
     66   """An item consisting only of text fields."""
     67   def _GetFields(self):
     68     """Returns the text fields list."""
     69     return self._elem.find_elements_by_tag_name('input')
     70 
     71   def Set(self, values):
     72     """Sets the value(s) of the item's text field(s).
     73 
     74     Args:
     75       values: The new value or the list of the new values of the fields.
     76     """
     77     field_list = self._GetFields()
     78     if len(field_list) > 1:
     79       assert type(values) == types.ListType, \
     80           """The values must be a list for a HTML list that has multi-field
     81           items. '%s' should be in a list.""" % values
     82       value_list = values
     83     else:
     84       value_list = [values]
     85 
     86     assert len(field_list) == len(value_list), \
     87         """The item to be added must have the same number of fields as an item
     88         in the HTML list. Given item '%s' should have %s fields.""" % (
     89             value_list, len(field_list))
     90     for field, value in zip(field_list, value_list):
     91       field.clear()
     92       field.send_keys(value)
     93     field_list[-1].send_keys('\n') # press enter on the last field.
     94 
     95   def Get(self):
     96     """Returns the list of the text field values."""
     97     return map(lambda f: f.get_attribute('value'), self._GetFields())
     98 
     99 
    100 class TextField(object):
    101   """A text field web element."""
    102   def __init__(self, elem):
    103     self._elem = elem
    104 
    105   def Set(self, value):
    106     """Sets the value of the text field.
    107 
    108     Args:
    109       value: The new value of the field.
    110     """
    111     self._elem.clear()
    112     self._elem.send_keys(value)
    113 
    114   def Get(self):
    115     """Returns the value of the text field."""
    116     return self._elem.get_attribute('value')
    117 
    118 
    119 class List(object):
    120   """A web element that holds a list of items."""
    121 
    122   def __init__(self, driver, elem, item_class=Item):
    123     """item element is an element in the HTML list.
    124     item class is the class of item the list holds."""
    125     self._driver = driver
    126     self._elem = elem
    127     self._item_class = item_class
    128 
    129   def RemoveAll(self):
    130     """Removes all items from the list.
    131 
    132     In the loop the removal of an elem renders the remaining elems of the list
    133     invalid. After each item is removed, GetItems() is called.
    134     """
    135     for i in range(len(self.GetItems())):
    136       self.GetItems()[0].Remove(self._driver)
    137 
    138   def GetItems(self):
    139     """Returns all the items that are in the list."""
    140     items = self._GetItemElems()
    141     return map(lambda x: self._item_class(x), items)
    142 
    143   def GetSize(self):
    144     """Returns the number of items in the list."""
    145     return len(self._GetItemElems())
    146 
    147   def _GetItemElems(self):
    148     return self._elem.find_elements_by_xpath('.//*[@role="listitem"]')
    149 
    150 
    151 class DynamicList(List):
    152   """A web element that holds a dynamic list of items of text fields.
    153 
    154   Terminology:
    155     item element: an element in the HTML list item.
    156     item_class: the class of item the list holds
    157     placeholder: the last item element in the list, which is not committed yet
    158 
    159   The user can add new items to the list by typing in the placeholder item.
    160   When a user presses enter or focuses something else, the placeholder item
    161   is committed and a new placeholder is created. An item may contain 1 or
    162   more text fields.
    163   """
    164 
    165   def __init__(self, driver, elem, item_class=TextFieldsItem):
    166     return super(DynamicList, self).__init__(
    167         driver, elem, item_class=item_class)
    168 
    169   def GetPlaceholderItem(self):
    170     return self.GetItems()[-1]
    171 
    172   def GetCommittedItems(self):
    173     """Returns all the items that are in the list, except the placeholder."""
    174     return map(lambda x: self._item_class(x), self._GetCommittedItemElems())
    175 
    176   def GetSize(self):
    177     """Returns the number of items in the list, excluding the placeholder."""
    178     return len(self._GetCommittedItemElems())
    179 
    180   def _GetCommittedItemElems(self):
    181     return self._GetItemElems()[:-1]
    182 
    183   def _GetPlaceholderElem(self):
    184     return self._GetItemElems()[-1]
    185 
    186 
    187 class AutofillEditAddressDialog(object):
    188   """The overlay for editing an autofill address."""
    189 
    190   _URL = 'chrome://settings-frame/autofillEditAddress'
    191 
    192   @staticmethod
    193   def FromNavigation(driver):
    194     """Creates an instance of the dialog by navigating directly to it."""
    195     driver.get(AutofillEditAddressDialog._URL)
    196     return AutofillEditAddressDialog(driver)
    197 
    198   def __init__(self, driver):
    199     self.driver = driver
    200     assert self._URL == driver.current_url
    201     self.dialog_elem = driver.find_element_by_id(
    202         'autofill-edit-address-overlay')
    203 
    204   def Fill(self, names=None, addr_line_1=None, city=None, state=None,
    205            postal_code=None, country_code=None, phones=None):
    206     """Fills in the given data into the appropriate fields.
    207 
    208     If filling into a text field, the given value will replace the current one.
    209     If filling into a list, the values will be added after all items are
    210     deleted.
    211 
    212     Note: 'names', in the new autofill UI, is an array of full names. A full
    213       name is an array of first, middle, last names. Example:
    214         names=[['Joe', '', 'King'], ['Fred', 'W', 'Michno']]
    215 
    216     Args:
    217       names: List of names; each name should be [first, middle, last].
    218       addr_line_1: First line in the address.
    219       city: City.
    220       state: State.
    221       postal_code: Postal code (zip code for US).
    222       country_code: Country code (e.g., US or FR).
    223       phones: List of phone numbers.
    224     """
    225     id_dict = {'addr-line-1': addr_line_1,
    226                'city': city,
    227                'state': state,
    228                'postal-code': postal_code}
    229     for id, value in id_dict.items():
    230       if value is not None:
    231         TextField(self.dialog_elem.find_element_by_id(id)).Set(value)
    232 
    233     list_id_dict = {'full-name-list': names,
    234                     'phone-list': phones}
    235     for list_id, values in list_id_dict.items():
    236       if values is not None:
    237         list = DynamicList(self.driver,
    238                            self.dialog_elem.find_element_by_id(list_id))
    239         list.RemoveAll()
    240         for value in values:
    241           list.GetPlaceholderItem().Set(value)
    242 
    243     if country_code is not None:
    244       self.dialog_elem.find_element_by_xpath(
    245           './/*[@id="country"]/*[@value="%s"]' % country_code).click()
    246 
    247   def GetStateLabel(self):
    248     """Returns the label used for the state text field."""
    249     return self.dialog_elem.find_element_by_id('state-label').text
    250 
    251   def GetPostalCodeLabel(self):
    252     """Returns the label used for the postal code text field."""
    253     return self.dialog_elem.find_element_by_id('postal-code-label').text
    254 
    255   def GetPhones(self):
    256     """Returns a list of the phone numbers in the phones list."""
    257     list = DynamicList(
    258         self.driver, self.dialog_elem.find_element_by_id('phone-list'))
    259     return [item.Get()[0] for item in list.GetCommittedItems()]
    260 
    261 
    262 class ContentTypes(object):
    263   COOKIES = 'cookies'
    264   IMAGES = 'images'
    265   JAVASCRIPT = 'javascript'
    266   HANDLERS = 'handlers'
    267   PLUGINS = 'plugins'
    268   POPUPS = 'popups'
    269   GEOLOCATION = 'location'
    270   NOTIFICATIONS = 'notifications'
    271   PASSWORDS = 'passwords'
    272 
    273 
    274 class Behaviors(object):
    275   ALLOW = 'allow'
    276   SESSION_ONLY = 'session_only'
    277   ASK = 'ask'
    278   BLOCK = 'block'
    279 
    280 
    281 class ContentSettingsPage(object):
    282   """The overlay for managing exceptions on the Content Settings page."""
    283 
    284   _URL = 'chrome://settings-frame/content'
    285 
    286   @staticmethod
    287   def FromNavigation(driver):
    288     """Creates an instance of the dialog by navigating directly to it."""
    289     driver.get(ContentSettingsPage._URL)
    290     return ContentSettingsPage(driver)
    291 
    292   def __init__(self, driver):
    293     assert self._URL == driver.current_url
    294     self.page_elem = driver.find_element_by_id(
    295         'content-settings-page')
    296 
    297   def SetContentTypeOption(self, content_type, option):
    298     """Set the option for the specified content type.
    299 
    300     Args:
    301       content_type: The content type to manage.
    302       option: The option to allow, deny or ask.
    303     """
    304     self.page_elem.find_element_by_xpath(
    305         './/*[@name="%s"][@value="%s"]' % (content_type, option)).click()
    306 
    307 
    308 class ManageExceptionsPage(object):
    309   """The overlay for the content exceptions page."""
    310 
    311   @staticmethod
    312   def FromNavigation(driver, content_type):
    313     """Creates an instance of the dialog by navigating directly to it.
    314 
    315     Args:
    316       driver: The remote WebDriver instance to manage some content type.
    317       content_type: The content type to manage.
    318     """
    319     content_url = 'chrome://settings-frame/contentExceptions#%s' % content_type
    320     driver.get(content_url)
    321     return ManageExceptionsPage(driver, content_type)
    322 
    323   def __init__(self, driver, content_type):
    324     self._list_elem = driver.find_element_by_xpath(
    325         './/*[@id="content-settings-exceptions-area"]'
    326         '//*[@contenttype="%s"]//list[@role="list"]'
    327         '[@class="settings-list"]' % content_type)
    328     self._driver = driver
    329     self._content_type = content_type
    330     try:
    331       self._incognito_list_elem = driver.find_element_by_xpath(
    332           './/*[@id="content-settings-exceptions-area"]'
    333           '//*[@contenttype="%s"]//div[not(@hidden)]'
    334           '//list[@mode="otr"][@role="list"]'
    335           '[@class="settings-list"]' % content_type)
    336     except selenium.common.exceptions.NoSuchElementException:
    337       self._incognito_list_elem = None
    338 
    339   def _AssertIncognitoAvailable(self):
    340     if not self._incognito_list_elem:
    341       raise AssertionError(
    342           'Incognito settings in "%s" content page not available'
    343           % self._content_type)
    344 
    345   def _GetExceptionList(self, incognito):
    346     if not incognito:
    347       list_elem = self._list_elem
    348     else:
    349       list_elem = self._incognito_list_elem
    350     return DynamicList(self._driver, list_elem)
    351 
    352   def _GetPatternList(self, incognito):
    353     if not incognito:
    354       list_elem = self._list_elem
    355     else:
    356       list_elem = self._incognito_list_elem
    357     pattern_list = [p.text for p in
    358         list_elem.find_elements_by_xpath(
    359             './/*[contains(@class, "exception-pattern")]'
    360             '//*[@class="static-text"]')]
    361     return pattern_list
    362 
    363   def AddNewException(self, pattern, behavior, incognito=False):
    364     """Add a new pattern and behavior to the Exceptions page.
    365 
    366     Args:
    367       pattern: Hostname pattern string.
    368       behavior: Setting for the hostname pattern (Allow, Block, Session Only).
    369       incognito: Incognito list box. Display to false.
    370 
    371     Raises:
    372       AssertionError when an exception cannot be added on the content page.
    373     """
    374     if incognito:
    375       self._AssertIncognitoAvailable()
    376       list_elem = self._incognito_list_elem
    377     else:
    378       list_elem = self._list_elem
    379     # Select behavior first.
    380     try:
    381       list_elem.find_element_by_xpath(
    382           './/*[@class="exception-setting"]'
    383           '[not(@displaymode)]//option[@value="%s"]'
    384              % behavior).click()
    385     except selenium.common.exceptions.NoSuchElementException:
    386       raise AssertionError(
    387           'Adding new exception not allowed in "%s" content page'
    388           % self._content_type)
    389     # Set pattern now.
    390     self._GetExceptionList(incognito).GetPlaceholderItem().Set(pattern)
    391 
    392   def DeleteException(self, pattern, incognito=False):
    393     """Delete the exception for the selected hostname pattern.
    394 
    395     Args:
    396       pattern: Hostname pattern string.
    397       incognito: Incognito list box. Default to false.
    398     """
    399     if incognito:
    400       self._AssertIncognitoAvailable()
    401     list = self._GetExceptionList(incognito)
    402     items = filter(lambda item: item.Get()[0] == pattern,
    403                    list.GetComittedItems())
    404     map(lambda item: item.Remove(self._driver), items)
    405 
    406   def GetExceptions(self, incognito=False):
    407     """Returns a dictionary of {pattern: behavior}.
    408 
    409     Example: {'file:///*': 'block'}
    410 
    411     Args:
    412       incognito: Incognito list box. Default to false.
    413     """
    414     if incognito:
    415       self._AssertIncognitoAvailable()
    416       list_elem = self._incognito_list_elem
    417     else:
    418       list_elem = self._list_elem
    419     pattern_list = self._GetPatternList(incognito)
    420     behavior_list = list_elem.find_elements_by_xpath(
    421         './/*[@role="listitem"][@class="deletable-item"]'
    422         '//*[@class="exception-setting"][@displaymode="static"]')
    423     assert len(pattern_list) == len(behavior_list), \
    424            'Number of patterns does not match the behaviors.'
    425     return dict(zip(pattern_list, [b.text.lower() for b in behavior_list]))
    426 
    427   def GetBehaviorForPattern(self, pattern, incognito=False):
    428     """Returns the behavior for a given pattern on the Exceptions page.
    429 
    430     Args:
    431       pattern: Hostname pattern string.
    432       incognito: Incognito list box. Default to false.
    433      """
    434     if incognito:
    435       self._AssertIncognitoAvailable()
    436     assert self.GetExceptions(incognito).has_key(pattern), \
    437            'No displayed host name matches pattern "%s"' % pattern
    438     return self.GetExceptions(incognito)[pattern]
    439 
    440   def SetBehaviorForPattern(self, pattern, behavior, incognito=False):
    441     """Set the behavior for the selected pattern on the Exceptions page.
    442 
    443     Args:
    444       pattern: Hostname pattern string.
    445       behavior: Setting for the hostname pattern (Allow, Block, Session Only).
    446       incognito: Incognito list box. Default to false.
    447 
    448     Raises:
    449       AssertionError when the behavior cannot be changed on the content page.
    450     """
    451     if incognito:
    452       self._AssertIncognitoAvailable()
    453       list_elem = self._incognito_list_elem
    454     else:
    455       list_elem = self._list_elem
    456     pattern_list = self._GetPatternList(incognito)
    457     listitem_list = list_elem.find_elements_by_xpath(
    458         './/*[@role="listitem"][@class="deletable-item"]')
    459     pattern_listitem_dict = dict(zip(pattern_list, listitem_list))
    460     # Set focus to appropriate listitem.
    461     listitem_elem = pattern_listitem_dict[pattern]
    462     listitem_elem.click()
    463     # Set behavior.
    464     try:
    465       listitem_elem.find_element_by_xpath(
    466           './/option[@value="%s"]' % behavior).click()
    467     except selenium.common.exceptions.ElementNotVisibleException:
    468       raise AssertionError(
    469           'Changing the behavior is invalid for pattern '
    470           '"%s" in "%s" content page' % (behavior, self._content_type))
    471     # Send enter key.
    472     pattern_elem = listitem_elem.find_element_by_tag_name('input')
    473     pattern_elem.send_keys('\n')
    474 
    475 
    476 class RestoreOnStartupType(object):
    477   NEW_TAB_PAGE = 5
    478   RESTORE_SESSION = 1
    479   RESTORE_URLS = 4
    480 
    481 
    482 class BasicSettingsPage(object):
    483   """The basic settings page."""
    484   _URL = 'chrome://settings-frame/settings'
    485 
    486   @staticmethod
    487   def FromNavigation(driver):
    488     """Creates an instance of BasicSetting page by navigating to it."""
    489     driver.get(BasicSettingsPage._URL)
    490     return BasicSettingsPage(driver)
    491 
    492   def __init__(self, driver):
    493     self._driver = driver
    494     assert self._URL == driver.current_url
    495 
    496   def SetOnStartupOptions(self, on_startup_option):
    497     """Set on-startup options.
    498 
    499     Args:
    500       on_startup_option: option types for on start up settings.
    501 
    502     Raises:
    503       AssertionError when invalid startup option type is provided.
    504     """
    505     if on_startup_option == RestoreOnStartupType.NEW_TAB_PAGE:
    506       startup_option_elem = self._driver.find_element_by_id('startup-newtab')
    507     elif on_startup_option == RestoreOnStartupType.RESTORE_SESSION:
    508       startup_option_elem = self._driver.find_element_by_id(
    509           'startup-restore-session')
    510     elif on_startup_option == RestoreOnStartupType.RESTORE_URLS:
    511       startup_option_elem = self._driver.find_element_by_id(
    512           'startup-show-pages')
    513     else:
    514       raise AssertionError('Invalid value for restore start up option!')
    515     startup_option_elem.click()
    516 
    517   def _GoToStartupSetPages(self):
    518     self._driver.find_element_by_id('startup-set-pages').click()
    519 
    520   def _FillStartupURL(self, url):
    521     list = DynamicList(self._driver, self._driver.find_element_by_id(
    522                        'startupPagesList'))
    523     list.GetPlaceholderItem().Set(url + '\n')
    524 
    525   def AddStartupPage(self, url):
    526     """Add a startup URL.
    527 
    528     Args:
    529       url: A startup url.
    530     """
    531     self._GoToStartupSetPages()
    532     self._FillStartupURL(url)
    533     self._driver.find_element_by_id('startup-overlay-confirm').click()
    534     self._driver.get(self._URL)
    535 
    536   def UseCurrentPageForStartup(self, title_list):
    537     """Use current pages and verify page url show up in settings.
    538 
    539     Args:
    540       title_list: startup web page title list.
    541     """
    542     self._GoToStartupSetPages()
    543     self._driver.find_element_by_id('startupUseCurrentButton').click()
    544     self._driver.find_element_by_id('startup-overlay-confirm').click()
    545     def is_current_page_visible(driver):
    546       title_elem_list = driver.find_elements_by_xpath(
    547           '//*[contains(@class, "title")][text()="%s"]' % title_list[0])
    548       if len(title_elem_list) == 0:
    549         return False
    550       return True
    551     WebDriverWait(self._driver, 10).until(is_current_page_visible)
    552     self._driver.get(self._URL)
    553 
    554   def VerifyStartupURLs(self, title_list):
    555     """Verify saved startup URLs appear in set page UI.
    556 
    557     Args:
    558       title_list: A list of startup page title.
    559 
    560     Raises:
    561       AssertionError when start up URLs do not appear in set page UI.
    562     """
    563     self._GoToStartupSetPages()
    564     for i in range(len(title_list)):
    565       try:
    566         self._driver.find_element_by_xpath(
    567             '//*[contains(@class, "title")][text()="%s"]' % title_list[i])
    568       except selenium.common.exceptions.NoSuchElementException:
    569         raise AssertionError("Current page %s did not appear as startup page."
    570             % title_list[i])
    571     self._driver.find_element_by_id('startup-overlay-cancel').click()
    572 
    573   def CancelStartupURLSetting(self, url):
    574     """Cancel start up URL settings.
    575 
    576     Args:
    577       url: A startup url.
    578     """
    579     self._GoToStartupSetPages()
    580     self._FillStartupURL(url)
    581     self._driver.find_element_by_id('startup-overlay-cancel').click()
    582     self._driver.get(self._URL)
    583 
    584 
    585 class PasswordsSettings(object):
    586   """The overlay for managing passwords on the Content Settings page."""
    587 
    588   _URL = 'chrome://settings-frame/passwords'
    589 
    590   class PasswordsItem(Item):
    591     """A list of passwords item web element."""
    592     def _GetFields(self):
    593       """Returns the field list element."""
    594       return self._elem.find_elements_by_xpath('./div/*')
    595 
    596     def GetSite(self):
    597       """Returns the site field value."""
    598       return self._GetFields()[0].text
    599 
    600     def GetUsername(self):
    601       """Returns the username field value."""
    602       return self._GetFields()[1].text
    603 
    604 
    605   @staticmethod
    606   def FromNavigation(driver):
    607     """Creates an instance of the dialog by navigating directly to it.
    608 
    609     Args:
    610       driver: The remote WebDriver instance to manage some content type.
    611     """
    612     driver.get(PasswordsSettings._URL)
    613     return PasswordsSettings(driver)
    614 
    615   def __init__(self, driver):
    616     self._driver = driver
    617     assert self._URL == driver.current_url
    618     list_elem = driver.find_element_by_id('saved-passwords-list')
    619     self._items_list = List(self._driver, list_elem, self.PasswordsItem)
    620 
    621   def DeleteItem(self, url, username):
    622     """Deletes a line entry in Passwords Content Settings.
    623 
    624     Args:
    625       url: The URL string as it appears in the UI.
    626       username: The username string as it appears in the second column.
    627     """
    628     for password_item in self._items_list.GetItems():
    629       if (password_item.GetSite() == url and
    630           password_item.GetUsername() == username):
    631         password_item.Remove(self._driver)
    632 
    633 
    634 class CookiesAndSiteDataSettings(object):
    635   """The overlay for managing cookies on the Content Settings page."""
    636 
    637   _URL = 'chrome://settings-frame/cookies'
    638 
    639   @staticmethod
    640   def FromNavigation(driver):
    641     """Creates an instance of the dialog by navigating directly to it.
    642 
    643     Args:
    644       driver: The remote WebDriver instance for managing content type.
    645     """
    646     driver.get(CookiesAndSiteDataSettings._URL)
    647     return CookiesAndSiteDataSettings(driver)
    648 
    649   def __init__(self, driver):
    650     self._driver = driver
    651     assert self._URL == driver.current_url
    652     self._list_elem = driver.find_element_by_id('cookies-list')
    653 
    654   def GetSiteNameList(self):
    655     """Returns a list of the site names.
    656 
    657     This is a public function since the test needs to check if the site is
    658     deleted.
    659     """
    660     site_list = [p.text for p in
    661                  self._list_elem.find_elements_by_xpath(
    662                      './/*[contains(@class, "deletable-item")]'
    663                      '//div[@class="cookie-site"]')]
    664     return site_list
    665 
    666   def _GetCookieNameList(self):
    667     """Returns a list where each item is the list of cookie names of each site.
    668 
    669     Example: site1 | cookie1 cookie2
    670              site2 | cookieA
    671              site3 | cookieA cookie1 cookieB
    672 
    673     Returns:
    674       A cookie names list such as:
    675       [ ['cookie1', 'cookie2'], ['cookieA'], ['cookieA', 'cookie1', 'cookieB'] ]
    676     """
    677     cookie_name_list = []
    678     for elem in self._list_elem.find_elements_by_xpath(
    679         './/*[@role="listitem"]'):
    680       elem.click()
    681       cookie_name_list.append([c.text for c in
    682             elem.find_elements_by_xpath('.//div[@class="cookie-item"]')])
    683     return cookie_name_list
    684 
    685   def DeleteSiteData(self, site):
    686     """Delete a site entry with its cookies in cookies content settings.
    687 
    688     Args:
    689       site: The site string as it appears in the UI.
    690     """
    691     delete_button_list = self._list_elem.find_elements_by_class_name(
    692         'row-delete-button')
    693     site_list = self.GetSiteNameList()
    694     for i in range(len(site_list)):
    695       if site_list[i] == site:
    696         # Highlight the item so the close button shows up, then delete button
    697         # shows up, then click on the delete button.
    698         ActionChains(self._driver).move_to_element(
    699             delete_button_list[i]).click().perform()
    700