Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: chrome/test/functional/webdriver_pages/settings.py

Issue 222873002: Remove pyauto tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: sync Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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()
OLDNEW
« no previous file with comments | « chrome/test/functional/tracing/tracing_smoke_test.py ('k') | chrome/test/functional/webpagereplay.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698