def create(self, cancel=False): """Create new keypair""" def refresh(): self.provider.refresh_provider_relationships() view.browser.selenium.refresh() view.flush_widget_cache() view = navigate_to(self, 'Add') view.form.fill({'name': self.name, 'public_key': self.public_key, 'provider': self.provider.name}) if cancel: view.form.cancel.click() flash_message = 'Add of new Key Pair was cancelled by the user' else: view.form.add.click() flash_message = VersionPick({ Version.lowest(): 'Creating Key Pair {}'.format(self.name), '5.8': 'Key Pair "{}" created'.format(self.name)}).pick(self.appliance.version) # add/cancel should redirect, new view view = self.create_view(KeyPairAllView) # TODO BZ 1444520 causing ridiculous redirection times after submitting the form wait_for(lambda: view.is_displayed, fail_condition=False, num_sec=120, delay=3, fail_func=lambda: view.flush_widget_cache(), handle_exception=True) view = self.create_view(KeyPairAllView) view.entities.flash.assert_no_error() view.entities.flash.assert_success_message(flash_message)
def pytest_generate_tests(metafunc): """ Build a list of tuples containing (group_name, context) Returns: tuple containing (group_name, context) where group_name is a string and context is ViaUI/SSUI """ appliance = find_appliance(metafunc) parameter_list = [] id_list = [] # TODO: Include SSUI role_access dict and VIASSUI context role_access_ui = VersionPick({ Version.lowest(): role_access_ui_58z, '5.9': role_access_ui_59z, '5.10': role_access_ui_510z }).pick(appliance.version) logger.info('Using the role access dict: %s', role_access_ui) roles_and_context = [( role_access_ui, ViaUI) ] for role_access, context in roles_and_context: for group in role_access.keys(): parameter_list.append((group, role_access, context)) id_list.append('{}-{}'.format(group, context)) metafunc.parametrize('group_name, role_access, context', parameter_list)
def all(self): # containers table has ems_id, join with ext_mgmgt_systems on id for provider name # Then join with container_groups on the id for the pod # TODO Update to use REST API instead of DB queries container_table = self.appliance.db.client['containers'] ems_table = self.appliance.db.client['ext_management_systems'] pod_table = self.appliance.db.client['container_groups'] container_pod_id = ( VersionPick({ Version.lowest(): getattr(container_table, 'container_definition_id', None), '5.9': getattr(container_table, 'container_group_id', None)}) .pick(self.appliance.version)) container_query = ( self.appliance.db.client.session .query(container_table.name, pod_table.name, ems_table.name) .join(ems_table, container_table.ems_id == ems_table.id) .join(pod_table, container_pod_id == pod_table.id)) if self.filters.get('archived'): container_query = container_query.filter(container_table.deleted_on.isnot(None)) if self.filters.get('active'): container_query = container_query.filter(container_table.deleted_on.is_(None)) provider = None # filtered if self.filters.get('provider'): provider = self.filters.get('provider') container_query = container_query.filter(ems_table.name == provider.name) containers = [] for name, pod_name, ems_name in container_query.all(): containers.append( self.instantiate(name=name, pod=pod_name, provider=provider or get_crud_by_name(ems_name))) return containers
def is_displayed(self): title = VersionPicker({ Version.lowest(): '{name} (All VM Templates)'.format(name=self.context['object'].name), '5.10': '{name} (All VM Templates and Images)'.format(name=self.context['object'].name), }).pick(self.extra.appliance.version) return (self.logged_in_as_current_user and self.navigation.currently_selected == ['Compute', 'Infrastructure', 'Providers'] and self.title.text == title)
def ProviderEntity(): # noqa """ Temporary wrapper for Provider Entity during transition to JS based Entity """ return VersionPick({ Version.lowest(): NonJSProviderEntity, '5.9': JSProviderEntity, })
def parent_provider(self): """ Return object of parent cloud provider """ view = navigate_to(self, 'Details') parent_cloud_text = VersionPick({Version.lowest(): 'Parent ems cloud', '5.10': 'Parent Cloud Provider'} ).pick(self.appliance.version) provider_name = view.entities.relationships.get_text_of(parent_cloud_text) return providers.get_crud_by_name(provider_name)
def HostEntity(): # noqa """ Temporary wrapper for Host Entity during transition to JS based Entity """ return VersionPick({ Version.lowest(): NonJSHostEntity, '5.9': JSBaseEntity, })
def before_filling(self): item_type = self.context['object'].provider_type or \ self.context['object'].item_type or 'Generic' if item_type == 'AnsibleTower': item_type = VersionPick({ Version.lowest(): "AnsibleTower", "5.9": "Ansible Tower" }) self.select_item_type.select_by_visible_text(item_type) self.flush_widget_cache()
def delete(self, cancel=False, wait=False): view = navigate_to(self, 'Details') # TODO: get rid of this resolve when widgetastic.core/pull/68 is merged item_name = VersionPick({Version.lowest(): 'Remove this Key Pair', '5.9': 'Remove this Key Pair from Inventory'} ).pick(self.appliance.version) view.toolbar.configuration.item_select(item_name, handle_alert=(not cancel)) # cancel doesn't redirect, confirmation does view.flush_widget_cache() if cancel: view = self.create_view(KeyPairDetailsView) else: view = self.create_view(KeyPairAllView) wait_for(lambda: view.is_displayed, fail_condition=False, num_sec=10, delay=1) # flash message only displayed if it was deleted if not cancel: view.flash.assert_no_error() view.flash.assert_success_message('Delete initiated for 1 Key Pair') if wait: def refresh(): self.provider.refresh_provider_relationships() view.browser.refresh() view.flush_widget_cache() view = navigate_to(self.parent, 'All') wait_for( lambda: self.name in view.entities.all_entity_names, message="Wait keypairs to disappear", fail_condition=True, num_sec=300, delay=5, fail_func=refresh )
def create(self, cancel=False): """Create new keypair""" def refresh(): self.provider.refresh_provider_relationships() view.browser.selenium.refresh() view.flush_widget_cache() view = navigate_to(self, 'Add') view.form.fill({ 'name': self.name, 'public_key': self.public_key, 'provider': self.provider.name }) if cancel: view.form.cancel.click() flash_message = 'Add of new Key Pair was cancelled by the user' else: view.form.add.click() flash_message = VersionPick({ Version.lowest(): 'Creating Key Pair {}'.format(self.name), '5.8': 'Key Pair "{}" created'.format(self.name) }).pick(self.appliance.version) # add/cancel should redirect, new view view = self.create_view(KeyPairAllView) # TODO BZ 1444520 causing ridiculous redirection times after submitting the form wait_for(lambda: view.is_displayed, fail_condition=False, num_sec=120, delay=3, fail_func=lambda: view.flush_widget_cache(), handle_exception=True) view = self.create_view(KeyPairAllView) view.entities.flash.assert_no_error() view.entities.flash.assert_success_message(flash_message)
class retirement(Tab): # noqa # TODO Somehow need to handle a modal window copy_from_provisioning = Button("Copy from provisioning") repository = BootstrapSelect("retirement_repository_id") playbook = BootstrapSelect("retirement_playbook_id") machine_credential = BootstrapSelect( "retirement_machine_credential_id") cloud_type = BootstrapSelect("retirement_cloud_type") cloud_credential = BootstrapSelect("retirement_cloud_credential_id") localhost = Input(id="retirement_inventory_localhost") specify_host_values = Input(id="retirement_inventory_specify") hosts = Input("retirement_inventory") logging_output = BootstrapSelect("retirement_log_output") max_ttl = Input("retirement_execution_ttl") escalate_privilege = BootstrapSwitch("retirement_become_enabled") verbosity = BootstrapSelect("retirement_verbosity") remove_resources = VersionPick({ Version.lowest(): BootstrapSelect("vm.catalogItemModel.retirement_remove_resources"), "5.9": BootstrapSelect( "vm.vm.catalogItemModel.retirement_remove_resources") }) extra_vars = AnsibleExtraVariables(tab="retirement")
class ContainerAllView(ContainerObjectAllBaseView): """Containers All view""" summary = Text(VersionPick({ Version.lowest(): '//h3[normalize-space(.) = {}]'.format(quote('All Containers')), '5.8': '//h1[normalize-space(.) = {}]'.format(quote('Containers')) })) containers = Table(locator="//div[@id='list_grid']//table") @View.nested class Filters(Accordion): # noqa ACCORDION_NAME = "Filters" @View.nested class Navigation(VerticalNavigation): DIV_LINKS_MATCHING = './/div/ul/li/a[contains(text(), {txt})]' def __init__(self, parent, logger=None): VerticalNavigation.__init__(self, parent, '#Container_def_searches', logger=logger) tree = ManageIQTree() @property def is_displayed(self): return self.summary.is_displayed
class ImageRegistryDetailsView(ContainerObjectDetailsBaseView): """Container Image Registries Detail view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Image Registries', '5.9': 'Container Image Registries' })
class MyView(View): widget = TextInput(id=VersionPick({ Version.lowest(): 'nonexisting', '1.0.0': 'input1' }))
class RequestsToolbar(View): """Toolbar on the requests view""" reload = Button(title=VersionPick({ Version.lowest(): 'Reload the current display', '5.9': 'Refresh this page' }))
class TowerExplorerSystemJobTemplatesToolbar(View): reload = Button(title=VersionPick({Version.lowest(): 'Reload current display', '5.9': 'Refresh this page'})) policy = Dropdown('Policy') download = Dropdown('Download') view_selector = View.nested(ItemsToolBarViewSelector)
class RouteAllView(ContainerObjectAllBaseView): """Container Routes All view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Routes', '5.9': 'Container Routes' })
def container_provider_edit_view_class(self): return VersionPick({ Version.lowest(): ContainerProviderEditView, '5.9': ContainerProviderEditViewUpdated })
def view_classes(self): return VersionPick({ Version.lowest(): RetirementView, "5.9": RetirementViewWithOffset })
class PodAllView(ContainerObjectAllBaseView): """Container Pods All view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Pods', '5.9': 'Container Pods' })
class Inputs(View, ClickableMixin): ROOT = './/button[@id="exp_collapse_img"]/i' INDIRECT = True # TODO: This appear to upset the parent lookup combined with ParView @property def is_opened(self): return 'fa-angle-up' in self.browser.classes(self) def child_widget_accessed(self, widget): if not self.is_opened: self.click() @ParametrizedView.nested class inputs(ParametrizedView): # noqa PARAMETERS = ('name', ) ROOT = ParametrizedLocator( '//tr[./td[2]/input[normalize-space(@value)={name|quote}]]') ALL_FIELDS = '//div[@id="inputs_div"]/table//tr/td[2]/input' @cached_property def row_id(self): attr = self.browser.get_attribute( 'id', './/td/input[contains(@id, "fields_name_")]', parent=self) return int(attr.rsplit('_', 1)[-1]) name = Input(locator=ParametrizedLocator( './/td/input[contains(@id, "fields_name_{@row_id}")]')) data_type = Select(locator=ParametrizedLocator( './/td/select[contains(@id, "fields_datatype_{@row_id}")]')) default_value = Input(locator=ParametrizedLocator( './/td/input[contains(@id, "fields_value_{@row_id}")]')) @classmethod def all(cls, browser): results = [] for e in browser.elements(cls.ALL_FIELDS): results.append((browser.get_attribute('value', e), )) return results def delete(self): if self.browser.product_version < '5.10': xpath = './/img[contains(@alt, "Click to delete this")]' else: xpath = './/a/i[contains(@class, "pficon-delete")]' self.browser.click(xpath, parent=self) try: del self.row_id except AttributeError: pass add_field = VersionPick({ Version.lowest(): Text('//img[@alt="Equal green"]'), '5.10': Text('//button//i[contains(@class, "fa-plus")]') }) name = Input(locator='.//td/input[contains(@id, "field_name")]') data_type = Select(locator='.//td/select[contains(@id, "field_datatype")]') default_value = Input( locator='.//td/input[contains(@id, "field_default_value")]') finish_add_field = VersionPick({ Version.lowest(): Text('//img[@alt="Add this entry"]'), '5.10': Text('//a[@title="Add this entry"]') }) def read(self): return self.inputs.read() def fill(self, value): keys = set(value.keys()) value = copy(value) present = {key for key, _ in self.inputs.read().items()} to_delete = present - keys changed = False # Create the new ones for key in keys: if key not in present: new_value = value.pop(key) new_value['name'] = key self.add_field.click() super(Inputs, self).fill(new_value) self.finish_add_field.click() changed = True # Fill the rest as expected if self.inputs.fill(value): changed = True # delete unneeded for key in to_delete: self.inputs(name=key).delete() changed = True return changed
def DatastoreEntity(): # noqa """Temporary wrapper for Datastore Entity during transition to JS based Entity """ return VersionPick({ Version.lowest(): NonJSDatastoreEntity, '5.9': JSDatastoreEntity, })
class MyView(View): widget = TextInput(id=VersionPick({ Version.lowest(): "nonexisting", "1.0.0": "input1" }))
class ReplicatorAllView(ContainerObjectAllBaseView): """Container Replicators All view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Replicators', '5.9': 'Container Replicators' })
def DeploymentRoleEntity(): # noqa """Temporary wrapper for Deployment Role Entity during transition to JS based Entity """ return VersionPick({ Version.lowest(): NonJSDepRoleEntity, '5.9': JSBaseEntity, })
class ReplicatorDetailsView(ContainerObjectDetailsBaseView): """Container Replicators Details view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Replicators', '5.9': 'Container Replicators' })
def test_picking_works_lowest_version(basic_verpick): assert basic_verpick.pick(Version.lowest()) == 0
class ProjectDetailsView(ContainerObjectDetailsBaseView): """Container Projects Detail view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Projects', '5.9': 'Container Projects' })
def step(self): self.prerequisite_view.toolbar.configuration.item_select( VersionPick({ Version.lowest(): 'Add Existing Containers Provider', '5.9': 'Add a new Containers Provider' }).pick(self.obj.appliance.version))
class mytasks(Tab): # noqa TAB_NAME = VersionPick({ Version.lowest(): 'My VM and Container Analysis Tasks', '5.9': 'My Tasks' }) table = Table(table_loc)
def ManageIQTree(tree_id=None): # noqa return VersionPick({ Version.lowest(): DynaTree(tree_id), '5.7.0.1': BootstrapTreeview(tree_id), })
class TestForm(View): table = Table('#withwidgets', column_widgets={ 'Column 2': TextInput(locator='./input'), 'Column 3': VersionPick({ Version.lowest(): TextInput(locator='./input'), '2.0': None})})
class myothertasks(Tab): # noqa TAB_NAME = VersionPick({ '5.9': 'My Tasks', Version.lowest(): 'My Other UI Tasks' }) table = Table(table_loc)
class LoginPage(View): flash = FlashMessages( VersionPick({ Version.lowest(): 'div#flash_text_div', '5.8': '//div[@class="flash_text_div"]' }) ) class details(View): # noqa region = Text('.//p[normalize-space(text())="Region:"]/span') zone = Text('.//p[normalize-space(text())="Zone:"]/span') appliance = Text('.//p[normalize-space(text())="Appliance:"]/span') change_password = Text('.//a[normalize-space(.)="Update password"]') back = Text('.//a[normalize-space(.)="Back"]') username = Input(name='user_name') password = Input(name='user_password') new_password = Input(name='user_new_password') verify_password = Input(name='user_verify_password') login = Button(id='login') def show_update_password(self): if not self.new_password.is_displayed: self.change_password.click() def hide_update_password(self): if self.new_password.is_displayed: self.back.click() def login_admin(self, **kwargs): username = conf.credentials['default']['username'] password = conf.credentials['default']['password'] cred = Credential(principal=username, secret=password) from cfme.configure.access_control import User user = User(credential=cred, name='Administrator') return self.log_in(user, **kwargs) def submit_login(self, method='click_on_login'): if method == 'click_on_login': self.login.click() elif method == 'press_enter_after_password': self.browser.send_keys(Keys.ENTER, self.password) elif method == '_js_auth_fn': self.browser.execute_script('miqAjaxAuth();') else: raise ValueError('Unknown method {}'.format(method)) if self.flash.is_displayed: self.flash.assert_no_error() def log_in(self, user, method='click_on_login'): self.fill({ 'username': user.credential.principal, 'password': user.credential.secret, }) self.submit_login(method) logged_in_view = self.browser.create_view(BaseLoggedInPage) if logged_in_view.logged_in: if user.name is None: name = logged_in_view.current_fullname self.logger.info( 'setting the appliance.user.name to %r because it was not specified', name) user.name = name self.extra.appliance.user = user def update_password( self, username, password, new_password, verify_password=None, method='click_on_login'): self.show_update_password() self.fill({ 'username': username, 'password': password, 'new_password': new_password, 'verify_password': verify_password if verify_password is not None else new_password }) self.submit_login(method) def logged_in_as_user(self, user): return False @property def logged_in_as_current_user(self): return False @property def current_username(self): return None @property def current_fullname(self): return None @property def logged_in(self): return not self.logged_out @property def logged_out(self): return self.username.is_displayed and self.password.is_displayed and self.login.is_displayed @property def is_displayed(self): return self.logged_out
class ExpressionEditor(View, Pretty): """This class enables to embed the expression in a Form. Args: show_func: Function to call to show the expression if there are more of them. """ @View.nested class field_form_view(View): # noqa type = BootstrapSelect("chosen_typ") field = BootstrapSelect("chosen_field") key = BootstrapSelect("chosen_key") value = Input(name="chosen_value") user_input = Input(name="user_input") @View.nested class field_date_form(View): # noqa dropdown_select = BootstrapSelect("chosen_from_1") input_select_date = Calendar(name="miq_date_1_0") input_select_time = BootstrapSelect("miq_time_1_0") @View.nested class count_form_view(View): # noqa type = BootstrapSelect("chosen_typ") count = BootstrapSelect("chosen_count") key = BootstrapSelect("chosen_key") value = Input(name="chosen_value") user_input = Input(name="user_input") @View.nested class tag_form_view(View): # noqa type = BootstrapSelect("chosen_typ") tag = BootstrapSelect("chosen_tag") value = BootstrapSelect("chosen_value") user_input = Input(name="user_input") @View.nested class find_form_view(View): # noqa type = BootstrapSelect("chosen_typ") field = BootstrapSelect("chosen_field") skey = BootstrapSelect("chosen_skey") value = Input(name="chosen_value") check = BootstrapSelect("chosen_check") cfield = BootstrapSelect("chosen_cfield") ckey = BootstrapSelect("chosen_ckey") cvalue = Input(name="chosen_cvalue") @View.nested class registry_form_view(View): # noqa type = BootstrapSelect("chosen_typ") key = Input(name="chosen_regkey") value = Input(name="chosen_regval") operation = BootstrapSelect("chosen_key") contents = Input(name="chosen_value") @View.nested class date_specific_form_view(View): # noqa date = Calendar(name="miq_date_1_0") time = BootstrapSelect("miq_time_1_0") @View.nested class date_relative_form_view(View): # noqa from_ = BootstrapSelect("chosen_from_1") through = BootstrapSelect("chosen_through_1") ROOT = "//div[@id='exp_editor_div']" MAKE_BUTTON = "//span[not(contains(@style,'none'))]//img[@alt='{}']" ATOM_ROOT = "./div[@id='exp_atom_editor_div']" EXPRESSIONS_ROOT = "./fieldset/div" COMMIT = VersionPick({ Version.lowest(): "//img[@alt='Commit expression element changes']", "5.7.1": Button(title="Commit expression element changes"), }) DISCARD = VersionPick({ Version.lowest(): "//img[@alt='Discard expression element changes']", "5.7.1": Button(title="Discard expression element changes"), }) REMOVE = VersionPick({ Version.lowest(): ("//span[not(contains(@style, 'none'))]/" "/img[@alt='Remove this expression element']"), "5.8": Button(title="Remove this expression element"), }) NOT = VersionPick({ Version.lowest(): ("//span[not(contains(@style, 'none'))]" "//img[@alt='Wrap this expression element with a NOT']"), "5.8": Button(title="Wrap this expression element with a NOT"), }) OR = VersionPick({ Version.lowest(): ("//span[not(contains(@style, 'none'))]/" "/img[@alt='OR with a new expression element']"), "5.8": Button(title="OR with a new expression element"), }) AND = VersionPick({ Version.lowest(): ("//span[not(contains(@style, 'none'))]/" "/img[@alt='AND with a new expression element']"), "5.8": Button(title="AND with a new expression element"), }) REDO = VersionPick({ Version.lowest(): "//img[@alt='Redo']", "5.8": Button(title="Redo the last change"), }) UNDO = VersionPick({ Version.lowest(): "//img[@alt='Undo']", "5.8": Button(title="Undo the last change"), }) SELECT_SPECIFIC = "//img[@alt='Click to change to a specific Date/Time format']" SELECT_RELATIVE = "//img[@alt='Click to change to a relative Date/Time format']" pretty_attrs = ['show_loc'] def __init__(self, parent, show_loc=None, logger=None): View.__init__(self, parent, logger=logger) self.show_loc = show_loc def __locator__(self): return self.ROOT def click_undo(self): self.browser.click(self.UNDO) def click_redo(self): self.browser.click(self.REDO) def click_and(self): self.browser.click(self.AND) def click_or(self): self.browser.click(self.OR) def click_not(self): self.browser.click(self.NOT) def click_remove(self): self.browser.click(self.REMOVE) def click_commit(self): self.browser.click(self.COMMIT) def click_discard(self): self.browser.click(self.DISCARD) def click_switch_to_relative(self): self.browser.click(self.SELECT_RELATIVE) def click_switch_to_specific(self): self.browser.click(self.SELECT_SPECIFIC) @property def _atom_root(self): return self.browser.element(self.ATOM_ROOT) @property def _expressions_root(self): return self.browser.element(self.EXPRESSIONS_ROOT) def select_first_expression(self): """There is always at least one (???), so no checking of bounds.""" self.browser.elements("//a[contains(@id,'exp_')]", parent=self._expressions_root)[0].click() def select_expression_by_text(self, text): self.browser.click( "//a[contains(@id,'exp_')][contains(normalize-space(text()),'{}')]" .format(text)) def no_expression_present(self): els = self.browser.elements("//a[contains(@id,'exp_')]", parent=self._expressions_root) if len(els) > 1: return False return els[0].text.strip() == "???" def any_expression_present(self): return not self.no_expression_present() def is_editing(self): try: self.browser.element( "//a[contains(@id,'exp_')][contains(normalize-space(text()),'???')]", parent=self._expressions_root) return True except NoSuchElementException: return False def delete_whole_expression(self): while self.any_expression_present(): self.select_first_expression() self.click_remove() def read(self): """Returns whole expression as represented visually.""" return self._expressions_root.text.encode("utf-8").strip() def enable_editor(self): try: el = self.browser.element(self.show_loc) wait_for(lambda: el.is_displayed, num_sec=2, delay=0.2) el.click() except (TimedOutError, NoSuchElementException): pass def fill(self, expression): if self.show_loc is not None: self.enable_editor() prog = create_program(expression, self) before = self._expressions_root.text.encode("utf-8").strip() prog() after = self._expressions_root.text.encode("utf-8").strip() return before != after def fill_count(self, count=None, key=None, value=None): """ Fills the 'Count of' type of form. If the value is unspecified and we are in the advanced search form (user input), the user_input checkbox will be checked if the value is None. Args: count: Name of the field to compare (Host.VMs, ...). key: Operation to do (=, <, >=, ...). value: Value to check against. Returns: See :py:func:`cfme.web_ui.fill`. """ view = self.count_form_view view.fill(dict(type="Count of", count=count, key=key, value=value)) # In case of advanced search box if view.user_input.is_displayed: user_input = value is None view.user_input.fill(user_input) self.click_commit() def fill_tag(self, tag=None, value=None): """ Fills the 'Tag' type of form. Args: tag: Name of the field to compare. value: Value to check against. """ view = self.tag_form_view view.fill(dict(type="Tag", tag=tag, value=value)) # In case of advanced search box if view.user_input.is_displayed: user_input = value is None view.user_input.fill(user_input) self.click_commit() def fill_registry(self, key=None, value=None, operation=None, contents=None): """ Fills the 'Registry' type of form.""" view = self.registry_form_view view.fill( dict( type="Registry", key=key, value=value, operation=operation, contents=contents, )) self.click_commit() def fill_find(self, field=None, skey=None, value=None, check=None, cfield=None, ckey=None, cvalue=None): view = self.find_form_view view.fill( dict(type="Find", field=field, skey=skey, value=value, check=check, cfield=cfield, ckey=ckey, cvalue=cvalue)) self.click_commit() def fill_field(self, field=None, key=None, value=None): """ Fills the 'Field' type of form. Args: tag: Name of the field to compare (Host.VMs, ...). key: Operation to do (=, <, >=, IS NULL, ...). value: Value to check against. Returns: See :py:func:`cfme.web_ui.fill`. """ field_norm = field.strip().lower() if ("date updated" in field_norm or "date created" in field_norm or "boot time" in field_norm or "timestamp" in field_norm): no_date = False else: no_date = True view = self.field_form_view view.fill( dict( type="Field", field=field, key=key, value=value if no_date else None, )) # In case of advanced search box if view.user_input.is_displayed: user_input = value is None view.user_input.fill(user_input) if not no_date: # Flip the right part of form view = self.field_date_form if (isinstance(value, basestring) and not re.match(r"^[0-9]{2}/[0-9]{2}/[0-9]{4}$", value)): if not view.dropdown_select.is_displayed: self.click_switch_to_relative() view.fill({"dropdown_select": value}) self.click_commit() else: # Specific selection if not view.input_select_date.is_displayed: self.click_switch_to_specific() if (isinstance(value, tuple) or isinstance(value, list)) and len(value) == 2: date, time = value elif isinstance(value, basestring): # is in correct format mm/dd/yyyy # Date only (for now) date = value[:] time = None else: raise TypeError( "fill_field expects a 2-tuple (date, time) or string with date" ) # TODO datetime.datetime support view.input_select_date.fill(date) # Try waiting a little bit for time field # If we don't wait, committing the expression will glitch try: wait_for(lambda: view.input_select_time.is_displayed, num_sec=6) # It appeared, so if the time is to be set, we will set it # (passing None glitches) if time: view.input_select_time.fill(time) except TimedOutError: # Did not appear, ignore that pass finally: # And finally, commit the expression :) self.click_commit() else: self.click_commit()
class RouteDetailsView(ContainerObjectDetailsBaseView): """Container Routes Detail view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Routes', '5.9': 'Container Routes' })
class ImageRegistryAllView(ContainerObjectAllBaseView): """Container Images Registries All view""" SUMMARY_TEXT = VersionPick({ Version.lowest(): 'Image Registries', '5.9': 'Container Image Registries' })
class form(TimeProfileForm): # noqa add = Button(VersionPick({Version.lowest(): 'Save', '5.9': 'Add'}))
class TasksView(BaseLoggedInPage): # Toolbar delete = Dropdown( 'Delete Tasks') # dropdown just has icon, use element title reload = Button(title=VersionPick({ Version.lowest(): 'Reload the current display', '5.9': 'Refresh this page' })) @View.nested class tabs(View): # noqa # Extra Toolbar # Only on 'All' type tabs, but for access it doesn't make sense to access the tab for a # toolbar button cancel = Button(title='Cancel the selected task') # Form Buttons apply = Button('Apply') reset = Button('Reset') default = Button('Default') # Filters zone = BootstrapSelect(id='chosen_zone') period = BootstrapSelect(id='time_period') user = BootstrapSelect(id='user_choice') # This checkbox search_root captures all the filter options # It will break for status if/when there is second checkbox selection field added # It's the lowest level div with an id that captures the status checkboxes status = CheckboxSelect(search_root='tasks_options_div') state = BootstrapSelect(id='state_choice') @View.nested class mytasks(Tab): # noqa TAB_NAME = VersionPick({ Version.lowest(): 'My VM and Container Analysis Tasks', '5.9': 'My Tasks' }) table = Table(table_loc) @View.nested class myothertasks(Tab): # noqa TAB_NAME = VersionPick({ '5.9': 'My Tasks', Version.lowest(): 'My Other UI Tasks' }) table = Table(table_loc) @View.nested class alltasks(Tab): # noqa TAB_NAME = VersionPick({ '5.9': 'All Tasks', Version.lowest(): "All VM and Container Analysis Tasks" }) table = Table(table_loc) @View.nested class allothertasks(Tab): # noqa TAB_NAME = "All Other Tasks" table = Table(table_loc) @property def is_displayed(self): return (self.tabs.mytasks.is_displayed and self.tabs.myothertasks.is_displayed and self.tabs.alltasks.is_displayed and self.tabs.allothertasks.is_displayed)