diff --git a/airgun/entities/contentview_new.py b/airgun/entities/contentview_new.py index fa2275d92..469017207 100644 --- a/airgun/entities/contentview_new.py +++ b/airgun/entities/contentview_new.py @@ -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, ) @@ -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): @@ -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.""" @@ -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.""" @@ -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() diff --git a/airgun/views/contentview_new.py b/airgun/views/contentview_new.py index 5def17d15..9415f54ce 100644 --- a/airgun/views/contentview_new.py +++ b/airgun/views/contentview_new.py @@ -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, ) @@ -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): @@ -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): @@ -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')