From e1fde47a0c2c3a3d9d12747857cbf489158b32ad Mon Sep 17 00:00:00 2001 From: Jan Jasek Date: Fri, 29 Nov 2024 02:59:50 +0100 Subject: [PATCH] Allow configuring separated UI tests for different themes Allow configuring of locators/parts of the tests that are theme specific, using a config file. Change-Id: I3ea3d0cf42dc8e89a23a763defe84389da56366b --- .../test/integration_tests/config.py | 40 ++++++ .../test/integration_tests/horizon.conf | 15 +++ .../test/selenium/ui/test_browse.py | 120 ++++++++++-------- .../test/selenium/ui/test_settings.py | 30 +++-- 4 files changed, 140 insertions(+), 65 deletions(-) diff --git a/openstack_dashboard/test/integration_tests/config.py b/openstack_dashboard/test/integration_tests/config.py index 11b39f0ab0..d2be001a45 100644 --- a/openstack_dashboard/test/integration_tests/config.py +++ b/openstack_dashboard/test/integration_tests/config.py @@ -200,6 +200,46 @@ ThemeGroup = [ default=['.//*[@class="dropdown user-menu"]', './/*[normalize-space()="Help"]'], help='Default steps for redirect to help URL'), + cfg.BoolOpt('test_material_theme', + default=True, + help='Set to False to disallow running the material ' + 'theme test'), + cfg.StrOpt('user_name_xpath', + default='.//*[@class="dropdown user-menu"]', + help='Default xpath for user name dropdown button'), + cfg.ListOpt('browse_left_panel_main', + default=['Project', 'Project', 'Project', 'Project', + 'Project', 'Project', 'Project', 'Project', + 'Project', 'Project', 'Project', 'Project', + 'Project', 'Project', 'Project', 'Project', + 'Admin', 'Admin', 'Admin', 'Admin', 'Admin', + 'Admin', 'Admin', 'Admin', 'Admin', 'Admin', + 'Admin', 'Admin', 'Admin', 'Admin', 'Admin', + 'Admin', 'Admin', 'Admin', 'Identity', 'Identity', + 'Identity', 'Identity', 'Identity'], + help='Main buttons for left browse panel'), + cfg.ListOpt('browse_left_panel_sec', + default=['None', 'Compute', 'Compute', 'Compute', 'Compute', + 'Compute', 'Volumes', 'Volumes', 'Network', + 'Network', 'Network', 'Network', 'Network', + 'Network', 'Network', 'Object store', 'None', + 'Compute', 'Compute', 'Compute', 'Compute', 'Compute', + 'Volume', 'Volume', 'Volume', 'Volume', 'Network', + 'Network', 'Network', 'Network', 'Network', 'Admin', + 'Admin', 'Admin', 'None', 'None', 'None', 'None', + 'None'], + help='Secondary buttons for left browse panel'), + cfg.StrOpt('b_l_p_sec_line_xpath', + default='.//*[@id="sidebar-accordion-{main_panel}"]', + help='Default xpath for first dropdown of browse panel'), + cfg.StrOpt('b_l_p_sec_line_req_btn', + default='.//a[@data-target=' + '"#sidebar-accordion-{main_panel}-{sec_panel}"]', + help='Default xpath for button for open second dropdown of ' + 'left browse panel'), + cfg.StrOpt('b_l_p_sidebar_xpath', + default='.//*[@id="sidebar-accordion-{main_panel}-{sec_panel}"]', + help='Default xpath for second dropdown of browse panel'), ] diff --git a/openstack_dashboard/test/integration_tests/horizon.conf b/openstack_dashboard/test/integration_tests/horizon.conf index d49d6217af..a80cd715a0 100644 --- a/openstack_dashboard/test/integration_tests/horizon.conf +++ b/openstack_dashboard/test/integration_tests/horizon.conf @@ -118,3 +118,18 @@ project_name_xpath=//*[@class="context-project"]//ancestor::ul #sequence for redirect to help URL help_sequence=.//*[@class="dropdown user-menu"],.//*[normalize-space()="Help"] + +#test material theme? +test_material_theme=True + +#xpath for user name (dropdown button) +user_name_xpath=.//*[@class="dropdown user-menu"] + +#buttons for browse left panel +browse_left_panel_main=project,project,project,project,project,project,project,project,project,project,project,project,project,project,project,project,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,admin,identity,identity,identity,identity,identity +browse_left_panel_sec=None,compute,compute,compute,compute,compute,volumes,volumes,network,network,network,network,network,network,network,object_store,None,compute,compute,compute,compute,compute,volume,volume,volume,volume,network,network,network,network,network,admin,admin,admin,None,None,None,None,None + +#xpaths for browse left panel test +b_l_p_sec_line_xpath=.//*[@id="sidebar-accordion-{main_panel}"] +b_l_p_sec_line_req_btn=.//a[@data-target="#sidebar-accordion-{main_panel}-{sec_panel}"] +b_l_p_sidebar_xpath=.//*[@id="sidebar-accordion-{main_panel}-{sec_panel}"] diff --git a/openstack_dashboard/test/selenium/ui/test_browse.py b/openstack_dashboard/test/selenium/ui/test_browse.py index ce5275b0c9..8384614a3a 100644 --- a/openstack_dashboard/test/selenium/ui/test_browse.py +++ b/openstack_dashboard/test/selenium/ui/test_browse.py @@ -17,91 +17,98 @@ from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait +from openstack_dashboard.test.integration_tests import config + from openstack_dashboard import api from openstack_dashboard.test.selenium import widgets +# Get browse_left_panel lists +conf = config.get_config() +t_b_p_m = conf.theme.browse_left_panel_main +t_b_p_s = conf.theme.browse_left_panel_sec + @pytest.mark.parametrize( "main_panel, sec_panel, link_text, title, h1_text", [ - ("project", None, "API Access", "API Access - OpenStack Dashboard", - "API Access"), - ("project", "compute", "Overview", + (t_b_p_m[0], t_b_p_s[0], "API Access", + "API Access - OpenStack Dashboard", "API Access"), + (t_b_p_m[1], t_b_p_s[1], "Overview", "Instance Overview - OpenStack Dashboard", "Overview"), - ("project", "compute", "Instances", + (t_b_p_m[2], t_b_p_s[2], "Instances", "Instances - OpenStack Dashboard", "Instances"), - ("project", "compute", "Images", + (t_b_p_m[3], t_b_p_s[3], "Images", "Images - OpenStack Dashboard", "Images"), - ("project", "compute", "Key Pairs", + (t_b_p_m[4], t_b_p_s[4], "Key Pairs", "Key Pairs - OpenStack Dashboard", "Key Pairs"), - ("project", "compute", "Server Groups", + (t_b_p_m[5], t_b_p_s[5], "Server Groups", "Server Groups - OpenStack Dashboard", "Server Groups"), - ("project", "volumes", "Volumes", + (t_b_p_m[6], t_b_p_s[6], "Volumes", "Volumes - OpenStack Dashboard", "Volumes"), - ("project", "volumes", "Snapshots", + (t_b_p_m[7], t_b_p_s[7], "Snapshots", "Volume Snapshots - OpenStack Dashboard", "Volume Snapshots"), - ("project", "network", "Network Topology", + (t_b_p_m[8], t_b_p_s[8], "Network Topology", "Network Topology - OpenStack Dashboard", "Network Topology"), - ("project", "network", "Networks", + (t_b_p_m[9], t_b_p_s[9], "Networks", "Networks - OpenStack Dashboard", "Networks"), - ("project", "network", "Routers", + (t_b_p_m[10], t_b_p_s[10], "Routers", "Routers - OpenStack Dashboard", "Routers"), - ("project", "network", "Security Groups", + (t_b_p_m[11], t_b_p_s[11], "Security Groups", "Security Groups - OpenStack Dashboard", "Security Groups"), - ("project", "network", "Floating IPs", + (t_b_p_m[12], t_b_p_s[12], "Floating IPs", "Floating IPs - OpenStack Dashboard", "Floating IPs"), - ("project", "network", "Trunks", + (t_b_p_m[13], t_b_p_s[13], "Trunks", "Trunks - OpenStack Dashboard", "Trunks"), - ("project", "network", "Network QoS", + (t_b_p_m[14], t_b_p_s[14], "Network QoS", "Network QoS Policies - OpenStack Dashboard", "QoS Policies"), - ("project", "object_store", "Containers", + (t_b_p_m[15], t_b_p_s[15], "Containers", "Containers - OpenStack Dashboard", "Containers"), - ("admin", None, "Overview", + (t_b_p_m[16], t_b_p_s[16], "Overview", "Usage Overview - OpenStack Dashboard", "Overview"), - ("admin", "compute", "Hypervisors", + (t_b_p_m[17], t_b_p_s[17], "Hypervisors", "Hypervisors - OpenStack Dashboard", "All Hypervisors"), - ("admin", "compute", "Host Aggregates", + (t_b_p_m[18], t_b_p_s[18], "Host Aggregates", "Host Aggregates - OpenStack Dashboard", "Host Aggregates"), - ("admin", "compute", "Instances", + (t_b_p_m[19], t_b_p_s[19], "Instances", "Instances - OpenStack Dashboard", "Instances"), - ("admin", "compute", "Flavors", + (t_b_p_m[20], t_b_p_s[20], "Flavors", "Flavors - OpenStack Dashboard", "Flavors"), - ("admin", "compute", "Images", + (t_b_p_m[21], t_b_p_s[21], "Images", "Images - OpenStack Dashboard", "Images"), - ("admin", "volume", "Volumes", + (t_b_p_m[22], t_b_p_s[22], "Volumes", "Volumes - OpenStack Dashboard", "Volumes"), - ("admin", "volume", "Snapshots", + (t_b_p_m[23], t_b_p_s[23], "Snapshots", "Volume Snapshots - OpenStack Dashboard", "Volume Snapshots"), - ("admin", "volume", "Volume Types", + (t_b_p_m[24], t_b_p_s[24], "Volume Types", "Volume Types - OpenStack Dashboard", "Volume Types"), - ("admin", "volume", "Group Types", + (t_b_p_m[25], t_b_p_s[25], "Group Types", "Group Types - OpenStack Dashboard", "Group Types"), - ("admin", "network", "Networks", + (t_b_p_m[26], t_b_p_s[26], "Networks", "Networks - OpenStack Dashboard", "Networks"), - ("admin", "network", "Routers", + (t_b_p_m[27], t_b_p_s[27], "Routers", "Routers - OpenStack Dashboard", "Routers"), - ("admin", "network", "Floating IPs", + (t_b_p_m[28], t_b_p_s[28], "Floating IPs", "Floating IPs - OpenStack Dashboard", "Floating IPs"), - ("admin", "network", "Trunks", + (t_b_p_m[29], t_b_p_s[29], "Trunks", "Trunks - OpenStack Dashboard", "Trunks"), - ("admin", "network", "RBAC Policies", + (t_b_p_m[30], t_b_p_s[30], "RBAC Policies", "RBAC Policies - OpenStack Dashboard", "RBAC Policies"), - ("admin", "admin", "Defaults", + (t_b_p_m[31], t_b_p_s[31], "Defaults", "Defaults - OpenStack Dashboard", "Defaults"), - ("admin", "admin", "Metadata Definitions", + (t_b_p_m[32], t_b_p_s[32], "Metadata Definitions", "Metadata Definitions - OpenStack Dashboard", "Metadata Definitions"), - ("admin", "admin", "System Information", + (t_b_p_m[33], t_b_p_s[33], "System Information", "System Information - OpenStack Dashboard", "System Information"), - ("identity", None, "Projects", + (t_b_p_m[34], t_b_p_s[34], "Projects", "Projects - OpenStack Dashboard", "Projects"), - ("identity", None, "Users", + (t_b_p_m[35], t_b_p_s[35], "Users", "Users - OpenStack Dashboard", "Users"), - ("identity", None, "Groups", + (t_b_p_m[36], t_b_p_s[36], "Groups", "Groups - OpenStack Dashboard", "Groups"), - ("identity", None, "Roles", + (t_b_p_m[37], t_b_p_s[37], "Roles", "Roles - OpenStack Dashboard", "Roles"), - ("identity", None, "Application Credentials", + (t_b_p_m[38], t_b_p_s[38], "Application Credentials", "Application Credentials - OpenStack Dashboard", "Application Credentials"), ] @@ -139,34 +146,41 @@ def test_browse_left_panel(live_server, driver, user, dashboard_data, } driver.get(live_server.url + '/settings') - driver.find_element_by_css_selector( - f"a[data-target='#sidebar-accordion-{main_panel}']").click() - if sec_panel is not None: + # First scroll click + driver.find_element_by_xpath( + f".//a[normalize-space()='{main_panel.capitalize()}']").click() + if sec_panel != 'None': + sec_line_req_button = config.theme.b_l_p_sec_line_req_btn.format( + main_panel=main_panel, sec_panel=sec_panel) + # Second scroll click WebDriverWait(driver, config.selenium.implicit_wait).until( EC.element_to_be_clickable( - (By.CSS_SELECTOR, f"a[data-target='#sidebar-accordion" - f"-{main_panel}-{sec_panel}']"))).click() - sidebar = driver.find_element_by_id( - f"sidebar-accordion-{main_panel}-{sec_panel}") + (By.XPATH, sec_line_req_button))).click() + sidebar_xpath = config.theme.b_l_p_sidebar_xpath.format( + main_panel=main_panel, sec_panel=sec_panel) + # Get tab with output of second scroll + sidebar = driver.find_element_by_xpath(sidebar_xpath) else: - sidebar = driver.find_element_by_id( - f"sidebar-accordion-{main_panel}") + # In case there is not second scroll + sec_line_xpath = config.theme.b_l_p_sec_line_xpath.format( + main_panel=main_panel) + sidebar = driver.find_element_by_xpath(sec_line_xpath) sidebar.find_element_by_link_text(link_text).click() assert driver.title == title assert driver.find_element_by_css_selector("h1").text == h1_text -def test_browse_user_setting_tab(live_server, driver, user): +def test_browse_user_setting_tab(live_server, driver, user, config): driver.get(live_server.url + '/project/api_access') - user_button = driver.find_element_by_class_name("dropdown.user-menu") + user_button = driver.find_element_by_xpath(config.theme.user_name_xpath) widgets.select_from_dropdown(user_button, "Settings") assert driver.title == "User Settings - OpenStack Dashboard" assert driver.find_element_by_css_selector("h1").text == "User Settings" -def test_browse_change_password_tab(live_server, driver, user): +def test_browse_change_password_tab(live_server, driver, user, config): driver.get(live_server.url + '/project/api_access') - user_button = driver.find_element_by_class_name("dropdown.user-menu") + user_button = driver.find_element_by_xpath(config.theme.user_name_xpath) widgets.select_from_dropdown(user_button, "Settings") driver.find_element_by_link_text("Change Password").click() assert driver.title == "Change Password - OpenStack Dashboard" diff --git a/openstack_dashboard/test/selenium/ui/test_settings.py b/openstack_dashboard/test/selenium/ui/test_settings.py index 7b32370634..661f88a28a 100644 --- a/openstack_dashboard/test/selenium/ui/test_settings.py +++ b/openstack_dashboard/test/selenium/ui/test_settings.py @@ -12,6 +12,8 @@ from unittest import mock +import pytest + from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait @@ -22,19 +24,10 @@ from openstack_dashboard.test.selenium import widgets import horizon -def test_languages(live_server, driver, user): - driver.get(live_server.url + '/settings') - user_settings = driver.find_element_by_id('user_settings_modal') - language_options = user_settings.find_element_by_id('id_language') - language_options.click() - language_options.find_element_by_xpath("//option[@value='de']").click() - user_settings.find_element_by_xpath('//*[@class="btn btn-primary"]').click() - messages = widgets.get_and_dismiss_messages(driver) - assert "Success: Settings saved." in messages - assert "Error" not in messages - - def test_switch_to_material_theme(live_server, driver, user, config): + if not config.theme.test_material_theme: + pytest.skip("Test material theme skipped.") + driver.get(live_server.url + '/settings') user_dropdown_menu = driver.find_element_by_css_selector( '.nav.navbar-nav.navbar-right') @@ -98,3 +91,16 @@ def test_message_after_password_change(live_server, driver, user, mocked_a_l_r.assert_called_once() assert (mocked_a_l_r.call_args.args[2] == 'Password changed. Please log in again to continue.') + + +def test_languages(live_server, driver, user): + driver.get(live_server.url + '/settings') + user_settings = driver.find_element_by_id('user_settings_modal') + language_options = user_settings.find_element_by_id('id_language') + language_options.click() + language_options.find_element_by_xpath("//option[@value='de']").click() + user_settings.find_element_by_xpath('//*[@class="btn btn-primary"]').click() + messages = widgets.get_and_dismiss_messages(driver) + assert ("Success: Settings saved." in messages or + "Erfolg:Einstellungen gespeichert." in messages) + assert "Error" not in messages