diff --git a/pytest_splunk_addon_ui_smartx/components/controls/checkbox.py b/pytest_splunk_addon_ui_smartx/components/controls/checkbox.py index 2a7c2619..4f420e5d 100644 --- a/pytest_splunk_addon_ui_smartx/components/controls/checkbox.py +++ b/pytest_splunk_addon_ui_smartx/components/controls/checkbox.py @@ -28,17 +28,38 @@ class Checkbox(BaseControl): def __init__(self, browser, container, searchable=True): super().__init__(browser, container) - self.elements.update( - { - "internal_container": Selector( - select=container.select + ' [data-test="switch"]' - ), - "checkbox": Selector(select=container.select + ' [data-test="switch"]'), - "checkbox_btn": Selector( - select=container.select + ' [data-test="button"][role="checkbox"]' - ), - } - ) + if container.by == "xpath": + self.elements.update( + { + "internal_container": Selector( + by=By.XPATH, + select=container.select + '//div[@data-test="switch"]', + ), + "checkbox": Selector( + by=By.XPATH, + select=container.select + '//div[@data-test="switch"]', + ), + "checkbox_btn": Selector( + by=By.XPATH, + select=container.select + '//button[@role="checkbox"]', + ), + } + ) + else: + self.elements.update( + { + "internal_container": Selector( + select=container.select + ' [data-test="switch"]' + ), + "checkbox": Selector( + select=container.select + ' [data-test="switch"]' + ), + "checkbox_btn": Selector( + select=container.select + + ' [data-test="button"][role="checkbox"]' + ), + } + ) def toggle(self, max_attempts=5): """ diff --git a/pytest_splunk_addon_ui_smartx/components/controls/checkboxgroup.py b/pytest_splunk_addon_ui_smartx/components/controls/checkboxgroup.py new file mode 100644 index 00000000..f06a3539 --- /dev/null +++ b/pytest_splunk_addon_ui_smartx/components/controls/checkboxgroup.py @@ -0,0 +1,152 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from selenium.webdriver.common.by import By + +from ..base_component import Selector +from .base_control import BaseControl +from .checkbox import Checkbox +from .textbox import TextBox + + +class CheckboxGroup(BaseControl): + """ + Entity_Component : CheckboxGroup + + This class represents a group of checkboxes, allowing for expanding groups, + selecting/deselecting checkboxes, and setting or retrieving values. + Note: Please use xpath as locator for this component. + """ + + def __init__(self, browser, container) -> None: + """ + Initializes the CheckboxGroup. + + Args: + browser (Browser): The browser instance to interact with. + container (Selector): The container element that holds the checkbox group. + """ + super().__init__(browser, container) + + def is_group_expanded(self, checkbox_group_name: str) -> bool: + """ + Checks if the specified group is expanded. + + Args: + checkbox_group_name (str): The name of the checkbox group to check. + + Returns: + bool: True if the group is expanded, False otherwise. + """ + self.elements.update( + { + f"{checkbox_group_name}_button": Selector( + by=By.XPATH, + select=self.elements.get("container").select + + f'//span[text()="{checkbox_group_name}"]/ancestor::button', + ) + } + ) + return ( + getattr(self, f"{checkbox_group_name}_button").get_attribute( + "aria-expanded" + ) + == "true" + ) + + def get_checkbox(self, checkbox_name: str) -> Checkbox: + return Checkbox( + self.browser, + Selector( + by=By.XPATH, + select=self.elements.get("container").select + + f"//div[@data-test-field='{checkbox_name}']/parent::div", + ), + ) + + def select_checkbox_and_set_value( + self, checkbox_group_name: str, checkbox_name: str, checkbox_value: str = None + ) -> None: + """ + Expands a group and selects a checkbox, then sets the specified value. + + Args: + checkbox_group_name (str): The name of the group to expand. + checkbox_name (str): The name of the checkbox to select. + checkbox_value (str): The value to set for the checkbox. + """ + self.expand_group(checkbox_group_name) + self.get_checkbox(checkbox_name).check() + if checkbox_value: + self.get_textbox(checkbox_name).set_value(checkbox_value) + + def deselect(self, checkbox_group_name: str, checkbox_name: str) -> None: + """ + Expands a group and deselects the specified checkbox. + + Args: + checkbox_group_name (str): The name of the group to expand. + checkbox_name (str): The name of the checkbox to deselect. + """ + self.expand_group(checkbox_group_name) + self.get_checkbox(checkbox_name).uncheck() + + def get_textbox(self, checkbox_name: str) -> TextBox: + return TextBox( + self.browser, + Selector( + by=By.XPATH, + select=self.elements.get("container").select + + f"//div[@data-test-field='{checkbox_name}' and @data-test='number']", + ), + ) + + def get_checkbox_text_value( + self, checkbox_group_name: str, checkbox_name: str + ) -> str: + """ + Expands a group and retrieves the text value of the specified checkbox. + + Args: + checkbox_group_name (str): The name of the group to expand. + checkbox_name (str): The name of the checkbox to retrieve the value from. + + Returns: + str: The value of the checkbox. + """ + self.expand_group(checkbox_group_name) + return self.get_textbox(checkbox_name).get_value() + + def expand_group(self, checkbox_group_name: str) -> None: + """ + Expands the specified group if it is not already expanded. + + Args: + checkbox_group_name (str): The name of the group to expand. + """ + is_expanded = self.is_group_expanded(checkbox_group_name) + if not is_expanded: + getattr(self, f"{checkbox_group_name}_button").click() + + def collapse_group(self, checkbox_group_name: str) -> None: + """ + collapse the specified group if it is not already expanded. + + Args: + checkbox_group_name (str): The name of the group to expand. + """ + is_expanded = self.is_group_expanded(checkbox_group_name) + if is_expanded: + getattr(self, f"{checkbox_group_name}_button").click() diff --git a/pytest_splunk_addon_ui_smartx/components/controls/textbox.py b/pytest_splunk_addon_ui_smartx/components/controls/textbox.py index 836f12e5..243f5636 100644 --- a/pytest_splunk_addon_ui_smartx/components/controls/textbox.py +++ b/pytest_splunk_addon_ui_smartx/components/controls/textbox.py @@ -16,6 +16,7 @@ import platform from selenium.webdriver.common.keys import Keys +from selenium.webdriver.common.by import By from ..base_component import Selector from .base_control import BaseControl @@ -37,7 +38,14 @@ def __init__(self, browser, container, encrypted=False): self.encrypted = encrypted self.container = container self.browser = browser - self.elements.update({"input": Selector(select=container.select + " input")}) + if container.by == "xpath": + self.elements.update( + {"input": Selector(by=By.XPATH, select=container.select + "//input")} + ) + else: + self.elements.update( + {"input": Selector(select=container.select + " input")} + ) def set_value(self, value): """ diff --git a/tests/testdata/Splunk_TA_UCCExample/globalConfig.json b/tests/testdata/Splunk_TA_UCCExample/globalConfig.json index 20039fa4..913649e7 100644 --- a/tests/testdata/Splunk_TA_UCCExample/globalConfig.json +++ b/tests/testdata/Splunk_TA_UCCExample/globalConfig.json @@ -860,6 +860,164 @@ "text": "Help Link", "link": "https://docs.splunk.com/Documentation" } + }, + { + "field": "apis", + "label": "APIs/Interval (in seconds)", + "type": "checkboxGroup", + "options": { + "groups": [ + { + "label": "EC2", + "options": { + "isExpandable": true + }, + "fields": [ + "ec2_volumes", + "ec2_instances", + "ec2_reserved_instances", + "ebs_snapshots", + "rds_instances", + "rds_reserved_instances", + "ec2_key_pairs", + "ec2_security_groups", + "ec2_images", + "ec2_addresses" + ] + }, + { + "label": "ELB", + "options": { + "isExpandable": true + }, + "fields": [ + "classic_load_balancers", + "application_load_balancers" + ] + }, + { + "label": "VPC", + "options": { + "isExpandable": true + }, + "fields": [ + "vpcs", + "vpc_network_acls", + "vpc_subnets" + ] + } + ], + "rows": [ + { + "field": "ec2_volumes", + "checkbox": { + "defaultValue": true + }, + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "ec2_instances", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "ec2_reserved_instances", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "ebs_snapshots", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "rds_instances", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "rds_reserved_instances", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "ec2_key_pairs", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "ec2_security_groups", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "ec2_images", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "ec2_addresses", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "classic_load_balancers", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "application_load_balancers", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "vpcs", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "vpc_network_acls", + "input": { + "defaultValue": 3600, + "required": true + } + }, + { + "field": "vpc_subnets", + "input": { + "defaultValue": 3600, + "required": true + } + } + ] + } } ], "title": "Example Input Two" diff --git a/tests/ui/Example_UccLib/input_page.py b/tests/ui/Example_UccLib/input_page.py index 08b6ed5f..c6f96c6f 100644 --- a/tests/ui/Example_UccLib/input_page.py +++ b/tests/ui/Example_UccLib/input_page.py @@ -1,3 +1,6 @@ +from pytest_splunk_addon_ui_smartx.components.controls.checkboxgroup import ( + CheckboxGroup, +) from pytest_splunk_addon_ui_smartx.pages.page import Page from pytest_splunk_addon_ui_smartx.components.base_component import Selector from pytest_splunk_addon_ui_smartx.components.base_component import BaseComponent @@ -15,6 +18,8 @@ from pytest_splunk_addon_ui_smartx.backend_confs import ListBackendConf from pytest_splunk_addon_ui_smartx.components.controls.toggle import Toggle +from selenium.webdriver.common.by import By + class ExampleInputOne(Entity): """ @@ -191,6 +196,9 @@ def __init__(self, browser, container): + ' [data-test="control-group"][data-name="example_help_link"]' ), ) + self.checkboxgroup = CheckboxGroup( + browser, Selector(by=By.XPATH, select="//div[@type='checkboxGroup']") + ) self.title = BaseComponent(browser, Selector(select=' [data-test="title"]')) diff --git a/tests/ui/test_splunk_ta_example_addon_input_2.py b/tests/ui/test_splunk_ta_example_addon_input_2.py index a6282a28..df134229 100644 --- a/tests/ui/test_splunk_ta_example_addon_input_2.py +++ b/tests/ui/test_splunk_ta_example_addon_input_2.py @@ -1,3 +1,5 @@ +import time + from pytest_splunk_addon_ui_smartx.base_test import UccTester from .Example_UccLib.account import AccountPage from .Example_UccLib.input_page import InputPage @@ -107,6 +109,7 @@ def add_input_two(ucc_smartx_rest_helper): "index": "main", "start_date": "2016-10-10T12:10:15.000z", "disabled": 0, + "apis": "ec2_volumes/3600,ec2_instances/100,classic_load_balancers/100", } yield input_page.backend_conf.post_stanza(url, kwargs) @@ -528,6 +531,12 @@ def test_example_input_two_add_backend_validation( input_page.entity2.example_multiple_select.select("Option Two") input_page.entity2.index.select("main") input_page.entity2.interval.set_value("90") + input_page.entity2.checkboxgroup.select_checkbox_and_set_value( + "EC2", "ec2_instances", "100" + ) + input_page.entity2.checkboxgroup.select_checkbox_and_set_value( + "ELB", "classic_load_balancers", "100" + ) input_page.entity2.example_account.select("test_input") input_page.entity2.query_start_date.set_value("2020-12-11T20:00:32.000z") self.assert_util(input_page.entity2.save, True) @@ -541,6 +550,7 @@ def test_example_input_two_add_backend_validation( "input_two_multiple_select": "one,two", "start_date": "2020-12-11T20:00:32.000z", "disabled": 0, + "apis": "ec2_volumes/3600,ec2_instances/100,classic_load_balancers/100", } backend_stanza = input_page.backend_conf.get_stanza( "example_input_two://dummy_input" @@ -608,6 +618,17 @@ def test_example_input_two_edit_backend_validation( input_page.entity2.example_multiple_select.deselect("Option One") input_page.entity2.interval.set_value("3600") input_page.entity2.query_start_date.set_value("2020-20-20T20:20:20.000z") + input_page.entity2.checkboxgroup.deselect("EC2", "ec2_instances") + input_page.entity2.checkboxgroup.deselect("ELB", "classic_load_balancers") + self.assert_util( + input_page.entity2.checkboxgroup.get_textbox( + "classic_load_balancers" + ).is_editable(), + False, + ) + input_page.entity2.checkboxgroup.select_checkbox_and_set_value( + "VPC", "vpcs", "1000" + ) self.assert_util(input_page.entity2.save, True) input_page.table.wait_for_rows_to_appear(1) value_to_test = { @@ -619,6 +640,7 @@ def test_example_input_two_edit_backend_validation( "input_two_multiple_select": "two", "start_date": "2020-20-20T20:20:20.000z", "disabled": 0, + "apis": "ec2_volumes/3600,vpcs/1000", } backend_stanza = input_page.backend_conf.get_stanza( "example_input_two://dummy_input_two" @@ -946,3 +968,27 @@ def test_example_input_two_delete_valid_prompt_message( self.assert_util( prompt_message, 'Are you sure you want to delete "{}" ?'.format(input_name) ) + + @pytest.mark.execute_enterprise_cloud_true + @pytest.mark.forwarder + @pytest.mark.input + def test_example_input_two_checkboxgroup_validation( + self, ucc_smartx_selenium_helper, ucc_smartx_rest_helper + ): + """Verifies the checkboxgroup component'""" + input_page = InputPage(ucc_smartx_selenium_helper, ucc_smartx_rest_helper) + input_page.create_new_input.select("Example Input Two") + input_page.entity2.example_account.wait_for_values() + input_page.entity2.checkboxgroup.select_checkbox_and_set_value( + "EC2", "ec2_instances", "100" + ) + input_page.entity2.checkboxgroup.collapse_group("EC2") + self.assert_util( + input_page.entity2.checkboxgroup.is_group_expanded("EC2"), False + ) + self.assert_util( + input_page.entity2.checkboxgroup.get_checkbox_text_value( + "EC2", "ec2_instances" + ), + "100", + )