Skip to content

Commit 7224445

Browse files
committed
remove InputSelectionWidthM and use _InputSelectBase instead
1 parent a82efcf commit 7224445

File tree

3 files changed

+59
-84
lines changed

3 files changed

+59
-84
lines changed

shiny/playwright/controller/_input_controls.py

Lines changed: 39 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
UiWithLabel,
2121
WidthContainerM,
2222
WidthLocM,
23-
_expect_multiple,
2423
all_missing,
2524
not_is_missing,
2625
)
@@ -923,14 +922,14 @@ def __init__(
923922
)
924923

925924

926-
class InputSelectionWidthM:
925+
class _InputSelectBase:
927926
"""
928-
A mixin class representing the input `select` and `selectize` widths.
927+
A base class representing the input `select` and `selectize` widths.
929928
930929
This class provides methods to expect the width attribute of a DOM element.
931930
"""
932931

933-
loc_label: Locator
932+
loc_container: Locator
934933
"""
935934
Playwright `Locator` for the label of the UI element.
936935
"""
@@ -946,34 +945,13 @@ def expect_width(self, value: AttrValue, *, timeout: Timeout = None) -> None:
946945
timeout
947946
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
948947
"""
949-
_expect_style_to_have_value(
950-
self.loc_label.locator(".."), "width", value, timeout=timeout
951-
)
948+
_expect_style_to_have_value(self.loc_container, "width", value, timeout=timeout)
952949

953950

954-
class _InputSelectBase(
955-
UiWithLabel,
956-
):
957-
loc_selected: Locator
958-
"""
959-
Playwright `Locator` for the selected option of the input select.
960-
"""
961-
loc_choices: Locator
962-
"""
963-
Playwright `Locator` for the choices of the input select.
964-
"""
965-
loc_choice_groups: Locator
966-
"""
967-
Playwright `Locator` for the choice groups of the input select.
968-
"""
951+
class InputSelect(UiWithLabel, _InputSelectBase):
952+
"""Controller for :func:`shiny.ui.input_select`."""
969953

970-
def __init__(
971-
self,
972-
page: Page,
973-
id: str,
974-
*,
975-
select_class: str = "",
976-
) -> None:
954+
def __init__(self, page: Page, id: str) -> None:
977955
"""
978956
Initializes the input select.
979957
@@ -983,18 +961,37 @@ def __init__(
983961
The page where the input select is located.
984962
id
985963
The id of the input select.
986-
select_class
987-
The class of the select element. Defaults to "".
988964
"""
989965
super().__init__(
990966
page,
991967
id=id,
992-
loc=f"select#{id}.shiny-bound-input{select_class}",
968+
loc=f"select#{id}.shiny-bound-input.form-select",
993969
)
970+
# self.loc = self.page.locator("select#{id}.shiny-bound-input.form-select")
994971
self.loc_selected = self.loc.locator("option:checked")
995972
self.loc_choices = self.loc.locator("option")
996973
self.loc_choice_groups = self.loc.locator("optgroup")
997974

975+
# selectize: bool = False,
976+
def expect_selectize(self, value: bool, *, timeout: Timeout = None) -> None:
977+
"""
978+
Expect the input select to be selectize.
979+
980+
Parameters
981+
----------
982+
value
983+
Whether the input select is selectize.
984+
timeout
985+
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
986+
"""
987+
# class_=None if selectize else "form-select",
988+
_expect_class_to_have_value(
989+
self.loc,
990+
"form-select",
991+
has_class=not value,
992+
timeout=timeout,
993+
)
994+
998995
def set(
999996
self,
1000997
selected: str | ListOrTuple[str],
@@ -1138,10 +1135,9 @@ def expect_choice_labels(
11381135
return
11391136
playwright_expect(self.loc_choices).to_have_text(value, timeout=timeout)
11401137

1141-
# multiple: bool = False,
11421138
def expect_multiple(self, value: bool, *, timeout: Timeout = None) -> None:
11431139
"""
1144-
Expect the input select to allow multiple selections.
1140+
Expect the input selectize to allow multiple selections.
11451141
11461142
Parameters
11471143
----------
@@ -1150,7 +1146,14 @@ def expect_multiple(self, value: bool, *, timeout: Timeout = None) -> None:
11501146
timeout
11511147
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
11521148
"""
1153-
_expect_multiple(self.loc, value, timeout=timeout)
1149+
if value:
1150+
playwright_expect(self.loc).to_have_attribute(
1151+
"multiple", "", timeout=timeout
1152+
)
1153+
else:
1154+
playwright_expect(self.loc).not_to_have_attribute(
1155+
"multiple", "multiple", timeout=timeout
1156+
)
11541157

11551158
def expect_size(self, value: AttrValue, *, timeout: Timeout = None) -> None:
11561159
"""
@@ -1171,48 +1174,7 @@ def expect_size(self, value: AttrValue, *, timeout: Timeout = None) -> None:
11711174
)
11721175

11731176

1174-
class InputSelect(_InputSelectBase, InputSelectionWidthM):
1175-
"""Controller for :func:`shiny.ui.input_select`."""
1176-
1177-
def __init__(self, page: Page, id: str) -> None:
1178-
"""
1179-
Initializes the input select.
1180-
1181-
Parameters
1182-
----------
1183-
page
1184-
The page where the input select is located.
1185-
id
1186-
The id of the input select.
1187-
"""
1188-
super().__init__(
1189-
page,
1190-
id=id,
1191-
select_class=".form-select",
1192-
)
1193-
1194-
# selectize: bool = False,
1195-
def expect_selectize(self, value: bool, *, timeout: Timeout = None) -> None:
1196-
"""
1197-
Expect the input select to be selectize.
1198-
1199-
Parameters
1200-
----------
1201-
value
1202-
Whether the input select is selectize.
1203-
timeout
1204-
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
1205-
"""
1206-
# class_=None if selectize else "form-select",
1207-
_expect_class_to_have_value(
1208-
self.loc,
1209-
"form-select",
1210-
has_class=not value,
1211-
timeout=timeout,
1212-
)
1213-
1214-
1215-
class InputSelectize(UiWithLabel, InputSelectionWidthM):
1177+
class InputSelectize(UiWithLabel, _InputSelectBase):
12161178
"""Controller for :func:`shiny.ui.input_selectize`."""
12171179

12181180
def __init__(self, page: Page, id: str) -> None:
@@ -1230,9 +1192,6 @@ def __init__(self, page: Page, id: str) -> None:
12301192
# We are only guaranteed to have `data-value` attribute for each _option_
12311193
self.loc_choices = self._loc_selectize.locator("[data-value]")
12321194
self.loc_selected = self.loc_container.locator(f"select#{id} > option")
1233-
self.clear = self.loc.locator("..").locator(
1234-
"> div.plugin-clear_button > a.clear"
1235-
)
12361195

12371196
def set(
12381197
self,

tests/playwright/shiny/inputs/input_controls_kitchensink/input_select/test_input_select_kitchensink.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ def test_input_select_kitchensink(page: Page, local_app: ShinyAppProc) -> None:
1111
basic_select_txt = controller.OutputText(page, "basic_result_txt")
1212
basic_select.expect_label("Default select")
1313
basic_select_txt.expect_value("Basic select: Apple")
14+
basic_select.expect_multiple(False)
1415

1516
multiple_select = controller.InputSelect(page, "multi_select")
1617
multiple_select_txt = controller.OutputText(page, "multi_result_txt")
17-
multiple_select.set(["Banana", "Cherry"])
18-
# multiple_select.expect_multiple(True) # TODO-karan: Investigate why this is failing
18+
multiple_options = ["Banana", "Cherry"]
19+
multiple_select.set(multiple_options)
20+
multiple_select.expect_multiple(True)
1921
multiple_select_txt.expect_value("Multi select: Banana, Cherry")
2022

2123
select_with_selected = controller.InputSelect(page, "select_with_selected")

tests/playwright/shiny/inputs/input_controls_kitchensink/input_selectize/test_input_selectize_kitchensink.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,23 @@ def test_input_selectize_kitchensink(page: Page, local_app: ShinyAppProc) -> Non
1111
basic_select_txt = controller.OutputText(page, "basic_result_txt")
1212
basic_selectize.expect_label("Default selectize")
1313
basic_select_txt.expect_value("Basic select: Apple")
14+
basic_selectize.expect_multiple(False)
1415

1516
multiple_selectize = controller.InputSelectize(page, "multi_selectize")
1617
multiple_selectize_txt = controller.OutputText(page, "multi_result_txt")
17-
multiple_selectize.set(["Banana", "Cherry"])
18+
multiple_options = ["Banana", "Cherry"]
19+
multiple_selectize.set(multiple_options)
20+
multiple_selectize.expect_selected(["Banana", "Cherry"])
1821
multiple_selectize_txt.expect_value("Multi select: Banana, Cherry")
22+
for option in multiple_options:
23+
multiple_selectize.loc.locator(
24+
f"+ div.plugin-remove_button > .has-options > .item[data-value={option}] > .remove"
25+
).click()
26+
page.keyboard.press(
27+
"Escape"
28+
) # to remove dropdown from blocking access to other selectize inputs
29+
multiple_selectize_txt.expect_value("Multi select: ")
30+
multiple_selectize.expect_multiple(True)
1931

2032
selectize_with_selected = controller.InputSelectize(page, "selectize_with_selected")
2133
selectize_with_selected_txt = controller.OutputText(page, "selected_result_txt")
@@ -31,7 +43,9 @@ def test_input_selectize_kitchensink(page: Page, local_app: ShinyAppProc) -> Non
3143
selectize_width_close_button_txt.expect_value("Selectize with close button: Orange")
3244
selectize_width_close_button.expect_width("400px")
3345
selectize_width_close_button.expect_choice_groups(["Citrus", "Berries"])
34-
selectize_width_close_button.clear_selection()
46+
selectize_width_close_button.loc.locator("..").locator(
47+
"> div.plugin-clear_button > a.clear"
48+
).click() # Clear default selection
3549
selectize_width_close_button_txt.expect_value(
3650
"Selectize with close button: "
3751
) # Expecting empty after clear

0 commit comments

Comments
 (0)