예제 #1
0
class AssignedTags(ParametrizedView):
    """
    Represents the assigned tag in EditTags menu.
    To remove the tag, you need to pass category name, e.g.: 'view.form.tags(category).remove()'.
    To read the value of the tag, pass the category name, e.g.: 'view.form.tags(category).read()'.
    """
    PARAMETERS = ("tag", )
    ALL_TAGS = ".//a[contains(@class, 'pf-remove-button')]"
    tag_remove = Text(
        ParametrizedLocator(
            ".//div[@class='category-label'][normalize-space(@title)={tag|quote}]/parent::li/"
            "following-sibling::li/descendant::a[contains(@class, 'pf-remove-button')]"
        ))

    tag_value = Text(
        ParametrizedLocator(
            ".//div[@class='category-label'][normalize-space(@title)={tag|quote}]/parent::li/"
            "following-sibling::li/span"))

    def remove(self):
        """Removes the assigned tag by clicking 'x' icon"""
        self.tag_remove.click()

    def read(self):
        """Return the assigned value to a tag category"""
        return self.browser.get_attribute("title", self.tag_value)
예제 #2
0
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()
예제 #3
0
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}")
        ]
예제 #4
0
파일: brick.py 프로젝트: usmqe/usmqe-tests
    class volume_parts(ParametrizedView):
        """
        Nested view for each volume part.
        """
        PARAMETERS = ("part_id", )
        ROOT = ParametrizedLocator(
            "(.//div[@class='list-group list-view-pf list-view-pf-view"
            " ng-scope'])[position() = {part_id|quote}]")
        bricks = Table(".//table", column_widgets={5: Button("Dashboard")})
        part_name = Text(".//div[@class='list-group-item-heading "
                         "bold-text sub-volume ng-binding']")
        brick_count = Text(
            ".//div[@class='list-view-pf-additional-info-item ng-binding']")
        utilization = Text(".//utilisation-chart")

        @classmethod
        def all(cls, browser):
            return [
                browser.text(e) for e in browser.elements(cls.ALL_VOLUMES)
                if browser.text(e) is not None and browser.text(e) != ''
            ]

        @property
        def is_expanded(self):
            return self.browser.elements("div")[0].get_attribute("class").find(
                "expand"
                "-active") > 0
예제 #5
0
    class clusters(ParametrizedView):
        """
        Nested view for each cluster
        """
        PARAMETERS = ("cluster_id",)
        ALL_CLUSTERS = ".//div[@class='list-group-item']"
        ALL_CLUSTER_IDS = ".//div[@class='list-view-pf-description']/descendant-or-self::*/text()"
        ROOT = ParametrizedLocator(
            "//div/*[text()[normalize-space(.)]={cluster_id|quote}]/ancestor-or-self::"
            "div[@class='list-group-item']")
        cluster_version = Text(".//div[text() = 'Cluster Version']/following-sibling::h5")
        managed = Text(".//div[text() = 'Managed']/following-sibling::h5")
        hosts = Text(".//div[text() = 'Hosts']/following-sibling::h5")
        volumes = Text(".//div[text() = 'Volumes']/following-sibling::h5")
        alerts = Text(".//div[text() = 'Alerts']/following-sibling::h5")
        profiling = Text(".//div[text() = 'Volume Profiling']/following-sibling::h5")
        status = Text(".//div[@class='list-view-pf-additional-info-item cluster-text']")
        task_details = Text(".//a[@ng-click='clusterCntrl.goToTaskDetail(cluster)']")
        import_button = Button("contains", "Import")
        dashboard_button = Button("Dashboard")
        actions = Kebab()

        @property
        def health(self):
            return self.browser.elements(".//div[@class='list-view-pf-left']"
                                         "/i")[0].get_attribute("uib-tooltip")

        @classmethod
        def all(cls, browser):
            return [browser.text(e) for e in browser.elements(cls.ALL_CLUSTER_IDS)
                    if browser.text(e) is not None and browser.text(e) != '']
예제 #6
0
class SatSecondaryTab(SatTab):
    """Secondary level Tab, typically 'List/Remove' or 'Add' sub-tab inside
    some primary tab.

    Usage::

        @View.nested
        class listremove(SatSecondaryTab):
            TAB_NAME = 'List/Remove'
    """
    ROOT = ParametrizedLocator(
        './/nav[@class="ng-scope" or not(@*)]/following-sibling::div')

    TAB_LOCATOR = ParametrizedLocator(
        './/nav[@class="ng-scope" or not(@*)]/ul[contains(@class, "nav-tabs")]'
        '/li[./a[normalize-space(.)={@tab_name|quote}]]')
예제 #7
0
class DonutLegendItem(ParametrizedView, ClickableMixin):
    PARAMETERS = ("label_text", )
    ROOT = ParametrizedLocator(
        ".//*[name()='text']"
        "/*[name()='tspan' and contains(., '{label_text}')]")
    ALL_ITEMS = ".//*[name()='text']/*[name()='tspan']"
    LEGEND_ITEM_REGEX = re.compile(r"(.*?): ([\d]+)")

    @classmethod
    def _get_legend_item(cls, text):
        match = cls.LEGEND_ITEM_REGEX.match(text)
        if match:
            return match.group(1), match.group(2)
        else:
            return text, None

    @property
    def label(self):
        """Returns the label of a DonutLegendItem as a string"""
        return self._get_legend_item(self.browser.text(self))[0]

    @property
    def value(self):
        """Returns the value of a DonutLegendItem as a string"""
        return self._get_legend_item(self.browser.text(self))[1]

    @classmethod
    def all(cls, browser):
        """Returns a list of all items"""
        return [(browser.text(el), ) for el in browser.elements(cls.ALL_ITEMS)]
예제 #8
0
파일: host.py 프로젝트: usmqe/usmqe-tests
    class hosts(ParametrizedView):
        """Nested view for each host"""
        PARAMETERS = ("hostname", )
        ROOT = ParametrizedLocator(
            ".//div/a[text()[normalize-space(.)]={hostname|quote}]/ancestor-or-self::"
            "div[@class='ft-row list-group-item ng-scope']")
        host_name = Text(
            ".//div[@class='ft-column ft-main host-name bold-text']/a")
        gluster_version = Text(
            ".//div[text() = 'Gluster Version']/following-sibling::div")
        managed = Text(".//div[text() = 'Managed']/following-sibling::div")
        role = Text(".//div[text() = 'Role']/following-sibling::div")
        bricks = Text(".//div[text() = 'Bricks']/following-sibling::div")
        alerts = Text(".//div[text() = 'Alerts']/following-sibling::div")
        dashboard_button = Button("Dashboard")

        @property
        def health(self):
            return self.browser.elements(
                ".//div[@class='ft-column ft-icon']"
                "/i")[0].get_attribute("uib-tooltip-html").strip("'")

        @classmethod
        def all(cls, browser):
            return [
                browser.text(e) for e in browser.elements(cls.ALL_HOSTNAMES)
                if browser.text(e) is not None and browser.text(e) != ''
            ]
예제 #9
0
class SatTab(Tab):
    """Regular primary level ``Tab``.

    Usage::

        @View.nested
        class mytab(SatTab):
            TAB_NAME = 'My Tab'

    Note that ``TAB_NAME`` is optional and if it's absent - capitalized class
    name is used instead, which is useful for simple tab names like
    'Subscriptions'::

        @View.nested
        class subscriptions(SatTab):
            # no need to specify 'TAB_NAME', it will be set to 'Subscriptions'
            # automatically
            pass

    """
    ROOT = ParametrizedLocator('.//div[contains(@class, "page-content") or '
                               'contains(@class, "tab-content")]')

    @property
    def is_displayed(self):
        return 'ng-hide' not in self.parent_browser.classes(self.TAB_LOCATOR)

    def read(self):
        """Do not attempt to read hidden tab contents"""
        if not self.is_displayed:
            do_not_read_this_widget()
        return super().read()
예제 #10
0
class DonutChart(View):
    """
        Represents the Donut Chart
        from Patternfly 4 (https://www.patternfly.org/v4/documentation/react/charts/chartdonut)
    """

    ROOT = ParametrizedLocator("{@locator}")
    BASE_LOCATOR = ".//div[@id={}]"

    def __init__(self, parent, id=None, locator=None, logger=None):
        """Create the widget"""
        Widget.__init__(self, parent, logger=logger)
        if id:
            self.locator = self.BASE_LOCATOR.format(quote(id))
        elif locator:
            self.locator = locator
        else:
            raise TypeError("You need to specify either id or locator")

    @View.nested
    class donut(View):  # noqa
        ROOT = ".//div[*[name()='svg'][*[name()='text'] and not(*[name()='rect'])]]"
        LABELS_LOCATOR = "./*[name()='svg']/*[name()='text']/*[name()='tspan']"

        @property
        def labels(self):
            return [
                self.browser.text(elem)
                for elem in self.browser.elements(self.LABELS_LOCATOR)
            ]

    @View.nested
    class legend(View):  # noqa
        ROOT = "./div[contains(@class, 'VictoryContainer')]"
        ALL_ITEMS = "./*[name()='svg']/*[name()='g']/*[name()='text']/*[name()='tspan']"

        @ParametrizedView.nested
        class item(ParametrizedView, ClickableMixin):  # noqa
            PARAMETERS = ("label_text", )
            ROOT = ParametrizedLocator(
                ".//*[name()='svg']/*[name()='g']/*[name()='text']"
                "/*[name()='tspan' and contains(., '{label_text}')]")

            @property
            def label(self):
                return _get_legend_item(self.browser.text(self))[0]

            @property
            def value(self):
                return _get_legend_item(self.browser.text(self))[1]

        @property
        def all_items(self):
            els = self.browser.elements(self.ALL_ITEMS)
            result = []
            for el in els:
                label, value = _get_legend_item(self.browser.text(el))
                result.append({"label": label, "value": value})
            return result
예제 #11
0
class AffectedRepositoriesTab(SatSecondaryTab):
    """Affected repositories tab contains repositories count inside tab title,
    making it impossible to rely on exact string value. Using ``starts-with``
    instead.
    """
    TAB_NAME = 'Affected Repositories'
    TAB_LOCATOR = ParametrizedLocator(
        './/nav[@class="ng-scope" or not(@*)]/ul[contains(@class, "nav-tabs")]'
        '/li[./a[starts-with(normalize-space(), {@tab_name|quote})]]')
예제 #12
0
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]
예제 #13
0
class OldChip(Chip):
    ROOT = ParametrizedLocator(
        f"{OLD_CHIP_ROOT}[{CHIP_TEXT}[starts-with(normalize-space(.), {{text|quote}})]]"
    )

    @classmethod
    def all(cls, browser):
        """Returns a list of the text of each chip"""
        return [(cls._get_text_ignoring_badge(browser, el), )
                for el in browser.elements(f"{OLD_CHIP_ROOT}/{CHIP_TEXT}")]
예제 #14
0
    class lce(ParametrizedView):
        """Parametrized view for the lifecycle environement, takes an LCE name on instantiation"""

        ROOT = ParametrizedLocator(
            ".//div[@ng-repeat='path in paths'][table//th/a[normalize-space(.)='{lce_name}']]"
        )
        PARAMETERS = ('lce_name', )
        LAST_ENV = "//div[@ng-repeat='path in paths']//table//th[last()]"
        current_env = Text(
            ParametrizedLocator(".//a[normalize-space(.)='{lce_name}']"))
        envs_table = Table(locator=".//table")
        new_child = Text(".//a[contains(@href, '/lifecycle_environments/')]")

        @classmethod
        def all(cls, browser):
            """Helper method which returns list of tuples with all available
            LCE names (last available environment is used as a name). It's
            required for :meth:`read` to work properly.
            """
            return [(element.text, )
                    for element in browser.elements(cls.LAST_ENV)]

        def read(self):
            """Returns content views and count hosts count per each available
            lifecycle environment
            We get dictionary in next format::

                {
                    'LCE_1': {'Content Views': 0, 'Content Hosts': 1},
                    'LCE_2': {'Content Views': 1, 'Content Hosts': 2},
                }

            """
            result = {}
            available_envs = self.envs_table.headers[1:]
            lce_metric_names = [row[0].text for row in self.envs_table]
            for column_name in available_envs:
                metric_values = (int(row[column_name].text)
                                 for row in self.envs_table)
                result[column_name] = {}
                for row_name in lce_metric_names:
                    result[column_name][row_name] = next(metric_values)
            return result
예제 #15
0
class SatTab(Tab):
    """Regular primary level ``Tab``.

    Usage::

        @View.nested
        class mytab(SatTab):
            TAB_NAME = 'My Tab'
    """
    ROOT = ParametrizedLocator('.//div[contains(@class, "page-content") or '
                               'contains(@class, "tab-content")]')
예제 #16
0
파일: common.py 프로젝트: ATIX-AG/airgun
class SatTabWithDropdown(TabWithDropdown):
    """Regular primary level ``Tab`` with dropdown.

    Usage::

        @View.nested
        class mytab(SatTabWithDropdown):
            TAB_NAME = 'My Tab'
            SUB_ITEM = 'My Tab Dropdown Item'
    """
    ROOT = ParametrizedLocator('.//div[contains(@class, "page-content") or '
                               'contains(@class, "tab-content")]')
예제 #17
0
class SatSecondaryTab(Tab):
    """Secondary level Tab, typically 'List/Remove' or 'Add' sub-tab inside
    some primary tab.

    Usage::

        @View.nested
        class listremove(SatSecondaryTab):
            TAB_NAME = 'List/Remove'
    """
    ROOT = ParametrizedLocator(
        './/nav[@class="ng-scope"]/following-sibling::div')
예제 #18
0
class ParametersForm(View):
    ROOT = ParametrizedLocator(
        "//generic-object-table-component[@key-type='{@param_type}'] "
        " | //generic-object-table[@key-type='{@param_type}']"
    )
    ALL_PARAMETERS = './/input[contains(@class, "ng-not-empty")]'
    add = Button(ParametrizedString('Add {@param_type}'))
    name = Input(locator='.//input[contains(@class, "ng-empty")]')
    type_class = BootstrapSelect(
        locator='.//input[contains(@class, "ng-empty")]//ancestor::tr//button')

    def __init__(self, parent, param_type, logger=None):
        View.__init__(self, parent, logger=logger)
        self.param_type = param_type

    def all(self):
        return [(element.get_attribute('value'), element.get_attribute('name'))
                for element in self.browser.elements(self.ALL_PARAMETERS)]

    @property
    def empty_field_is_present(self):
        try:
            return self.browser.element(self.name)
        except NoSuchElementException:
            return False

    def add_parameter_row(self):
        if not self.empty_field_is_present:
            self.add.click()

    def fill(self, parameters):
        if parameters:
            if isinstance(parameters, dict):
                for name, type_class in parameters.items():
                    self.add_parameter_row()
                    type_result = self.type_class.fill(type_class.capitalize())
                    result = self.name.fill(name)
                    return result and type_result
            elif isinstance(parameters, list):
                for name in parameters:
                    self.add_parameter_row()
                    result = self.name.fill(name)
                    return result

    def delete(self, name):
        all_params = self.all()
        for param in all_params:
            param_name, element_name = param
            if param_name == name:
                self.browser.element(
                    '//td[contains(@ng-class,  "{}")]/ancestor::tr'
                    '//div[@title = "Delete Row"]'.format(element_name)).click()
예제 #19
0
class SatVerticalTab(SatTab):
    """Represent vertical tabs that usually used in location and organization
    entities

    Usage::

        @View.nested
        class mytab(SatVerticalTab):
            TAB_NAME = 'My Tab'
    """
    TAB_LOCATOR = ParametrizedLocator(
        ".//ul[@data-tabs='pills']"
        "/li[./a[normalize-space(.)={@tab_name|quote}]]")
예제 #20
0
        class item(ParametrizedView, ClickableMixin):  # noqa
            PARAMETERS = ("label_text", )
            ROOT = ParametrizedLocator(
                ".//*[name()='svg']/*[name()='g']/*[name()='text']"
                "/*[name()='tspan' and contains(., '{label_text}')]")

            @property
            def label(self):
                return _get_legend_item(self.browser.text(self))[0]

            @property
            def value(self):
                return _get_legend_item(self.browser.text(self))[1]
예제 #21
0
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() != {}
예제 #22
0
    class events(ParametrizedView):
        """Nested view for each event"""
        PARAMETERS = ("event_id", )
        ROOT = ParametrizedLocator("(.//div[@class='ft-row list-group-item'])"
                                   "[position() = {event_id|quote}]")
        description = Text(".//div[@class='ft-column ft-main event-desc']/div")
        date = Text(".//div[@class='ft-column']/div")

        @classmethod
        def all(cls, browser):
            return [
                browser.text(e) for e in browser.elements(cls.ALL_VOLUMES)
                if browser.text(e) is not None and browser.text(e) != ''
            ]
예제 #23
0
파일: task.py 프로젝트: usmqe/usmqe-tests
    class events(ParametrizedView):
        """
        Nested view for each event during the task completion
        """
        PARAMETERS = ("event_id",)
        ALL_IDS = './/div[@class="row list-group-item logs ng-scope"]'
        ROOT = ParametrizedLocator('.//div[@id={event_id|quote}]')
        event_type = Text(".//div[@class='col-md-1 ng-binding']")
        description = Text(".//div[@class='col-md-6 ng-binding']")
        date = Text(".//div[@class='col-md-2 ng-binding']")

        @classmethod
        def all(cls, browser):
            return [e.text.split(" ")[2] for e in browser.elements(cls.ALL_IDS)
                    if browser.text(e) is not None and browser.text(e) != '']
예제 #24
0
class RadioGroup(Widget):
    """ Radio Group Control

    .. code-block:: python

        radio_group = RadioGroup(locator=".//div[./label[@for='role']]")
        radio_group.select(radio_group.button_values()[-1])
    """

    ROOT = ParametrizedLocator('{@locator}')
    BUTTONS = './/input[@type="radio"]'
    BUTTON = './/input[@type="radio" and @value={}]'

    def __init__(self, parent, locator, logger=None):
        Widget.__init__(self, parent=parent, logger=logger)
        self.locator = locator

    @property
    def button_values(self):
        return [
            btn.get_attribute("value")
            for btn in self.browser.elements(self.BUTTONS)
        ]

    @property
    def selected(self):

        for btn in self.browser.elements(self.BUTTONS):
            if ("ng-valid-parse" in self.browser.classes(btn)
                    or btn.get_attribute("checked") is not None):
                return btn.get_attribute("value")

        else:
            # radio button doesn't have any marks to make out which button is selected by default.
            # so, returning first radio button's name
            return self.button_values[0]

    def select(self, value):
        if self.selected != value:
            self.browser.element(self.BUTTON.format(quote(value))).click()
            return True
        return False

    def read(self):
        return self.selected

    def fill(self, name):
        return self.select(name)
예제 #25
0
파일: task.py 프로젝트: usmqe/usmqe-tests
    class tasks(ParametrizedView):
        """
        Nested view for each task
        """
        PARAMETERS = ("task_id",)
        ROOT = ParametrizedLocator(
            ".//p[contains(text(), {task_id|quote})]/ancestor-or-self::"
            "div[@class='ft-row list-group-item']")
        task_name = Text(".//a[@class='bold-text name ng-binding']")
        submitted_date = Text(".//div[text() = 'Submitted']/following-sibling::div")
        status = Text(".//div[@class='bold-text ng-binding']")
        changed_date = Text(".//div[@class='bold-text ng-binding']/following-sibling::div")

        @classmethod
        def all(cls, browser):
            return [e.text.split(" ")[2] for e in browser.elements(cls.ALL_IDS)
                    if browser.text(e) is not None and browser.text(e) != '']
예제 #26
0
파일: volume.py 프로젝트: usmqe/usmqe-tests
    class volumes(ParametrizedView):
        """Nested view for each volume"""
        PARAMETERS = ("volume_name", )
        ROOT = ParametrizedLocator(
            ".//div/a[text()[normalize-space(.)]={volume_name|quote}]/ancestor-or-self::"
            "div[@class='ft-row list-group-item ng-scope']")
        volname = Text(".//div[@class='bold-text long-volume-name']/a")
        volume_type = Text(".//div[@class='pull-left vol-type ng-binding']")
        bricks = Text(".//div[text() = 'Bricks']/following-sibling::div")
        running = Text(".//div[text() = 'Running']/following-sibling::div")
        rebalance = Text(".//div[text() = 'Rebalance']/following-sibling::div")
        profiling = Text(
            ".//div[text() = 'Volume Profiling']/following-sibling::div")
        alerts = Text(".//div[text() = 'Alerts']/following-sibling::div")
        enable_profiling = Button("Enable Profiling")
        disable_profiling = Button("Disable Profiling")
        dashboard_button = Button("Dashboard")

        @property
        def health(self):
            """
            Returns the corresponding expected value of Grafana Health panel
            TODO: find out the icon for state 'Failed'
            """
            health = self.browser.elements(".//div[@class='ft-column ft-icon']"
                                           "/i")[0].get_attribute("class")
            if health == "pficon pficon-ok":
                return "Up"
            elif health == "pficon pficon-degraded icon-orange":
                return "Up(Degraded)"
            elif health == "pficon pficon-degraded icon-red":
                return "Up(Partial)"
            elif health == "fa ffont fa-arrow-circle-o-down":
                return "Down"
            elif health == "fa ffont fa-question":
                return "Unknown"
            else:
                return "Unexpected state"

        @classmethod
        def all(cls, browser):
            return [
                browser.text(e) for e in browser.elements(cls.ALL_VOLUMES)
                if browser.text(e) is not None and browser.text(e) != ''
            ]
예제 #27
0
class Chip(ParametrizedView, _BaseChip):
    PARAMETERS = ("text",)
    ROOT = ParametrizedLocator(
        f"{CHIP_ROOT}[{CHIP_TEXT}[starts-with(normalize-space(.), {{text|quote}})]]"
    )

    @staticmethod
    def _get_text_ignoring_badge(browser, element):
        el = element
        badge_elements = browser.elements(CHIP_BADGE, parent=el)
        if badge_elements:
            badge = browser.text(el)
            return badge.rstrip(browser.text(badge_elements[0]))
        return browser.text(el)

    @classmethod
    def all(cls, browser):
        """Returns a list of the text of each chip"""
        return [
            (cls._get_text_ignoring_badge(browser, el),)
            for el in browser.elements(f"{CHIP_ROOT}/{CHIP_TEXT}")
        ]

    def __init__(self, *args, **kwargs):
        ParametrizedView.__init__(self, *args, **kwargs)

    def remove(self):
        """Removes a chip"""

        def _gone():
            return not self.is_displayed

        if not self.read_only:
            self.button.click()
            wait_for(_gone, num_sec=3, message="wait for chip to dissappear", delay=0.1)
        else:
            raise ChipReadOnlyError(self, "Chip is read-only")

    @property
    def read_only(self):
        """Returns a boolean detailing if the chip is read only"""
        """
        Return whether or not this chip is read-only
        """
        return not self.button.is_displayed
예제 #28
0
    class alerts(ParametrizedView):
        PARAMETERS = ("alert_id", )
        ROOT = ParametrizedLocator("(.//div[@class='list-group-item'])"
                                   "[position() = {alert_id|quote}]")
        description = Text(".//p[@class='ng-binding']")
        date = Text(".//p[@class='ng-binding']/following-sibling::div")

        @classmethod
        def all(cls, browser):
            return [
                browser.text(e) for e in browser.elements(cls.ALL_VOLUMES)
                if browser.text(e) is not None and browser.text(e) != ''
            ]

        @property
        def severity(self):
            return self.browser.elements(
                ".//i[@data-toggle]")[0].get_attribute("title")
예제 #29
0
class DonutChart(View):
    """
    Represents the Donut Chart
    from Patternfly 4 (https://www.patternfly.org/v4/documentation/react/charts/chartdonut)
    """

    ROOT = ParametrizedLocator("{@locator}")
    BASE_LOCATOR = ".//div[@id={}]"

    donut = View.nested(DonutCircle)
    legend = View.nested(DonutLegend)

    def __init__(self, parent, id=None, locator=None, logger=None):
        """Create the widget"""
        Widget.__init__(self, parent, logger=logger)
        if id:
            self.locator = self.BASE_LOCATOR.format(quote(id))
        elif locator:
            self.locator = locator
        else:
            raise TypeError("You need to specify either id or locator")
예제 #30
0
class SatTabWithDropdown(TabWithDropdown):
    """Regular primary level ``Tab`` with dropdown.

    Usage::

        @View.nested
        class mytab(SatTabWithDropdown):
            TAB_NAME = 'My Tab'
            SUB_ITEM = 'My Tab Dropdown Item'
    """
    ROOT = ParametrizedLocator('.//div[contains(@class, "page-content") or '
                               'contains(@class, "tab-content")]')

    @property
    def is_displayed(self):
        return 'ng-hide' not in self.parent_browser.classes(self.TAB_LOCATOR)

    def read(self):
        """Do not attempt to read hidden tab contents"""
        if not self.is_displayed:
            do_not_read_this_widget()
        return super().read()