Skip to content

Commit 856776a

Browse files
feat: adding support for checkboxgroup component (#439)
Added support for testing checkbox-group component. - Added support for testing checkbox and textbox component using xpath rather then fixing it with css selector. - Reused checkbox and textbox component inside checkbox-group component. - Updated test cases to check the checkbox-group component
1 parent 9fcd861 commit 856776a

File tree

6 files changed

+405
-12
lines changed

6 files changed

+405
-12
lines changed

pytest_splunk_addon_ui_smartx/components/controls/checkbox.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,38 @@ class Checkbox(BaseControl):
2828

2929
def __init__(self, browser, container, searchable=True):
3030
super().__init__(browser, container)
31-
self.elements.update(
32-
{
33-
"internal_container": Selector(
34-
select=container.select + ' [data-test="switch"]'
35-
),
36-
"checkbox": Selector(select=container.select + ' [data-test="switch"]'),
37-
"checkbox_btn": Selector(
38-
select=container.select + ' [data-test="button"][role="checkbox"]'
39-
),
40-
}
41-
)
31+
if container.by == "xpath":
32+
self.elements.update(
33+
{
34+
"internal_container": Selector(
35+
by=By.XPATH,
36+
select=container.select + '//div[@data-test="switch"]',
37+
),
38+
"checkbox": Selector(
39+
by=By.XPATH,
40+
select=container.select + '//div[@data-test="switch"]',
41+
),
42+
"checkbox_btn": Selector(
43+
by=By.XPATH,
44+
select=container.select + '//button[@role="checkbox"]',
45+
),
46+
}
47+
)
48+
else:
49+
self.elements.update(
50+
{
51+
"internal_container": Selector(
52+
select=container.select + ' [data-test="switch"]'
53+
),
54+
"checkbox": Selector(
55+
select=container.select + ' [data-test="switch"]'
56+
),
57+
"checkbox_btn": Selector(
58+
select=container.select
59+
+ ' [data-test="button"][role="checkbox"]'
60+
),
61+
}
62+
)
4263

4364
def toggle(self, max_attempts=5):
4465
"""
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#
2+
# Copyright 2024 Splunk Inc.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
from selenium.webdriver.common.by import By
17+
18+
from ..base_component import Selector
19+
from .base_control import BaseControl
20+
from .checkbox import Checkbox
21+
from .textbox import TextBox
22+
23+
24+
class CheckboxGroup(BaseControl):
25+
"""
26+
Entity_Component : CheckboxGroup
27+
28+
This class represents a group of checkboxes, allowing for expanding groups,
29+
selecting/deselecting checkboxes, and setting or retrieving values.
30+
Note: Please use xpath as locator for this component.
31+
"""
32+
33+
def __init__(self, browser, container) -> None:
34+
"""
35+
Initializes the CheckboxGroup.
36+
37+
Args:
38+
browser (Browser): The browser instance to interact with.
39+
container (Selector): The container element that holds the checkbox group.
40+
"""
41+
super().__init__(browser, container)
42+
43+
def is_group_expanded(self, checkbox_group_name: str) -> bool:
44+
"""
45+
Checks if the specified group is expanded.
46+
47+
Args:
48+
checkbox_group_name (str): The name of the checkbox group to check.
49+
50+
Returns:
51+
bool: True if the group is expanded, False otherwise.
52+
"""
53+
self.elements.update(
54+
{
55+
f"{checkbox_group_name}_button": Selector(
56+
by=By.XPATH,
57+
select=self.elements.get("container").select
58+
+ f'//span[text()="{checkbox_group_name}"]/ancestor::button',
59+
)
60+
}
61+
)
62+
return (
63+
getattr(self, f"{checkbox_group_name}_button").get_attribute(
64+
"aria-expanded"
65+
)
66+
== "true"
67+
)
68+
69+
def get_checkbox(self, checkbox_name: str) -> Checkbox:
70+
return Checkbox(
71+
self.browser,
72+
Selector(
73+
by=By.XPATH,
74+
select=self.elements.get("container").select
75+
+ f"//div[@data-test-field='{checkbox_name}']/parent::div",
76+
),
77+
)
78+
79+
def select_checkbox_and_set_value(
80+
self, checkbox_group_name: str, checkbox_name: str, checkbox_value: str = None
81+
) -> None:
82+
"""
83+
Expands a group and selects a checkbox, then sets the specified value.
84+
85+
Args:
86+
checkbox_group_name (str): The name of the group to expand.
87+
checkbox_name (str): The name of the checkbox to select.
88+
checkbox_value (str): The value to set for the checkbox.
89+
"""
90+
self.expand_group(checkbox_group_name)
91+
self.get_checkbox(checkbox_name).check()
92+
if checkbox_value:
93+
self.get_textbox(checkbox_name).set_value(checkbox_value)
94+
95+
def deselect(self, checkbox_group_name: str, checkbox_name: str) -> None:
96+
"""
97+
Expands a group and deselects the specified checkbox.
98+
99+
Args:
100+
checkbox_group_name (str): The name of the group to expand.
101+
checkbox_name (str): The name of the checkbox to deselect.
102+
"""
103+
self.expand_group(checkbox_group_name)
104+
self.get_checkbox(checkbox_name).uncheck()
105+
106+
def get_textbox(self, checkbox_name: str) -> TextBox:
107+
return TextBox(
108+
self.browser,
109+
Selector(
110+
by=By.XPATH,
111+
select=self.elements.get("container").select
112+
+ f"//div[@data-test-field='{checkbox_name}' and @data-test='number']",
113+
),
114+
)
115+
116+
def get_checkbox_text_value(
117+
self, checkbox_group_name: str, checkbox_name: str
118+
) -> str:
119+
"""
120+
Expands a group and retrieves the text value of the specified checkbox.
121+
122+
Args:
123+
checkbox_group_name (str): The name of the group to expand.
124+
checkbox_name (str): The name of the checkbox to retrieve the value from.
125+
126+
Returns:
127+
str: The value of the checkbox.
128+
"""
129+
self.expand_group(checkbox_group_name)
130+
return self.get_textbox(checkbox_name).get_value()
131+
132+
def expand_group(self, checkbox_group_name: str) -> None:
133+
"""
134+
Expands the specified group if it is not already expanded.
135+
136+
Args:
137+
checkbox_group_name (str): The name of the group to expand.
138+
"""
139+
is_expanded = self.is_group_expanded(checkbox_group_name)
140+
if not is_expanded:
141+
getattr(self, f"{checkbox_group_name}_button").click()
142+
143+
def collapse_group(self, checkbox_group_name: str) -> None:
144+
"""
145+
collapse the specified group if it is not already expanded.
146+
147+
Args:
148+
checkbox_group_name (str): The name of the group to expand.
149+
"""
150+
is_expanded = self.is_group_expanded(checkbox_group_name)
151+
if is_expanded:
152+
getattr(self, f"{checkbox_group_name}_button").click()

pytest_splunk_addon_ui_smartx/components/controls/textbox.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import platform
1717

1818
from selenium.webdriver.common.keys import Keys
19+
from selenium.webdriver.common.by import By
1920

2021
from ..base_component import Selector
2122
from .base_control import BaseControl
@@ -37,7 +38,14 @@ def __init__(self, browser, container, encrypted=False):
3738
self.encrypted = encrypted
3839
self.container = container
3940
self.browser = browser
40-
self.elements.update({"input": Selector(select=container.select + " input")})
41+
if container.by == "xpath":
42+
self.elements.update(
43+
{"input": Selector(by=By.XPATH, select=container.select + "//input")}
44+
)
45+
else:
46+
self.elements.update(
47+
{"input": Selector(select=container.select + " input")}
48+
)
4149

4250
def set_value(self, value):
4351
"""

tests/testdata/Splunk_TA_UCCExample/globalConfig.json

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,164 @@
860860
"text": "Help Link",
861861
"link": "https://docs.splunk.com/Documentation"
862862
}
863+
},
864+
{
865+
"field": "apis",
866+
"label": "APIs/Interval (in seconds)",
867+
"type": "checkboxGroup",
868+
"options": {
869+
"groups": [
870+
{
871+
"label": "EC2",
872+
"options": {
873+
"isExpandable": true
874+
},
875+
"fields": [
876+
"ec2_volumes",
877+
"ec2_instances",
878+
"ec2_reserved_instances",
879+
"ebs_snapshots",
880+
"rds_instances",
881+
"rds_reserved_instances",
882+
"ec2_key_pairs",
883+
"ec2_security_groups",
884+
"ec2_images",
885+
"ec2_addresses"
886+
]
887+
},
888+
{
889+
"label": "ELB",
890+
"options": {
891+
"isExpandable": true
892+
},
893+
"fields": [
894+
"classic_load_balancers",
895+
"application_load_balancers"
896+
]
897+
},
898+
{
899+
"label": "VPC",
900+
"options": {
901+
"isExpandable": true
902+
},
903+
"fields": [
904+
"vpcs",
905+
"vpc_network_acls",
906+
"vpc_subnets"
907+
]
908+
}
909+
],
910+
"rows": [
911+
{
912+
"field": "ec2_volumes",
913+
"checkbox": {
914+
"defaultValue": true
915+
},
916+
"input": {
917+
"defaultValue": 3600,
918+
"required": true
919+
}
920+
},
921+
{
922+
"field": "ec2_instances",
923+
"input": {
924+
"defaultValue": 3600,
925+
"required": true
926+
}
927+
},
928+
{
929+
"field": "ec2_reserved_instances",
930+
"input": {
931+
"defaultValue": 3600,
932+
"required": true
933+
}
934+
},
935+
{
936+
"field": "ebs_snapshots",
937+
"input": {
938+
"defaultValue": 3600,
939+
"required": true
940+
}
941+
},
942+
{
943+
"field": "rds_instances",
944+
"input": {
945+
"defaultValue": 3600,
946+
"required": true
947+
}
948+
},
949+
{
950+
"field": "rds_reserved_instances",
951+
"input": {
952+
"defaultValue": 3600,
953+
"required": true
954+
}
955+
},
956+
{
957+
"field": "ec2_key_pairs",
958+
"input": {
959+
"defaultValue": 3600,
960+
"required": true
961+
}
962+
},
963+
{
964+
"field": "ec2_security_groups",
965+
"input": {
966+
"defaultValue": 3600,
967+
"required": true
968+
}
969+
},
970+
{
971+
"field": "ec2_images",
972+
"input": {
973+
"defaultValue": 3600,
974+
"required": true
975+
}
976+
},
977+
{
978+
"field": "ec2_addresses",
979+
"input": {
980+
"defaultValue": 3600,
981+
"required": true
982+
}
983+
},
984+
{
985+
"field": "classic_load_balancers",
986+
"input": {
987+
"defaultValue": 3600,
988+
"required": true
989+
}
990+
},
991+
{
992+
"field": "application_load_balancers",
993+
"input": {
994+
"defaultValue": 3600,
995+
"required": true
996+
}
997+
},
998+
{
999+
"field": "vpcs",
1000+
"input": {
1001+
"defaultValue": 3600,
1002+
"required": true
1003+
}
1004+
},
1005+
{
1006+
"field": "vpc_network_acls",
1007+
"input": {
1008+
"defaultValue": 3600,
1009+
"required": true
1010+
}
1011+
},
1012+
{
1013+
"field": "vpc_subnets",
1014+
"input": {
1015+
"defaultValue": 3600,
1016+
"required": true
1017+
}
1018+
}
1019+
]
1020+
}
8631021
}
8641022
],
8651023
"title": "Example Input Two"

0 commit comments

Comments
 (0)