class details(SatTab): # Basic information name = EditableEntry(name='Name') uuid = ReadOnlyEntry(name='UUID') description = EditableEntry(name='Description') type = ReadOnlyEntry(name='Type') katello_agent = ReadOnlyEntry(name='Katello Agent') virtual_guests = ReadOnlyEntry(name='Virtual Guests') registered_through = ReadOnlyEntry(name='Registered Through') # Subscriptions subscription_status = ReadOnlyEntry(name='Subscription Status') details = ReadOnlyEntry(name='Details') auto_attach = EditableEntryCheckbox(name='Auto-Attach') service_level = EditableEntrySelect(name='Service Level') # Content Host Properties os = ReadOnlyEntry(name='OS') architecture = ReadOnlyEntry(name='Architecture') number_of_cpus = ReadOnlyEntry(name='Number of CPUs') sockets = ReadOnlyEntry(name='Sockets') cores_per_socket = ReadOnlyEntry(name='Cores per Socket') ram = ReadOnlyEntry(name='RAM (GB)') virtual_guest = ReadOnlyEntry(name='Virtual Guest') # Installable Errata security = ReadOnlyEntry(name='Security') bug_fix = ReadOnlyEntry(name='Bug Fix') enhancement = ReadOnlyEntry(name='Enhancement') # Content Host Content release_version = EditableEntrySelect(name='Release Version') content_view = EditableEntrySelect(name='Content View') lce = ParametrizedView.nested(LCESelectorGroup) # Content Host Status registered = ReadOnlyEntry(name='Registered') registered_by = ReadOnlyEntry(name='Registered By') last_checkin = ReadOnlyEntry(name='Last Checkin')
class details(SatTab): name = EditableEntry(name='Name') description = EditableEntry(name='Description') hosts_limit = EditableLimitEntry(name='Host Limit') service_level = EditableEntrySelect(name='Service Level') lce = ParametrizedView.nested(LCESelectorGroup) content_view = EditableEntrySelect(name='Content View')
class CategoryChipGroup(ChipGroup): """ Represents a Chip Group with a category label """ ROOT = ParametrizedLocator( f"{CATEGORY_GROUP_ROOT}[{CATEGORY_LABEL}[normalize-space(.)={{@_label|quote}}]]" ) chips = ParametrizedView.nested(Chip) close_button = Button(locator=CATEGORY_CLOSE) def __init__(self, parent, label, logger=None): self._label = label ChipGroup.__init__(self, parent, logger=logger) @property def label(self): elements = self.browser.elements(CATEGORY_LABEL) return self.browser.text(elements[0]) if elements else None @property def can_close(self): return self.close_button.is_displayed def close(self): self.close_button.click()
class ChipGroupToolbarCategory(ParametrizedView, ChipGroup): """ Represents a chip group that is part of a toolbar, identifiable by a category label """ PARAMETERS = ("label",) ROOT = ParametrizedLocator( f"{OLD_GROUP_ROOT}[{TOOLBAR_GROUP_LABEL}[normalize-space(.)={{label|quote}}]]" ) chips = ParametrizedView.nested(OldChip) def __init__(self, *args, **kwargs): ParametrizedView.__init__(self, *args, **kwargs) @property def label(self): elements = self.browser.elements(CATEGORY_LABEL) return self.browser.text(elements[0]) if elements else None @classmethod def all(cls, browser): return [ (browser.text(el),) for el in browser.elements(f"{OLD_GROUP_ROOT}/{TOOLBAR_GROUP_LABEL}") ]
class VMDetailsEntities(View): """ Details entities view for vms/instances details destinations VM's have 3-4 more tables, should inherit and add them there. """ title = Text('//div[@id="main-content"]//h1//span[@id="explorer_title_text"]') summary = ParametrizedView.nested(ParametrizedSummaryTable)
class ProfileDetialsView(View): title = Text(".//h1") edit = GenericLocatorWidget(".//a[normalize-space(.)='Edit your profile']") posts = ParametrizedView.nested(PostView) @property def is_displayed(self): return self.title.text == "User: {}".format( self.context["object"].username)
class CardGroup(GenericLocatorWidget, View): def __init__(self, parent, locator=None, logger=None, **kwargs): View.__init__(self, parent, logger=logger, **kwargs) self.locator = locator or './/section[@class="pf-c-page__main-section"]/div' cards = ParametrizedView.nested(CardForCardGroup) def __iter__(self): return iter(self.cards)
class StandAloneChipGroup(View): """ Represents a chip group that is "on its own", i.e. not a part of a chip group toolbar """ ROOT = ParametrizedLocator("{@locator}") overflow = OverflowChip() chips = ParametrizedView.nested(Chip) def __init__(self, parent, locator=None, logger=None): super().__init__(parent, logger=logger) self.locator = locator or GROUP_ROOT @property def label(self): # It's unlikely we'll have a labelled chip group that is not in a toolbar # ... but just in case elements = self.browser.elements(STANDALONE_GROUP_LABEL) return self.browser.text(elements[0]) if elements else None def show_more(self): self.overflow.show_more() def show_less(self): self.overflow.show_less() @property def is_multiselect(self): return self.overflow.is_displayed def get_chips(self, show_more=True): """ A helper to expand the chip group before reading its chips """ if self.is_multiselect and show_more: self.show_more() return self.chips def __iter__(self): for chip in self.get_chips(): yield chip def remove_chip_by_name(self, name): for chip in self: if chip.text.lower() == name.lower(): chip.remove() break else: raise ValueError(f"Could not find chip with name '{name}'") def remove_all_chips(self): for chip in self: chip.remove() def read(self): return [chip.text for chip in self]
class MyServiceDetailsEntities(View): """Represents Details page.""" # TODO: use a ParametrizedSummaryTable eventually to do this summary = ParametrizedView.nested(ParametrizedSummaryTable) properties = SummaryTable(title='Properties') lifecycle = SummaryTable(title='Lifecycle') relationships = SummaryTable(title='Relationships') vm = SummaryTable(title='Totals for Service VMs ') smart_management = SummaryTable(title='Smart Management') generic_objects = SummaryTable(title='Generic Objects')
class AllPostsView(BaseLoggedInView): greeting = Text(".//h1") text_area = TextInput(name="post") submit = GenericLocatorWidget('.//input[@name="submit"]') posts = ParametrizedView.nested(PostView) @property def is_displayed(self): return (self.logged_in and self.greeting.text == "Hi, {}!".format( self.context["object"].username))
class DonutLegend(View): ROOT = "./div[contains(@class, 'VictoryContainer')]" item = ParametrizedView.nested(DonutLegendItem) @property def all_items(self): result = [] for i in self.item: result.append({"label": i.label, "value": i.value}) return result
class ContentViewVersionPromoteView(BaseLoggedInView): lce = ParametrizedView.nested(LCESelectorGroup) description = TextInput(id='description') force_metadata_regeneration = Checkbox(id='forceMetadataRegeneration') promote = Text('//button[contains(@ng-click, "verifySelection()")]') cancel = Text( '//a[contains(@class, "btn")][@ui-sref="content-view.versions"]') @property def is_displayed(self): return self.browser.wait_for_element(self.save, exception=False) is not None
class DonutLegend(View): ROOT = ".//*[name()='g'][2]" item = ParametrizedView.nested(DonutLegendItem) @property def all_items(self): """Returns a list of all items, arranged as {label: value}""" result = [] for i in self.item: result.append({"label": i.label, "value": i.value}) return result
class ActivationKeyCreateView(BaseLoggedInView): name = TextInput(id='name') hosts_limit = LimitInput() description = TextInput(id='description') lce = ParametrizedView.nested(LCESelectorGroup) content_view = Select(id='content_view_id') submit = Text("//button[contains(@ng-click, 'handleSave')]") @property def is_displayed(self): return self.browser.wait_for_element(self.name, exception=False) is not None
class ChipGroupToolbar(View): ROOT = ParametrizedLocator("{@locator}") # The parent of the chip group toolbar can be any element type # The locator should be the parent node which holds all the pf-c-chip-group elements TOOLBAR_LOCATOR = ( ".//ul[contains(@class, 'pf-c-chip-group') and " "contains(@class, 'pf-m-toolbar')]/parent::*" ) overflow = OldOverflowChip( locator=("./div[contains(@class, 'pf-c-chip') and contains(@class, 'pf-m-overflow')]") ) groups = ParametrizedView.nested(ChipGroupToolbarCategory) def __init__(self, parent, locator=None, logger=None): self.locator = locator or self.TOOLBAR_LOCATOR super().__init__(parent, logger=logger) def get_groups(self, show_more=True): """ A helper to expand the chip group toolbar before reading its groups """ if self.overflow.is_displayed and show_more: self.overflow.show_more() return self.groups def __iter__(self): for group in self.get_groups(): yield group def read(self): """Returns a dict of chips""" groups = {} for group in self: groups[group.label] = group.read() return groups def show_more(self): """Expands a chip group""" self.overflow.show_more() def show_less(self): """Collapses a chip group""" self.overflow.show_less() @property def has_chips(self): # If we delete all chips the ROOT is still shown thus we need to check if there are # any chips. return self.read() != {}
class ActivationKeyCreateView(BaseLoggedInView): breadcrumb = BreadCrumb() name = TextInput(id='name') hosts_limit = LimitInput() description = TextInput(id='description') lce = ParametrizedView.nested(LCESelectorGroup) content_view = Select(id='content_view_id') submit = Text("//button[contains(@ng-click, 'handleSave')]") @property def is_displayed(self): breadcrumb_loaded = self.browser.wait_for_element(self.breadcrumb, exception=False) return (breadcrumb_loaded and self.breadcrumb.locations[0] == 'Activation Keys' and self.breadcrumb.read() == 'New Activation Key')
class ContentViewVersionPromoteView(BaseLoggedInView): breadcrumb = BreadCrumb() lce = ParametrizedView.nested(LCESelectorGroup) description = TextInput(id='description') force_metadata_regeneration = Checkbox(id='forceMetadataRegeneration') promote = Text('//button[contains(@ng-click, "verifySelection()")]') cancel = Text('//a[contains(@class, "btn")][@ui-sref="content-view.versions"]') @property def is_displayed(self): breadcrumb_loaded = self.browser.wait_for_element(self.breadcrumb, exception=False) return ( breadcrumb_loaded and self.breadcrumb.locations[0] == 'Content Views' and self.breadcrumb.read() == 'Promotion' )
class form(View): # noqa tags = VersionPicker({ Version.lowest(): Table("//div[@id='assignments_div']//table"), "5.11": ParametrizedView.nested(AssignedTags) }) tag_category = VersionPicker({ Version.lowest(): BootstrapSelect(id='tag_cat'), "5.11": ReactSelect(locator='.//div[@id="tag_cat"]') }) tag_name = VersionPicker({ Version.lowest(): BootstrapSelect(id='tag_add'), "5.11": ReactSelect(locator='.//div[@id="cat_tags_div"]') }) entities = View.nested(BaseNonInteractiveEntitiesView) save = Button('Save') reset = Button('Reset') cancel = Button('Cancel')
class HostCollectionChangeAssignedContentView(BaseLoggedInView): title = Text("//h4[contains(., 'Content Host Bulk Content')]") lce = ParametrizedView.nested(LCESelectorGroup) content_view = Select(locator=".//select[@ng-model='selected.contentView']") assign = Text(locator=".//form/button[contains(@ng-click, 'showConfirm')]") @View.nested class dialog(ConfirmationDialog): ROOT = ".//div[@ng-show='showConfirm']" confirm_dialog = Text(".//button[contains(@ng-click, 'performAction')]") cancel_dialog = Text( ".//button[contains(@ng-click, 'showConfirm')" " and not(contains(@ng-click, 'performAction'))]" ) @property def is_displayed(self): """The view is displayed when it's title exists""" return self.browser.wait_for_element(self.title, exception=False) is not None
class details(SatTab): # Basic information name = EditableEntry(name='Name') uuid = ReadOnlyEntry(name='Subscription UUID') bios_uuid = ReadOnlyEntry(name='BIOS UUID') description = EditableEntry(name='Description') type = ReadOnlyEntry(name='Type') katello_agent = ReadOnlyEntry(name='Katello Agent') virtual_guests = ReadOnlyEntry(name='Virtual Guests') registered_through = ReadOnlyEntry(name='Registered Through') # Subscriptions subscription_status = ReadOnlyEntry(name='Subscription Status') details = ReadOnlyEntry(name='Details') auto_attach = EditableEntryCheckbox(name='Auto-Attach') # System Purpose system_purpose_status = ReadOnlyEntry(name='System Purpose Status') service_level = EditableEntrySelect(name='Service Level (SLA)') usage_type = EditableEntrySelect(name='Usage Type') role = EditableEntrySelect(name='Role') addons = EditableEntryMultiCheckbox(name='Add ons') # Content Host Properties os = ReadOnlyEntry( locator= ".//dt[.='OS']/following-sibling::dd[not(contains(@class, 'ng-hide'))]" ) architecture = ReadOnlyEntry(name='Architecture') number_of_cpus = ReadOnlyEntry(name='Number of CPUs') sockets = ReadOnlyEntry(name='Sockets') cores_per_socket = ReadOnlyEntry(name='Cores per Socket') ram = ReadOnlyEntry(name='RAM (GB)') virtual_guest = ReadOnlyEntry(name='Virtual Guest') # Installable Errata security = ReadOnlyEntry(name='Security') bug_fix = ReadOnlyEntry(name='Bug Fix') enhancement = ReadOnlyEntry(name='Enhancement') # Content Host Content release_version = EditableEntrySelect(name='Release Version') content_view = EditableEntrySelect(name='Content View') lce = ParametrizedView.nested(LCESelectorGroup) # Content Host Status registered = ReadOnlyEntry(name='Registered') registered_by = ReadOnlyEntry(name='Registered By') last_checkin = ReadOnlyEntry(name='Last Checkin')
class ProviderTileIconEntity(BaseTileIconEntity): """ Provider child of Tile Icon entity """ quad_icon = ParametrizedView.nested(ProviderQuadIconEntity)
class entities(View): # noqa summary = ParametrizedView.nested(ParametrizedSummaryTable)
class DatastoreTileIconEntity(BaseTileIconEntity): quad_icon = ParametrizedView.nested(DatastoreQuadIconEntity)
class HostTileIconEntity(BaseTileIconEntity): quad_icon = ParametrizedView.nested(HostQuadIconEntity)
class PhysicalServerTileIconEntity(BaseTileIconEntity): quad_icon = ParametrizedView.nested(PhysicalServerQuadIconEntity)
class VolumeTileIconEntity(BaseTileIconEntity): quad_icon = ParametrizedView.nested(VolumeQuadIconEntity)
class DepRoleTileIconEntity(BaseTileIconEntity): quad_icon = ParametrizedView.nested(DepRoleQuadIconEntity)
class Cards(CardGroup): def __init__(self, parent, locator=None, logger=None, **kwargs): View.__init__(self, parent, logger=logger, **kwargs) self.locator = locator or './/div[contains(@class, "pf-l-gallery")]' cards = ParametrizedView.nested(PageCard)
class PhysicalSwitchTileIconEntity(BaseTileIconEntity): quad_icon = ParametrizedView.nested(PhysicalSwitchQuadIconEntity)
class HostDetailsEntities(View): """Represents Details page.""" summary = ParametrizedView.nested(ParametrizedSummaryTable)