mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 23:50:03 -06:00
WebUI tests: Extend user group tests with more scenarios
1) Extended webui group automation test with below scenarios Scenarios *Add user group with invalid names *Add multiple groups records at one shot *Select and delete multiple records *Find and delete records etc... 2) Improved add_record method to support additional use cases: *confirm by additional buttons: 'Add', 'Add and add another', 'Add and Edit,' 'Cancel' *add multiple records in one call (uses 'Add and add another' behavior) https://pagure.io/freeipa/issue/7485 Signed-off-by: Varun Mylaraiah <mvarun@redhat.com> Reviewed-By: Petr Vobornik <pvoborni@redhat.com> Reviewed-By: Michal Reznik <mreznik@redhat.com>
This commit is contained in:
parent
b43c2f8ab4
commit
105d7d7f2e
@ -78,3 +78,41 @@ DATA6 = {
|
||||
('textbox', 'gidnumber', '77777'),
|
||||
]
|
||||
}
|
||||
|
||||
PKEY7 = ''
|
||||
DATA7 = {
|
||||
'pkey': PKEY7,
|
||||
'add': [
|
||||
('textbox', 'cn', PKEY7),
|
||||
('textarea', 'description', 'Empty Group name'),
|
||||
]
|
||||
}
|
||||
|
||||
PKEY8 = ';test-gr@up'
|
||||
DATA8 = {
|
||||
'pkey': PKEY8,
|
||||
'add': [
|
||||
('textbox', 'cn', PKEY8),
|
||||
('textarea', 'description', 'Invalid Group name'),
|
||||
]
|
||||
}
|
||||
|
||||
PKEY9 = 'itest-group9'
|
||||
DATA9 = {
|
||||
'pkey': PKEY9,
|
||||
'add': [
|
||||
('textbox', 'cn', PKEY9),
|
||||
('textarea', 'description', 'test-group9 desc'),
|
||||
('radio', 'type', 'nonposix'),
|
||||
]
|
||||
}
|
||||
|
||||
PKEY10 = 'itest-group10'
|
||||
DATA10 = {
|
||||
'pkey': PKEY10,
|
||||
'add': [
|
||||
('textbox', 'cn', PKEY10),
|
||||
('textarea', 'description', 'test-group10 desc'),
|
||||
('radio', 'type', 'nonposix'),
|
||||
]
|
||||
}
|
||||
|
@ -31,6 +31,12 @@ import ipatests.test_webui.test_rbac as rbac
|
||||
import ipatests.test_webui.data_sudo as sudo
|
||||
import pytest
|
||||
|
||||
try:
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.common.action_chains import ActionChains
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.tier1
|
||||
class test_group(UI_driver):
|
||||
@ -75,6 +81,118 @@ class test_group(UI_driver):
|
||||
def check_posix_enabled(self, enabled):
|
||||
self.assert_disabled("[name=gidnumber]", negative=enabled)
|
||||
|
||||
@screenshot
|
||||
def test_add_group_negative(self):
|
||||
"""
|
||||
Negative test for adding groups
|
||||
"""
|
||||
self.init_app()
|
||||
|
||||
self.empty_group_name()
|
||||
self.invalid_group_name()
|
||||
self.duplicate_group_name()
|
||||
self.tailing_spaces_in_group_description()
|
||||
self.leading_spaces_in_group_description()
|
||||
|
||||
def empty_group_name(self):
|
||||
self.navigate_to_entity(group.ENTITY)
|
||||
self.facet_button_click('add')
|
||||
self.dialog_button_click('add')
|
||||
elem = self.find(".widget[name='cn']")
|
||||
self.assert_field_validation_required(elem)
|
||||
self.dialog_button_click('cancel')
|
||||
|
||||
def invalid_group_name(self):
|
||||
expected_error = 'may only include letters, numbers, _, -, . and $'
|
||||
pkey = ';test-gr@up'
|
||||
self.navigate_to_entity(group.ENTITY)
|
||||
self.facet_button_click('add')
|
||||
self.fill_input('cn', pkey)
|
||||
elem = self.find(".widget[name='cn']")
|
||||
self.assert_field_validation(expected_error, parent=elem)
|
||||
self.dialog_button_click('cancel')
|
||||
|
||||
def duplicate_group_name(self):
|
||||
pkey = 'editors'
|
||||
expected_error = 'group with name "editors" already exists'
|
||||
self.navigate_to_entity(group.ENTITY)
|
||||
self.facet_button_click('add')
|
||||
self.fill_input('cn', pkey)
|
||||
self.cancel_retry_dialog(expected_error)
|
||||
|
||||
def tailing_spaces_in_group_description(self):
|
||||
pkey = 'itest_group0'
|
||||
desc = 'with_trailing_space '
|
||||
expected_error = 'invalid \'desc\': Leading and trailing ' \
|
||||
'spaces are not allowed'
|
||||
self.navigate_to_entity(group.ENTITY)
|
||||
self.facet_button_click('add')
|
||||
self.fill_input('cn', pkey)
|
||||
self.fill_textarea('description', desc)
|
||||
self.cancel_retry_dialog(expected_error)
|
||||
|
||||
def leading_spaces_in_group_description(self):
|
||||
pkey = 'itest_group0'
|
||||
desc = ' with_leading_space'
|
||||
expected_error = 'invalid \'desc\': Leading and trailing' \
|
||||
' spaces are not allowed'
|
||||
self.navigate_to_entity(group.ENTITY)
|
||||
self.facet_button_click('add')
|
||||
self.fill_input('cn', pkey)
|
||||
self.fill_textarea('description', desc)
|
||||
self.cancel_retry_dialog(expected_error)
|
||||
|
||||
def cancel_retry_dialog(self, expected_error):
|
||||
self.dialog_button_click('add')
|
||||
dialog = self.get_last_error_dialog()
|
||||
assert (expected_error in dialog.text)
|
||||
self.wait_for_request()
|
||||
# Key press for Retry
|
||||
actions = ActionChains(self.driver)
|
||||
actions.send_keys(Keys.ENTER).perform()
|
||||
self.wait_for_request(n=2)
|
||||
self.dialog_button_click('cancel')
|
||||
self.wait_for_request(n=2)
|
||||
self.dialog_button_click('cancel')
|
||||
|
||||
@screenshot
|
||||
def test_add_multiple_group(self):
|
||||
"""
|
||||
Use 'add and add another' button to create multiple groups at one shot
|
||||
"""
|
||||
self.init_app()
|
||||
# adding a POSIX and a Non-POSIX group
|
||||
self.add_record(group.ENTITY, [group.DATA, group.DATA2])
|
||||
|
||||
# adding Two Non-POSIX groups
|
||||
self.add_record(group.ENTITY, [group.DATA9, group.DATA10])
|
||||
|
||||
# adding Two POSIX groups
|
||||
self.add_record(group.ENTITY, [group.DATA5, group.DATA6])
|
||||
|
||||
# delete multiple records
|
||||
records = [group.DATA, group.DATA2, group.DATA5, group.DATA6,
|
||||
group.DATA9, group.DATA10]
|
||||
self.select_multiple_records(records)
|
||||
self.facet_button_click('remove')
|
||||
self.dialog_button_click('ok')
|
||||
|
||||
@screenshot
|
||||
def test_add_and_edit_group(self):
|
||||
"""
|
||||
1. add and switch to edit mode
|
||||
2. add and cancel
|
||||
"""
|
||||
self.init_app()
|
||||
|
||||
# add and edit record
|
||||
self.add_record(group.ENTITY, group.DATA, dialog_btn='add_and_edit')
|
||||
self.switch_to_facet('details')
|
||||
self.delete_action()
|
||||
|
||||
# add then cancel
|
||||
self.add_record(group.ENTITY, group.DATA, dialog_btn='cancel')
|
||||
|
||||
@screenshot
|
||||
def test_actions(self):
|
||||
"""
|
||||
@ -124,11 +242,9 @@ class test_group(UI_driver):
|
||||
|
||||
# prepare
|
||||
# -------
|
||||
self.add_record(group.ENTITY, group.DATA)
|
||||
self.add_record(group.ENTITY, group.DATA2, navigate=False)
|
||||
self.add_record(group.ENTITY, group.DATA3, navigate=False)
|
||||
self.add_record(user.ENTITY, user.DATA)
|
||||
self.add_record(netgroup.ENTITY, netgroup.DATA)
|
||||
self.add_record(group.ENTITY, [group.DATA, group.DATA2, group.DATA3])
|
||||
self.add_record(user.ENTITY, [user.DATA, user.DATA2])
|
||||
self.add_record(netgroup.ENTITY, [netgroup.DATA, netgroup.DATA2])
|
||||
self.add_record(rbac.ROLE_ENTITY, rbac.ROLE_DATA)
|
||||
self.add_record(hbac.RULE_ENTITY, hbac.RULE_DATA)
|
||||
self.add_record(sudo.RULE_ENTITY, sudo.RULE_DATA)
|
||||
@ -137,24 +253,32 @@ class test_group(UI_driver):
|
||||
# -------------------------
|
||||
self.navigate_to_record(group.PKEY, entity=group.ENTITY)
|
||||
|
||||
# members
|
||||
self.add_associations([group.PKEY2], facet='member_group', delete=True)
|
||||
self.add_associations([user.PKEY], facet='member_user', delete=True)
|
||||
# "members" add with multiple select
|
||||
self.add_associations([group.PKEY2, group.PKEY3], facet='member_group',
|
||||
delete=True)
|
||||
self.add_associations([user.PKEY, user.PKEY2], facet='member_user',
|
||||
delete=True)
|
||||
# TODO: external
|
||||
|
||||
# member of
|
||||
self.add_associations([group.PKEY3], facet='memberof_group', delete=True)
|
||||
self.add_associations([netgroup.PKEY], facet='memberof_netgroup', delete=True)
|
||||
self.add_associations([rbac.ROLE_PKEY], facet='memberof_role', delete=True)
|
||||
self.add_associations([hbac.RULE_PKEY], facet='memberof_hbacrule', delete=True)
|
||||
# "member of": add with search
|
||||
self.add_associations([group.PKEY3, group.PKEY2],
|
||||
facet='memberof_group', delete=True, search=True)
|
||||
self.add_associations([netgroup.PKEY, netgroup.PKEY2],
|
||||
facet='memberof_netgroup',
|
||||
delete=True, search=True)
|
||||
self.add_associations([rbac.ROLE_PKEY], facet='memberof_role',
|
||||
delete=True)
|
||||
self.add_associations([hbac.RULE_PKEY], facet='memberof_hbacrule',
|
||||
delete=True)
|
||||
self.navigate_to_record(group.PKEY, entity=group.ENTITY)
|
||||
self.add_associations([sudo.RULE_PKEY], facet='memberof_sudorule', delete=True)
|
||||
self.add_associations([sudo.RULE_PKEY], facet='memberof_sudorule',
|
||||
delete=True, search=True)
|
||||
|
||||
# cleanup
|
||||
# -------
|
||||
self.delete(group.ENTITY, [group.DATA, group.DATA2, group.DATA3])
|
||||
self.delete(user.ENTITY, [user.DATA])
|
||||
self.delete(netgroup.ENTITY, [netgroup.DATA])
|
||||
self.delete(user.ENTITY, [user.DATA, user.DATA2])
|
||||
self.delete(netgroup.ENTITY, [netgroup.DATA, netgroup.DATA2])
|
||||
self.delete(rbac.ROLE_ENTITY, [rbac.ROLE_DATA])
|
||||
self.delete(hbac.RULE_ENTITY, [hbac.RULE_DATA])
|
||||
self.delete(sudo.RULE_ENTITY, [sudo.RULE_DATA])
|
||||
@ -168,11 +292,8 @@ class test_group(UI_driver):
|
||||
|
||||
# add
|
||||
# ---
|
||||
self.add_record(group.ENTITY, group.DATA)
|
||||
self.add_record(group.ENTITY, group.DATA2, navigate=False)
|
||||
self.add_record(group.ENTITY, group.DATA3, navigate=False)
|
||||
self.add_record(group.ENTITY, group.DATA4, navigate=False)
|
||||
self.add_record(group.ENTITY, group.DATA5, navigate=False)
|
||||
self.add_record(group.ENTITY, [group.DATA, group.DATA2, group.DATA3,
|
||||
group.DATA4, group.DATA5])
|
||||
self.add_record(user.ENTITY, user.DATA)
|
||||
|
||||
# prepare indirect member
|
||||
@ -215,15 +336,21 @@ class test_group(UI_driver):
|
||||
self.assert_indirect_record(user.PKEY, group.ENTITY, 'member_user')
|
||||
self.assert_indirect_record(group.PKEY3, group.ENTITY, 'member_group')
|
||||
|
||||
self.assert_indirect_record(group.PKEY5, group.ENTITY, 'memberof_group')
|
||||
self.assert_indirect_record(netgroup.PKEY, group.ENTITY, 'memberof_netgroup')
|
||||
self.assert_indirect_record(rbac.ROLE_PKEY, group.ENTITY, 'memberof_role')
|
||||
self.assert_indirect_record(hbac.RULE_PKEY, group.ENTITY, 'memberof_hbacrule')
|
||||
self.assert_indirect_record(sudo.RULE_PKEY, group.ENTITY, 'memberof_sudorule')
|
||||
self.assert_indirect_record(group.PKEY5, group.ENTITY,
|
||||
'memberof_group')
|
||||
self.assert_indirect_record(netgroup.PKEY, group.ENTITY,
|
||||
'memberof_netgroup')
|
||||
self.assert_indirect_record(rbac.ROLE_PKEY, group.ENTITY,
|
||||
'memberof_role')
|
||||
self.assert_indirect_record(hbac.RULE_PKEY, group.ENTITY,
|
||||
'memberof_hbacrule')
|
||||
self.assert_indirect_record(sudo.RULE_PKEY, group.ENTITY,
|
||||
'memberof_sudorule')
|
||||
|
||||
## cleanup
|
||||
## -------
|
||||
self.delete(group.ENTITY, [group.DATA, group.DATA2, group.DATA3, group.DATA4, group.DATA5])
|
||||
# cleanup
|
||||
# -------
|
||||
self.delete(group.ENTITY, [group.DATA, group.DATA2, group.DATA3,
|
||||
group.DATA4, group.DATA5])
|
||||
self.delete(user.ENTITY, [user.DATA])
|
||||
self.delete(netgroup.ENTITY, [netgroup.DATA])
|
||||
self.delete(rbac.ROLE_ENTITY, [rbac.ROLE_DATA])
|
||||
|
@ -1268,9 +1268,9 @@ class UI_driver(object):
|
||||
self.wait_for_request(n=2)
|
||||
|
||||
def add_record(self, entity, data, facet='search', facet_btn='add',
|
||||
dialog_btn='add', delete=False, pre_delete=True,
|
||||
dialog_name='add', navigate=True, combobox_input=None,
|
||||
negative=False):
|
||||
dialog_btn='add', add_another_btn='add_and_add_another',
|
||||
delete=False, pre_delete=True, dialog_name='add',
|
||||
navigate=True, combobox_input=None, negative=False):
|
||||
"""
|
||||
Add records.
|
||||
|
||||
@ -1285,8 +1285,15 @@ class UI_driver(object):
|
||||
],
|
||||
}
|
||||
"""
|
||||
pkey = data['pkey']
|
||||
if type(data) is not list:
|
||||
data = [data]
|
||||
|
||||
last_element = data[len(data) - 1]
|
||||
|
||||
pkeys = []
|
||||
|
||||
for record in data:
|
||||
pkeys.append(record['pkey'])
|
||||
if navigate:
|
||||
self.navigate_to_entity(entity, facet)
|
||||
|
||||
@ -1294,8 +1301,9 @@ class UI_driver(object):
|
||||
self.assert_facet(entity, facet)
|
||||
|
||||
# delete if exists, ie. from previous test fail
|
||||
|
||||
if pre_delete:
|
||||
self.delete_record(pkey, data.get('del'))
|
||||
self.delete(entity, data, navigate=False)
|
||||
|
||||
# current row count
|
||||
self.wait_for_request(0.5)
|
||||
@ -1306,40 +1314,58 @@ class UI_driver(object):
|
||||
self.facet_button_click(facet_btn)
|
||||
self.assert_dialog(dialog_name)
|
||||
|
||||
# fill dialog
|
||||
self.fill_fields(data['add'], combobox_input=combobox_input)
|
||||
for record in data:
|
||||
|
||||
# confirm dialog
|
||||
self.dialog_button_click(dialog_btn)
|
||||
self.wait_for_request()
|
||||
self.wait_for_request()
|
||||
# fill dialog
|
||||
self.fill_fields(record['add'], combobox_input=combobox_input)
|
||||
|
||||
# check expected error/warning/info
|
||||
expected = ['error_4304_info']
|
||||
dialog_info = self.get_dialog_info()
|
||||
if dialog_info and dialog_info['name'] in expected:
|
||||
self.dialog_button_click('ok')
|
||||
btn = dialog_btn
|
||||
|
||||
if record != last_element:
|
||||
btn = add_another_btn
|
||||
|
||||
self.dialog_button_click(btn)
|
||||
self.wait_for_request()
|
||||
self.wait_for_request()
|
||||
|
||||
if negative:
|
||||
# check expected error/warning/info
|
||||
expected = ['error_4304_info']
|
||||
dialog_info = self.get_dialog_info()
|
||||
if dialog_info and dialog_info['name'] in expected:
|
||||
self.dialog_button_click('ok')
|
||||
self.wait_for_request()
|
||||
|
||||
if negative:
|
||||
return
|
||||
|
||||
# check for error
|
||||
self.assert_no_error_dialog()
|
||||
self.wait_for_request()
|
||||
self.wait_for_request(0.4)
|
||||
|
||||
if dialog_btn == 'add_and_edit':
|
||||
page_pkey = self.get_text('.facet-pkey')
|
||||
assert record['pkey'] in page_pkey
|
||||
# we cannot delete because we are on different page
|
||||
return
|
||||
|
||||
# check for error
|
||||
self.assert_no_error_dialog()
|
||||
self.wait_for_request()
|
||||
self.wait_for_request(0.4)
|
||||
|
||||
# check if table has more rows
|
||||
elif dialog_btn == add_another_btn:
|
||||
# dialog is still open, we cannot check for records on search page
|
||||
# or delete the records
|
||||
return
|
||||
elif dialog_btn == 'cancel':
|
||||
return
|
||||
# when standard 'add' was used then it will land on search page
|
||||
# and we can check if new item was added - table has more rows
|
||||
new_count = len(self.get_rows())
|
||||
# adjust because of paging
|
||||
expected = count + 1
|
||||
expected = count + len(data)
|
||||
if count == 20:
|
||||
expected = 20
|
||||
self.assert_row_count(expected, new_count)
|
||||
|
||||
# delete record
|
||||
if delete:
|
||||
self.delete_record(pkey)
|
||||
self.delete(entity, data, navigate=False)
|
||||
new_count = len(self.get_rows())
|
||||
self.assert_row_count(count, new_count)
|
||||
|
||||
@ -1403,10 +1429,9 @@ class UI_driver(object):
|
||||
self.wait_for_request()
|
||||
|
||||
# 2. Add record
|
||||
self.add_record(parent_entity, data, facet=search_facet, navigate=False,
|
||||
facet_btn=add_facet_btn, dialog_name=add_dialog_name,
|
||||
dialog_btn=add_dialog_btn
|
||||
)
|
||||
self.add_record(parent_entity, data, facet=search_facet,
|
||||
navigate=False, facet_btn=add_facet_btn,
|
||||
dialog_name=add_dialog_name, dialog_btn=add_dialog_btn)
|
||||
|
||||
self.close_notifications()
|
||||
|
||||
@ -1458,7 +1483,7 @@ class UI_driver(object):
|
||||
|
||||
def prepare_associations(
|
||||
self, pkeys, facet=None, facet_btn='add', member_pkeys=None,
|
||||
confirm_btn='add'):
|
||||
confirm_btn='add', search=False):
|
||||
"""
|
||||
Helper function for add_associations and delete_associations
|
||||
"""
|
||||
@ -1469,8 +1494,18 @@ class UI_driver(object):
|
||||
self.wait()
|
||||
self.wait_for_request()
|
||||
|
||||
for key in pkeys:
|
||||
self.select_record(key, table_name='available')
|
||||
if search is True:
|
||||
for key in pkeys:
|
||||
search_field_s = '.adder-dialog-top input[name="filter"]'
|
||||
self.fill_text(search_field_s, key)
|
||||
self._button_click(selector="button[name='find'].btn-default",
|
||||
parent=None)
|
||||
self.wait_for_request()
|
||||
self.select_record(key, table_name='available')
|
||||
self.button_click('add')
|
||||
else:
|
||||
for key in pkeys:
|
||||
self.select_record(key, table_name='available')
|
||||
self.button_click('add')
|
||||
|
||||
self.dialog_button_click(confirm_btn)
|
||||
@ -1485,18 +1520,19 @@ class UI_driver(object):
|
||||
|
||||
def add_associations(
|
||||
self, pkeys, facet=None, delete=False, facet_btn='add',
|
||||
member_pkeys=None, confirm_btn='add'):
|
||||
member_pkeys=None, confirm_btn='add', search=False):
|
||||
"""
|
||||
Add associations
|
||||
"""
|
||||
check_pkeys = self.prepare_associations(
|
||||
pkeys, facet, facet_btn, member_pkeys, confirm_btn=confirm_btn)
|
||||
pkeys, facet, facet_btn, member_pkeys, confirm_btn, search)
|
||||
|
||||
# we need to return if we want to "cancel" to avoid assert record fail
|
||||
if confirm_btn == 'cancel':
|
||||
return
|
||||
|
||||
for key in check_pkeys:
|
||||
|
||||
self.assert_record(key)
|
||||
if delete:
|
||||
self.delete_record(key)
|
||||
@ -1513,7 +1549,8 @@ class UI_driver(object):
|
||||
for key in check_pkeys:
|
||||
self.assert_record(key, negative=True)
|
||||
|
||||
def add_table_associations(self, table_name, pkeys, parent=False, delete=False):
|
||||
def add_table_associations(self, table_name, pkeys, parent=False,
|
||||
delete=False):
|
||||
"""
|
||||
Add value to table (association|rule|...)
|
||||
"""
|
||||
@ -1987,9 +2024,9 @@ class UI_driver(object):
|
||||
assert is_enabled == enabled, ('Invalid enabled state of action item %s. '
|
||||
'Expected: %s') % (action, str(visible))
|
||||
|
||||
def assert_field_validation_required(self, parent=None):
|
||||
def assert_field_validation(self, expect_error, parent=None):
|
||||
"""
|
||||
Assert we got 'Required field' error message in field validation
|
||||
Assert for error in field validation
|
||||
"""
|
||||
|
||||
if not parent:
|
||||
@ -1998,7 +2035,11 @@ class UI_driver(object):
|
||||
req_field_css = '.help-block[name="error_link"]'
|
||||
|
||||
res = self.find(req_field_css, By.CSS_SELECTOR, context=parent)
|
||||
assert 'Required field' in res.text, 'No "Required field" error found'
|
||||
assert expect_error in res.text, \
|
||||
'Expected error: {} not found'.format(expect_error)
|
||||
|
||||
def assert_field_validation_required(self, parent=None):
|
||||
self.assert_field_validation('Required field', parent)
|
||||
|
||||
def assert_notification(self, type='success', assert_text=None):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user