Skip to content

Commit

Permalink
CV UI Filter Create/Delete/Edit (SatelliteQE#1014)
Browse files Browse the repository at this point in the history
* Add minimum elements for Publish workflow

* View/Entity for Filter Create/Delete

* Address review comments

* Add french navigation

* Change entity name, add some checks

* Rework progressbar widget to use PF4 widget

* address review comments

* Fix ruff issues

* Add support for RPM Rule edit

* Add many view locators for different types of filters

* Merge and fix conflicts
  • Loading branch information
sambible authored Dec 11, 2023
1 parent 8322495 commit 2f635ac
Show file tree
Hide file tree
Showing 2 changed files with 256 additions and 19 deletions.
116 changes: 100 additions & 16 deletions airgun/entities/contentview_new.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from navmazing import NavigateToSibling
from widgetastic.exceptions import NoSuchElementException

from airgun.entities.base import BaseEntity
from airgun.navigation import NavigateStep, navigator
from airgun.utils import retry_navigation
from airgun.views.contentview_new import (
AddRPMRuleView,
ContentViewCreateView,
ContentViewEditView,
ContentViewTableView,
ContentViewVersionPublishView,
CreateFilterView,
EditFilterView,
)


Expand Down Expand Up @@ -42,9 +46,78 @@ def publish(self, entity_name, values=None):
view = self.navigate_to(self, 'Edit', entity_name=entity_name)
self.browser.plugin.ensure_page_safe(timeout='5s')
view.wait_displayed()
view.versions.table.wait_displayed()
return view.versions.table.read()

def create_filter(self, entity_name, filter_name, filter_type, filter_inclusion):
"""Create a new filter on a CV - filter_type should be one of the available dropdown options
in the Content Type dropdown, and filter_inclusion should be either 'include' or 'exclude'
:return: dict with new filter table row
"""
view = self.navigate_to(self, 'Edit', entity_name=entity_name)
view.filters.new_filter.click()
view = CreateFilterView(self.browser)
view.name.fill(filter_name)
view.filterType.fill(filter_type)
if filter_inclusion == 'include':
view.includeFilter.fill(True)
elif filter_inclusion == 'exclude':
view.excludeFilter.fill(True)
else:
raise ValueError("Filter_inclusion must be one of include or exclude.")
view.create.click()
view = self.navigate_to(self, 'Edit', entity_name=entity_name)
return view.filters.table.read()

def delete_filter(self, entity_name, filter_name):
view = self.navigate_to(self, 'Edit', entity_name=entity_name)
view.filters.search(filter_name)
view.filters.table[0][6].widget.item_select('Remove')
# Attempt to read the table, and if there isn't one return True, else delete failed so return False
try:
view.filters.table.read()
except NoSuchElementException:
return True
else:
return False

"""
Filter Editing will be handled in discrete methods, since each type has different actions. These will be
created as tests and cases are encountered.
"""

def add_rule_rpm_filter(self, entity_name, filter_name, rpm_name, arch):
view = self.navigate_to(self, 'Edit', entity_name=entity_name)
view.filters.search(filter_name)
view.filters.table[0][1].widget.click()
view = EditFilterView(self.browser)
view.addRpmRule.click()
view = AddRPMRuleView(self.browser)
view.rpmName.fill(rpm_name)
view.architecture.fill(arch)
view.addEdit.click()
view = EditFilterView(self.browser)
return view.rpmRuleTable.read()

def add_rule_tag_filter(self, entity_name, filter_name, rpm_name, arch):
view = self.navigate_to(self, 'Edit', entity_name=entity_name)
view.filters.search(filter_name)
view.filters.table[0][1].widget.click()
view = EditFilterView(self.browser)
view.addRpmRule.click()
view = AddRPMRuleView(self.browser)
view.rpmName.fill(rpm_name)
view.architecture.fill(arch)
view.addEdit.click()
view = EditFilterView(self.browser)
return view.rpmRuleTable.read()

def read_french_lang_cv(self):
"""Navigates to main CV page, when system is set to French, and reads table"""
view = self.navigate_to(self, 'French')
self.browser.plugin.ensure_page_safe(timeout='5s')
view.wait_displayed()
return view.table.read()


@navigator.register(NewContentViewEntity, 'All')
class ShowAllContentViewsScreen(NavigateStep):
Expand All @@ -57,6 +130,17 @@ def step(self, *args, **kwargs):
self.view.menu.select('Content', 'Lifecycle', 'Content Views')


@navigator.register(NewContentViewEntity, 'French')
class ShowAllContentViewsScreenFrench(NavigateStep):
"""Navigate to All Content Views screen ( in French )"""

VIEW = ContentViewTableView

@retry_navigation
def step(self, *args, **kwargs):
self.view.menu.select('Contenu', 'Lifecycle', 'Content Views')


@navigator.register(NewContentViewEntity, 'New')
class CreateContentView(NavigateStep):
"""Navigate to Create content view."""
Expand All @@ -69,21 +153,6 @@ def step(self, *args, **kwargs):
self.parent.create_content_view.click()


@navigator.register(NewContentViewEntity, 'Edit')
class EditContentView(NavigateStep):
"""Navigate to Edit Content View screen."""

VIEW = ContentViewEditView

def prerequisite(self, *args, **kwargs):
return self.navigate_to(self.obj, 'All')

def step(self, *args, **kwargs):
entity_name = kwargs.get('entity_name')
self.parent.search(entity_name)
self.parent.table.row(name=entity_name)['Name'].widget.click()


@navigator.register(NewContentViewEntity, 'Publish')
class PublishContentViewVersion(NavigateStep):
"""Navigate to Content View Publish screen."""
Expand All @@ -98,3 +167,18 @@ def prerequisite(self, *args, **kwargs):
def step(self, *args, **kwargs):
"""Click 'Publish new version' button"""
self.parent.publish.click()


@navigator.register(NewContentViewEntity, 'Edit')
class EditContentView(NavigateStep):
"""Navigate to Edit Content View screen."""

VIEW = ContentViewEditView

def prerequisite(self, *args, **kwargs):
return self.navigate_to(self.obj, 'All')

def step(self, *args, **kwargs):
entity_name = kwargs.get('entity_name')
self.parent.search(entity_name)
self.parent.table.row(name=entity_name)['Name'].widget.click()
159 changes: 156 additions & 3 deletions airgun/views/contentview_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from widgetastic.utils import ParametrizedLocator
from widgetastic.widget import Checkbox, Text, TextInput, View
from widgetastic_patternfly import BreadCrumb, Tab
from widgetastic_patternfly4 import Button, Dropdown
from widgetastic_patternfly4 import Button, Dropdown, Radio as PF4Radio
from widgetastic_patternfly4.ouia import (
Button as PF4Button,
ExpandableTable,
PatternflyTable,
Select as PF4Select,
Switch,
)

Expand Down Expand Up @@ -102,7 +103,7 @@ class ContentViewTableView(BaseLoggedInView, SearchableViewMixinPF4):

@property
def is_displayed(self):
return self.create_content_view.is_displayed
return self.create_content_view.is_displayed()


class ContentViewCreateView(BaseLoggedInView):
Expand Down Expand Up @@ -207,7 +208,25 @@ class repositories(Tab):
@View.nested
class filters(Tab):
TAB_LOCATOR = ParametrizedLocator('//a[contains(@href, "#/filters")]')
new_filter = Text(".//button[@ui-sref='content-view.yum.filters.new']")
new_filter = PF4Button('create-filter-button')
searchbox = PF4Search()
table = PatternflyTable(
component_id="content-view-filters-table",
column_widgets={
0: Checkbox(locator='.//input[@type="checkbox"]'),
'Name': Text('.//a'),
'Description': Text('.//a'),
'Updated': Text('.//a'),
'Content type': Text('.//a'),
'Inclusion type': Text('.//a'),
6: Dropdown(locator='.//div[contains(@class, "pf-c-dropdown")]'),
},
)

def search(self, name):
"""Searches for specific filter'"""
self.searchbox.search(name)
return self.table.read()


class ContentViewVersionPublishView(BaseLoggedInView):
Expand Down Expand Up @@ -264,3 +283,137 @@ def is_displayed(self):
and self.breadcrumb.locations[0] == 'Content Views'
and self.breadcrumb.locations[2] == 'Versions'
)


class CreateFilterView(View):
ROOT = './/div[@data-ouia-component-id="create-filter-modal"]'

name = TextInput(id='name')
filterType = PF4Select('content_type')
includeFilter = PF4Radio(label_text='Include filter')
excludeFilter = PF4Radio(label_test='Exclude filter')
create = PF4Button('create-filter-form-submit-button')
cancel = PF4Button('create-filter-form-cancel-button')


class EditFilterView(View):
name = Text('.//h2[@data-ouia-component-id="name-text-value"]')
editName = PF4Button('edit-button-name')
nameInput = TextInput('name text input')
submitName = PF4Button('submit-button-name')
clearName = PF4Button('clear-button-name')
description = Text('.//h2[@data-ouia-component-id="description-text-value"]')
editDescription = PF4Button('edit-button-description')
descriptionInput = TextInput(locator='.//textarea[@aria-label="description text area"]')

# Below this, the fields are generally not shared by each Filter Type

# RPM Rule
search = PF4Search()
addRpmRule = PF4Button('add-rpm-rule-button')
rpmRuleTable = PatternflyTable(
component_id="content-view-rpm-filter-table",
column_widgets={
0: Checkbox(locator='.//input[@type="checkbox"]'),
'RPM Name': Text('.//a'),
'Architecture': Text('.//a'),
'Versions': Text('.//a'),
4: Dropdown(locator='.//div[contains(@class, "pf-c-dropdown")]'),
},
)

# Container Image Tag Rule
addTagRule = PF4Button('add-content-view-container-image-filter-button')
tagRuleTable = PatternflyTable(
component_id="content-view-container-image-filter",
column_widgets={
0: Checkbox(locator='.//input[@type="checkbox"]'),
'Tag Name': Text('.//a'),
2: Dropdown(locator='.//div[contains(@class, "pf-c-dropdown")]'),
},
)

# Package Group Rule
addPackageGroupRule = PF4Button('add-package-group-filter-rule-button')
removePackageGroupRule = Dropdown('cv-package-group-filter-bulk-actions-dropdown')
packageGroupRuleTable = PatternflyTable(
component_id="content-view-package-group-filter-table",
column_widgets={
0: Checkbox(locator='.//input[@type="checkbox"]'),
'Name': Text('.//a'),
'Product': Text('.//a'),
'Repository': Text('.//a'),
'Description': Text('.//a'),
'Status': Text('.//a'),
6: Dropdown(locator='.//div[contains(@class, "pf-c-dropdown")]'),
},
)

# Module Streams Rule
addModuleStreamRule = PF4Button('add-module-stream-rule-button')
removeModuleStreamRule = Dropdown('bulk-actions-dropdown')
moduleStreamRuleTable = PatternflyTable(
component_id="content-view-module-stream-filter-table",
column_widgets={
0: Checkbox(locator='.//input[@type="checkbox"]'),
'Name': Text('.//a'),
'Stream': Text('.//a'),
'Version': Text('.//a'),
'Context': Text('.//a'),
'Status': Text('.//a'),
6: Dropdown(locator='.//div[contains(@class, "pf-c-dropdown")]'),
},
)

# Errata Rule
addErrataRule = PF4Button('add-errata-id-button')
removeErratRule = Dropdown('cv-errata-id-bulk-action-dropdown')
moduleErrataTable = PatternflyTable(
component_id="content-view-errata-by-id-filter-table",
column_widgets={
0: Checkbox(locator='.//input[@type="checkbox"]'),
'Errata ID': Text('.//a'),
'Type': Text('.//a'),
'Issued': Text('.//a'),
'Updated': Text('.//a'),
'Severity': Text('.//a'),
'Synopsis': Text('.//a'),
'Status': Text('.//a'),
8: Dropdown(locator='.//div[contains(@class, "pf-c-dropdown")]'),
},
)

# Errata by Date Range

saveErrataByDate = PF4Button('save-filter-rule-button')
cancelErrataByDate = PF4Button('cancel-save-filter-rule-button')

@property
def is_displayed(self):
return self.name.is_displayed


class AddRPMRuleView(View):
ROOT = './/div[@data-ouia-component-id="add-edit-rpm-rule-modal"]'

rpmName = TextInput(
locator=".//div[contains(.//span, 'RPM name') and @class='pf-c-form__group']/*//input"
)
architecture = TextInput(
locator=".//div[contains(.//span, 'Architecture') and @class='pf-c-form__group']/*//input"
)

versions = PF4Select('version-comparator')
addEdit = PF4Button('add-edit-package-modal-submit')
cancel = PF4Button('add-edit-package-modal-cancel')


class AddContainerTagRuleView(View):
ROOT = './/div[@data-ouia-component-id="add-edit-container-tag-rule-modal"]'

tagName = TextInput(
locator=".//div[contains(.//span, 'Tag name') and @class='pf-c-form__group']/*//input"
)

addEdit = PF4Button('add-edit-container-tag-filter-rule-submit')
cancel = PF4Button('add-edit-container-tag-filter-rule-cancel')

0 comments on commit 2f635ac

Please sign in to comment.