Source code for cfme.web_ui.tabstrip

# -*- coding: utf-8 -*-
""" The tab strip manipulation which appears in Configure / Configuration and possibly other pages.

Usage:

    import cfme.web_ui.tabstrip as tabs
    tabs.select_tab("Authentication")
    print(is_tab_selected("Authentication"))
    print(get_selected_tab())

"""
from collections import Mapping, OrderedDict

import cfme.fixtures.pytest_selenium as sel
from cfme import web_ui
from cfme.utils.log import logger
from cfme.utils.pretty import Pretty

# Entry point
# There have been different types of the entry points throughout the history, sometimes even
# different versions in one build.
_entry_loc = "|".join([
    "//div[contains(@class, 'ui-tabs')]",
    "//ul[contains(@class, 'nav-tabs')]",
    "//ul[contains(@class, 'ui-tabs-nav') or @class='tab2' or @class='tab3']",
    "//ul[@id='tab' and @class='tab']"])


def _root():
    """ Returns the div element encapsulating whole tab strip as an entry point.

    Returns: :py:class:`list` of :py:class:`cfme.fixtures.pytest_selenium.WebElement`.
    """
    return sel.elements(_entry_loc)


[docs]def get_all_tabs(): """ Return list of all tabs present. Returns: :py:class:`list` of :py:class:`str` Displayed names. """ return [opt.text.strip().encode("utf-8") for opt in sel.elements(".//li/a", root=_root())]
[docs]def get_selected_tab(): """ Return currently selected tab. Returns: :py:class:`str` Displayed name """ return sel.element( ".//li[@aria-selected='true' or contains(@class, 'active')]/a", root=_root())\ .text\ .strip()\ .encode("utf-8")
[docs]def is_tab_element_selected(element): """ Determine whether the passed element is selected. This function takes the element, climbs to its parent and looks whether the aria-selected attribute contains true. If yes, element is selected. Args: element: WebElement with the link (a) Returns: :py:class:`bool` """ aria = sel.element("..", root=element).get_attribute("aria-selected") if aria is not None: return "true" in aria.lower() else: return sel.element("..", root=element)\ .get_attribute("class")\ .lower() in {"active", "active-single"}
[docs]def is_tab_selected(ident_string): """ Determine whether the element identified by passed name is selected. Args: ident_string: Identification string (displayed name) of the tab button. Returns: :py:class:`bool` """ return is_tab_element_selected(get_clickable_tab(ident_string))
[docs]def get_clickable_tab(ident_string): """ Returns the relevant tab element that can be clicked on. Args: ident_string: The text diplayed on the tab. """ return sel.element( ".//li/a[contains(normalize-space(text()), '{}')]".format(ident_string), root=_root())
[docs]def select_tab(ident_string): """ Clicks on the tab with text from ident_string. Clicks only if it's not actually selected. Args: ident_string: The text displayed on the tab. """ if not is_tab_selected(ident_string): return sel.click(get_clickable_tab(ident_string))
class _TabStripField(Pretty): """A form field type for use in TabStripForms""" pretty_attrs = ['ident_string', 'arg'] def __init__(self, ident_string, arg, default_when_no_tabs=False): self.ident_string = ident_string self.arg = arg self.default_when_no_tabs = default_when_no_tabs def locate(self): if len(get_all_tabs()) == 0: if self.default_when_no_tabs: # There is no tabstrip and this is the proper "tab" return self.arg else: # A different tab but given the fact that this one is "hidden", bail out raise ValueError('Requested tab {} is not displayed'.format(self.ident_string)) select_tab(self.ident_string) return self.arg def __getattr__(self, name): self.locate() return getattr(self.arg, name) @web_ui.fill.method((_TabStripField, object)) def _fill_tabstrip(tabstrip_field, value): logger.debug(' Navigating to tabstrip %s', tabstrip_field.ident_string) web_ui.fill(tabstrip_field.locate(), value) # In a fight between _TabStripField and object, _TabStripField should win, # since it always delegates back to fill web_ui.fill.prefer((_TabStripField, object), (object, Mapping))
[docs]class TabStripForm(web_ui.Form): """ A class for interacting with tabstrip-contained Form elements on pages. This behaves exactly like a :py:class:`Form`, but is able to deal with form elements being broken up into tabs, accessible via a tab strip. Args: fields: A list of field name/locator tuples (same as Form implementation) tab_fields: A dict with tab names as keys, and each key's value being a list of field name/locator tuples. The ordering of fields within a tab is guaranteed (as it is with the normal Form) but the ordering of tabs is not guaranteed by default. If such ordering is needed, tab_fields can be a ``collections.OrderedDict``. identifying_loc: A locator which should be present if the form is visible. order: If specified, specifies order of the tabs. Can be lower number than number of tabs, remaining values will be complemented. fields_end: Same as fields, but these are appended at the end of generated fields instead. Usage: provisioning_form = web_ui.TabStripForm( tab_fields={ 'Request': [ ('email', Input("requester__owner_email")), ('first_name', Input("requester__owner_first_name")), ('last_name', Input("requester__owner_last_name")), ('notes', '//textarea[@id="requester__request_notes"]'), ], 'Catalog': [ ('instance_name', Input("service__vm_name")), ('instance_description', '//textarea[@id="service__vm_description"]'), ] } ) Each tab's fields will be exposed by their name on the resulting instance just like fields on a Form. Don't use duplicate field names in the ``tab_fields`` dict. Forms can then be filled in like so:: request_info = { 'email': 'your@email.com', 'first_name': 'First', 'last_name': 'Last', 'notes': 'Notes about this request', 'instance_name': 'An instance name', 'instance_description': 'This is my instance!', } web_ui.fill(provisioning_form, request_info) """ def __init__( self, fields=None, tab_fields=None, identifying_loc=None, order=None, fields_end=None): fields = fields or list() new_tab_fields = OrderedDict() flags_per_tab = {} for key, value in tab_fields.iteritems(): if isinstance(key, tuple): field_name, flags = key flags = {f: True for f in flags} else: field_name = key flags = {} new_tab_fields[field_name] = value flags_per_tab[field_name] = flags tab_fields = new_tab_fields if order is None: order = tab_fields.keys() else: order = list(order) if len(order) > len(tab_fields.keys()): raise ValueError("More order items passed than there is in real!") if len(order) < len(tab_fields.keys()): remaining_keys = set(tab_fields.keys()) - set(order) for key in remaining_keys: order.append(key) for tab_ident in order: field = tab_fields[tab_ident] for field_name, field_locator in field: fields.append( (field_name, _TabStripField( tab_ident, field_locator, **flags_per_tab[tab_ident]))) if fields_end is not None: fields.extend(fields_end) super(TabStripForm, self).__init__(fields, identifying_loc)