Skip to content

Commit 3e9beb5

Browse files
authored
Extend flatpak view and entity with remote details page and actions (SatelliteQE#1924)
1 parent bc3d5fe commit 3e9beb5

2 files changed

Lines changed: 194 additions & 18 deletions

File tree

airgun/entities/flatpak.py

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1+
from time import sleep
2+
13
from airgun.entities.base import BaseEntity
24
from airgun.navigation import NavigateStep, navigator
3-
from airgun.views.flatpak import FlatpakRemotesView
5+
from airgun.utils import retry_navigation
6+
from airgun.views.flatpak import (
7+
CreateFlatpakRemoteModal,
8+
EditFlatpakRemoteModal,
9+
FlatpakRemoteDeleteModal,
10+
FlatpakRemoteDetailsView,
11+
FlatpakRemotesView,
12+
MirrorFlatpakRemoteModal,
13+
)
414

515

616
class FlatpakRemotesEntity(BaseEntity):
@@ -40,17 +50,38 @@ def read_table(self):
4050
view.wait_displayed()
4151
return view.table.read()
4252

43-
def scan(self, entity_name):
44-
"""Scan a Flatpak remote.
53+
def read_remote_details(self, name, repo_search=None):
54+
"""
55+
Read details from the Flatpak remote details page
4556
46-
:param str entity_name: name of the remote to scan
57+
Args:
58+
name (str): Name of the flatpak remote to be read
59+
repo_search (str, optional): Name of scanned remote repository to be searched
4760
"""
4861
view = self.navigate_to(self, 'All')
4962
view.wait_displayed()
50-
view.table.row(name=entity_name)[2].click()
51-
view.table.row(name=entity_name)[2].widget.item_select('Scan')
52-
view.flash.assert_no_error()
53-
view.flash.dismiss()
63+
view.search(name)
64+
view.table.row(name=name)['Name'].widget.click()
65+
view = FlatpakRemoteDetailsView(self.browser)
66+
view.wait_displayed()
67+
if repo_search:
68+
view.search(repo_search)
69+
return view.read()
70+
71+
def create(self, values):
72+
"""Create a Flatpak remote.
73+
74+
:param dict values: values to create the remote with
75+
"""
76+
view = self.navigate_to(self, 'All')
77+
view.wait_displayed()
78+
view.create_new_btn.click()
79+
create_modal = CreateFlatpakRemoteModal(self.browser)
80+
create_modal.wait_displayed()
81+
create_modal.fill(values)
82+
create_modal.create_btn.click()
83+
view = FlatpakRemoteDetailsView(self.browser)
84+
view.wait_displayed(delay=3)
5485

5586
def edit(self, entity_name, values):
5687
"""Edit a Flatpak remote.
@@ -62,10 +93,12 @@ def edit(self, entity_name, values):
6293
view.wait_displayed()
6394
view.table.row(name=entity_name)[2].click()
6495
view.table.row(name=entity_name)[2].widget.item_select('Edit')
65-
view.fill(values)
66-
view.submit.click()
67-
view.flash.assert_no_error()
68-
view.flash.dismiss()
96+
edit_modal = EditFlatpakRemoteModal(self.browser)
97+
edit_modal.wait_displayed()
98+
edit_modal.fill(values)
99+
edit_modal.update_btn.click()
100+
view = FlatpakRemoteDetailsView(self.browser)
101+
view.wait_displayed(delay=3)
69102

70103
def delete(self, entity_name):
71104
"""Delete a Flatpak remote.
@@ -76,16 +109,55 @@ def delete(self, entity_name):
76109
view.wait_displayed()
77110
view.table.row(name=entity_name)[2].click()
78111
view.table.row(name=entity_name)[2].widget.item_select('Delete')
79-
self.browser.handle_alert()
112+
delete_modal = FlatpakRemoteDeleteModal(self.browser)
113+
delete_modal.wait_displayed()
114+
delete_modal.delete_btn.click()
115+
sleep(3)
116+
self.browser.plugin.ensure_page_safe()
117+
view = FlatpakRemotesView(self.browser)
118+
view.wait_displayed(delay=3)
119+
120+
def scan(self, entity_name):
121+
"""Scan a Flatpak remote.
122+
123+
:param str entity_name: name of the remote to scan
124+
"""
125+
view = self.navigate_to(self, 'All')
126+
view.wait_displayed()
127+
view.table.row(name=entity_name)[2].click()
128+
view.table.row(name=entity_name)[2].widget.item_select('Scan')
80129
view.flash.assert_no_error()
81130
view.flash.dismiss()
82131

132+
def mirror(self, remote, repo, product):
133+
"""Mirror a repository from Flatpak remote.
134+
135+
:param str remote: name of the remote to mirror from
136+
:param str repo: name of the repository to be mirrored
137+
:param str product: name of the product where the repository should be mirrored
138+
"""
139+
view = self.navigate_to(self, 'All')
140+
view.wait_displayed()
141+
view.search(remote)
142+
view.table.row(name=remote)['Name'].widget.click()
143+
view = FlatpakRemoteDetailsView(self.browser)
144+
view.wait_displayed()
145+
view.search(repo) # in case of many repos
146+
view.table.row(name=repo)['Mirror'].widget.click()
147+
mirror_modal = MirrorFlatpakRemoteModal(self.browser)
148+
mirror_modal.wait_displayed()
149+
mirror_modal.searchbar.fill(product.name)
150+
self.browser.plugin.ensure_page_safe()
151+
mirror_modal.mirror_btn.click()
152+
view.wait_displayed(delay=3)
153+
83154

84155
@navigator.register(FlatpakRemotesEntity, 'All')
85156
class ShowAllFlatpakRemotes(NavigateStep):
86157
"""Navigate to All Flatpak Remotes page."""
87158

88159
VIEW = FlatpakRemotesView
89160

161+
@retry_navigation
90162
def step(self, *args, **kwargs):
91163
self.view.menu.select('Content', 'Flatpak Remotes')

airgun/views/flatpak.py

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
from widgetastic.widget import Text
22
from widgetastic_patternfly5 import (
3+
Button as PF5Button,
34
Menu as PF5Menu,
5+
Modal as PF5Modal,
46
Pagination,
57
)
68
from widgetastic_patternfly5.ouia import (
79
PatternflyTable as PF5OUIATable,
10+
Text as PF5OUIAText,
11+
TextInput as PF5OUIATextInput,
12+
Title as PF5OUIATitle,
813
)
914

1015
from airgun.views.common import BaseLoggedInView, SearchableViewMixinPF4
16+
from airgun.widgets import SearchInput
1117

1218

1319
class FlatpakRemotesView(BaseLoggedInView, SearchableViewMixinPF4):
@@ -18,10 +24,12 @@ class FlatpakRemotesView(BaseLoggedInView, SearchableViewMixinPF4):
1824
table_loading = Text("//h5[normalize-space(.)='Loading']")
1925
no_results = Text("//h5[normalize-space(.)='No Results']")
2026

27+
create_new_btn = PF5Button('Create new')
28+
2129
table = PF5OUIATable(
2230
component_id='flatpak-remotes-table',
2331
column_widgets={
24-
'Name': Text('./a'),
32+
'Name': Text('./a[contains(@href, "flatpak_remotes")]'),
2533
'URL': Text('./a'),
2634
2: PF5Menu(locator='.//div[contains(@class, "pf-v5-c-menu")]'),
2735
},
@@ -30,7 +38,103 @@ class FlatpakRemotesView(BaseLoggedInView, SearchableViewMixinPF4):
3038

3139
@property
3240
def is_displayed(self):
33-
return (
34-
self.browser.wait_for_element(self.table_loading, exception=False) is None
35-
and self.browser.wait_for_element(self.table, exception=False) is not None
36-
)
41+
return self.browser.wait_for_element(self.create_new_btn, exception=False) is not None
42+
43+
44+
class FlatpakRemoteDetailsView(BaseLoggedInView, SearchableViewMixinPF4):
45+
"""View for the Flatpak Remote details page"""
46+
47+
title = PF5OUIATitle('flatpak-remote-title')
48+
url = PF5OUIAText('url-text-value')
49+
subtitle = PF5OUIATitle('flatpak-remote-subtitle')
50+
description = PF5OUIAText('flatpak-remote-description')
51+
52+
table = PF5OUIATable(
53+
component_id='remote-repos-table',
54+
column_widgets={
55+
'Name': Text('./a'),
56+
'ID': Text('./a'),
57+
'Application name': Text('./a'),
58+
'Last mirrored': Text('./a'),
59+
'Mirror': PF5Button('Mirror'),
60+
},
61+
)
62+
pagination = Pagination("//div[@class = 'pf-v5-c-pagination pf-m-bottom tfm-pagination']")
63+
64+
@property
65+
def is_displayed(self):
66+
return self.browser.wait_for_element(self.title, exception=False) is not None
67+
68+
69+
class CreateFlatpakRemoteModal(PF5Modal):
70+
"""View for the Create Flatpak Remote modal"""
71+
72+
ROOT = './/div[@data-ouia-component-id="create-flatpak-modal"]'
73+
74+
title = Text("//span[normalize-space(.)='Create Flatpak Remote']")
75+
76+
name = PF5OUIATextInput('input_name')
77+
url = PF5OUIATextInput('input_url')
78+
username = PF5OUIATextInput('input_username')
79+
password = PF5OUIATextInput('input_password')
80+
81+
create_btn = PF5Button('Create')
82+
cancel_btn = PF5Button('Cancel')
83+
84+
@property
85+
def is_displayed(self):
86+
return self.browser.wait_for_element(self.title, exception=False) is not None
87+
88+
89+
class EditFlatpakRemoteModal(PF5Modal):
90+
"""View for the Edit Flatpak Remote modal"""
91+
92+
ROOT = './/div[@data-ouia-component-id="edit-flatpak-modal"]'
93+
94+
title = Text("//span[normalize-space(.)='Edit Flatpak Remote']")
95+
96+
name = PF5OUIATextInput('input_name')
97+
url = PF5OUIATextInput('input_url')
98+
username = PF5OUIATextInput('input_username')
99+
password = PF5OUIATextInput('input_password')
100+
101+
update_btn = PF5Button('Update')
102+
cancel_btn = PF5Button('Cancel')
103+
104+
@property
105+
def is_displayed(self):
106+
return self.browser.wait_for_element(self.title, exception=False) is not None
107+
108+
109+
class MirrorFlatpakRemoteModal(PF5Modal, SearchableViewMixinPF4):
110+
"""View for the Mirror Flatpak Remote modal"""
111+
112+
ROOT = './/div[@data-ouia-component-id="mirror-repo-modal"]'
113+
114+
title = Text("//span[normalize-space(.)='Mirror Repository']")
115+
116+
searchbar = SearchInput(
117+
locator='.//input[contains(@class, "pf-v5-c-text-input-group__text-input")]'
118+
)
119+
120+
mirror_btn = PF5Button('Mirror')
121+
cancel_btn = PF5Button('Cancel')
122+
123+
@property
124+
def is_displayed(self):
125+
return self.browser.wait_for_element(self.title, exception=False) is not None
126+
127+
128+
class FlatpakRemoteDeleteModal(PF5Modal):
129+
"""Confirmation dialog for deleting Flatpak Remote"""
130+
131+
ROOT = './/div[@data-ouia-component-id="flatpak-delete-modal"]'
132+
133+
title = Text("//span[normalize-space(.)='Delete Flatpak remote?']")
134+
135+
delete_btn = PF5Button('Delete')
136+
cancel_btn = PF5Button('Cancel')
137+
138+
@property
139+
def is_displayed(self):
140+
return self.browser.wait_for_element(self.title, exception=False) is not None

0 commit comments

Comments
 (0)