1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import logging 7import os 8import pickle 9import re 10import simplejson 11 12import pyauto_functional # Must be imported before pyauto 13import pyauto 14import test_utils 15from selenium.webdriver.common.keys import Keys 16from selenium.webdriver.common.action_chains import ActionChains 17from webdriver_pages import settings 18 19 20class AutofillTest(pyauto.PyUITest): 21 """Tests that autofill UI works correctly. Also contains a manual test for 22 the crowdsourcing server.""" 23 24 def setUp(self): 25 pyauto.PyUITest.setUp(self) 26 self._driver = self.NewWebDriver() 27 28 def AutofillCrowdsourcing(self): 29 """Test able to send POST request of web form to Autofill server. 30 31 The Autofill server processes the data offline, so it can take a few days 32 for the result to be detectable. Manual verification is required. 33 """ 34 # HTML file needs to be run from a specific http:// url to be able to verify 35 # the results a few days later by visiting the same url. 36 url = 'http://www.corp.google.com/~dyu/autofill/crowdsourcing-test.html' 37 # Autofill server captures 2.5% of the data posted. 38 # Looping 1000 times is a safe minimum to exceed the server's threshold or 39 # noise. 40 for i in range(1000): 41 fname = 'David' 42 lname = 'Yu' 43 email = 'david.yu@gmail.com' 44 # Submit form to collect crowdsourcing data for Autofill. 45 self.NavigateToURL(url, 0, 0) 46 profile = {'fn': fname, 'ln': lname, 'em': email} 47 js = ''.join(['document.getElementById("%s").value = "%s";' % 48 (key, value) for key, value in profile.iteritems()]) 49 js += 'document.getElementById("testform").submit();' 50 self.ExecuteJavascript(js) 51 52 def _SelectOptionXpath(self, value): 53 """Returns an xpath query used to select an item from a dropdown list. 54 Args: 55 value: Option selected for the drop-down list field. 56 57 Returns: 58 The value of the xpath query. 59 """ 60 return '//option[@value="%s"]' % value 61 62 def testPostalCodeAndStateLabelsBasedOnCountry(self): 63 """Verify postal code and state labels based on selected country.""" 64 data_file = os.path.join(self.DataDir(), 'autofill', 'functional', 65 'state_zip_labels.txt') 66 test_data = simplejson.loads(open(data_file).read()) 67 68 page = settings.AutofillEditAddressDialog.FromNavigation(self._driver) 69 # Initial check of State and ZIP labels. 70 self.assertEqual('State', page.GetStateLabel()) 71 self.assertEqual('ZIP code', page.GetPostalCodeLabel()) 72 73 for country_code in test_data: 74 page.Fill(country_code=country_code) 75 76 # Compare postal code labels. 77 actual_postal_label = page.GetPostalCodeLabel() 78 self.assertEqual( 79 test_data[country_code]['postalCodeLabel'], 80 actual_postal_label, 81 msg=('Postal code label "%s" does not match Country "%s"' % 82 (actual_postal_label, country_code))) 83 84 # Compare state labels. 85 actual_state_label = page.GetStateLabel() 86 self.assertEqual( 87 test_data[country_code]['stateLabel'], 88 actual_state_label, 89 msg=('State label "%s" does not match Country "%s"' % 90 (actual_state_label, country_code))) 91 92 def testNoDuplicatePhoneNumsInPrefs(self): 93 """Test duplicate phone numbers entered in prefs are removed.""" 94 page = settings.AutofillEditAddressDialog.FromNavigation(self._driver) 95 non_duplicates = ['111-1111', '222-2222'] 96 duplicates = ['111-1111'] 97 page.Fill(phones=non_duplicates + duplicates) 98 self.assertEqual(non_duplicates, page.GetPhones(), 99 msg='Duplicate phone number in prefs unexpectedly saved.') 100 101 def testDisplayLineItemForEntriesWithNoCCNum(self): 102 """Verify Autofill creates a line item for CC entries with no CC number.""" 103 self.NavigateToURL('chrome://settings-frame/autofillEditCreditCard') 104 self._driver.find_element_by_id('name-on-card').send_keys('Jane Doe') 105 query_month = self._SelectOptionXpath('12') 106 query_year = self._SelectOptionXpath('2014') 107 self._driver.find_element_by_id('expiration-month').find_element_by_xpath( 108 query_month).click() 109 self._driver.find_element_by_id('expiration-year').find_element_by_xpath( 110 query_year).click() 111 self._driver.find_element_by_id( 112 'autofill-edit-credit-card-apply-button').click() 113 # Refresh the page to ensure the UI is up-to-date. 114 self._driver.refresh() 115 list_entry = self._driver.find_element_by_class_name('autofill-list-item') 116 self.assertTrue(list_entry.is_displayed) 117 self.assertEqual('Jane Doe', list_entry.text, 118 msg='Saved CC line item not same as what was entered.') 119 120 def _GetElementList(self, container_elem, fields_to_select): 121 """Returns all sub elements of specific characteristics. 122 123 Args: 124 container_elem: An element that contains other elements. 125 fields_to_select: A list of fields to select with strings that 126 help create an xpath string, which in turn identifies 127 the elements needed. 128 For example: ['input', 'button'] 129 ['div[@id]', 'button[@disabled]'] 130 ['*[class="example"]'] 131 132 Returns: 133 List of all subelements found in the container element. 134 """ 135 self.assertTrue(fields_to_select, msg='No fields specified for selection.') 136 fields_to_select = ['.//' + field for field in fields_to_select] 137 xpath_arg = ' | '.join(fields_to_select) 138 field_elems = container_elem.find_elements_by_xpath(xpath_arg) 139 return field_elems 140 141 def _GetElementInfo(self, element): 142 """Returns visual comprehensive info about an element. 143 144 This function identifies the text of the correspoinding label when tab 145 ordering fails. 146 This info consists of: 147 The labels, buttons, ids, placeholder attribute values, or the element id. 148 149 Args: 150 element: The target element. 151 152 Returns: 153 A string that identifies the element in the page. 154 """ 155 element_info = '' 156 if element.tag_name == 'button': 157 element_info = element.text 158 element_info = (element_info or element.get_attribute('id') or 159 element.get_attribute('placeholder') or 160 element.get_attribute('class') or element.id) 161 return '%s: %s' % (element.tag_name, element_info) 162 163 def _LoadPageAndGetFieldList(self): 164 """Navigate to autofillEditAddress page and finds the elements with focus. 165 166 These elements are of input, select, and button types. 167 168 Returns: 169 A list with all elements that can receive focus. 170 """ 171 url = 'chrome://settings-frame/autofillEditAddress' 172 self._driver.get(url) 173 container_elem = self._driver.find_element_by_id( 174 'autofill-edit-address-overlay') 175 # The container element contains input, select and button fields. Some of 176 # the buttons are disabled so they are ignored. 177 field_list = self._GetElementList(container_elem, 178 ['input', 'select', 179 'button[not(@disabled)]']) 180 self.assertTrue(field_list, 'No fields found in "%s".' % url) 181 return field_list 182 183 def testTabOrderForEditAddress(self): 184 """Verify the TAB ordering for Edit Address page is correct.""" 185 tab_press = ActionChains(self._driver).send_keys(Keys.TAB) 186 field_list = self._LoadPageAndGetFieldList() 187 188 # Creates a dictionary where a field key returns the value of the next field 189 # in the field list. The last field of the field list is mapped to the first 190 # field of the field list. 191 field_nextfield_dict = dict( 192 zip(field_list, field_list[1:] + field_list[:1])) 193 194 # Wait until a field of |field_list| has received the focus. 195 self.WaitUntil(lambda: 196 self._driver.switch_to_active_element().id in 197 [f.id for f in field_list]) 198 # The first field is expected to receive the focus. 199 self.assertEqual(self._driver.switch_to_active_element().id, 200 field_list[0].id, 201 msg='The first field did not receive tab focus.') 202 for field in field_list: 203 tab_press.perform() 204 # Wait until a field of |field_list|, other than the current field, has 205 # received the focus. 206 self.WaitUntil(lambda: 207 self._driver.switch_to_active_element().id != field.id and 208 self._driver.switch_to_active_element().id in 209 [f.id for f in field_list]) 210 211 self.assertEqual(self._driver.switch_to_active_element().id, 212 field_nextfield_dict[field].id, 213 msg=('The TAB ordering is broken. Previous field: "%s"\n' 214 'Field expected to receive focus: "%s"\n' 215 'Field that received focus instead: "%s"') 216 % (self._GetElementInfo(field), 217 self._GetElementInfo(field_nextfield_dict[field]), 218 self._GetElementInfo( 219 self._driver.switch_to_active_element()))) 220 221 222if __name__ == '__main__': 223 pyauto_functional.Main() 224