Skip to content

Commit b45b89f

Browse files
tests(input_select): Add kitchensink tests for input_select and input_selectize (#1686)
Co-authored-by: Barret Schloerke <barret@posit.co>
1 parent 14d820c commit b45b89f

File tree

6 files changed

+458
-72
lines changed

6 files changed

+458
-72
lines changed

shiny/playwright/controller/_input_controls.py

Lines changed: 60 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
from ..expect._internal import expect_style_to_have_value as _expect_style_to_have_value
1818
from ._base import (
1919
InitLocator,
20+
UiWithContainerP,
2021
UiWithLabel,
2122
WidthContainerM,
2223
WidthLocM,
23-
_expect_multiple,
2424
all_missing,
2525
not_is_missing,
2626
)
@@ -923,30 +923,40 @@ def __init__(
923923
)
924924

925925

926-
class _InputSelectBase(
927-
WidthLocM,
928-
UiWithLabel,
929-
):
930-
loc_selected: Locator
931-
"""
932-
Playwright `Locator` for the selected option of the input select.
933-
"""
934-
loc_choices: Locator
935-
"""
936-
Playwright `Locator` for the choices of the input select.
937-
"""
938-
loc_choice_groups: Locator
926+
class InputSelectWidthM:
939927
"""
940-
Playwright `Locator` for the choice groups of the input select.
928+
A base class representing the input `select` and `selectize` widths.
929+
930+
This class provides methods to expect the width attribute of a DOM element.
941931
"""
942932

943-
def __init__(
944-
self,
945-
page: Page,
946-
id: str,
933+
def expect_width(
934+
self: UiWithContainerP,
935+
value: AttrValue,
947936
*,
948-
select_class: str = "",
937+
timeout: Timeout = None,
949938
) -> None:
939+
"""
940+
Expect the input select to have a specific width.
941+
942+
Parameters
943+
----------
944+
value
945+
The expected width.
946+
timeout
947+
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
948+
"""
949+
_expect_style_to_have_value(self.loc_container, "width", value, timeout=timeout)
950+
951+
952+
class InputSelect(InputSelectWidthM, UiWithLabel):
953+
"""
954+
Controller for :func:`shiny.ui.input_select`.
955+
956+
If you have defined your app's select input (`ui.input_select()`) with `selectize=TRUE`, use `InputSelectize` to test your app's UI.
957+
"""
958+
959+
def __init__(self, page: Page, id: str) -> None:
950960
"""
951961
Initializes the input select.
952962
@@ -956,13 +966,11 @@ def __init__(
956966
The page where the input select is located.
957967
id
958968
The id of the input select.
959-
select_class
960-
The class of the select element. Defaults to "".
961969
"""
962970
super().__init__(
963971
page,
964972
id=id,
965-
loc=f"select#{id}.shiny-bound-input{select_class}",
973+
loc=f"select#{id}.shiny-bound-input.form-select",
966974
)
967975
self.loc_selected = self.loc.locator("option:checked")
968976
self.loc_choices = self.loc.locator("option")
@@ -988,9 +996,29 @@ def set(
988996
selected = [selected]
989997
self.loc.select_option(value=selected, timeout=timeout)
990998

999+
# If `selectize=` parameter does not become deprecated, uncomment this
1000+
# # selectize: bool = False,
1001+
# def expect_selectize(self, value: bool, *, timeout: Timeout = None) -> None:
1002+
# """
1003+
# Expect the input select to be selectize.
1004+
1005+
# Parameters
1006+
# ----------
1007+
# value
1008+
# Whether the input select is selectize.
1009+
# timeout
1010+
# The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
1011+
# """
1012+
# # class_=None if selectize else "form-select",
1013+
# _expect_class_to_have_value(
1014+
# self.loc,
1015+
# "form-select",
1016+
# has_class=not value,
1017+
# timeout=timeout,
1018+
# )
1019+
9911020
def expect_choices(
9921021
self,
993-
# TODO-future; support patterns?
9941022
choices: ListPatternOrStr,
9951023
*,
9961024
timeout: Timeout = None,
@@ -1111,10 +1139,9 @@ def expect_choice_labels(
11111139
return
11121140
playwright_expect(self.loc_choices).to_have_text(value, timeout=timeout)
11131141

1114-
# multiple: bool = False,
11151142
def expect_multiple(self, value: bool, *, timeout: Timeout = None) -> None:
11161143
"""
1117-
Expect the input select to allow multiple selections.
1144+
Expect the input selectize to allow multiple selections.
11181145
11191146
Parameters
11201147
----------
@@ -1123,7 +1150,12 @@ def expect_multiple(self, value: bool, *, timeout: Timeout = None) -> None:
11231150
timeout
11241151
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
11251152
"""
1126-
_expect_multiple(self.loc, value, timeout=timeout)
1153+
_expect_attribute_to_have_value(
1154+
self.loc,
1155+
"multiple",
1156+
value="" if value else None,
1157+
timeout=timeout,
1158+
)
11271159

11281160
def expect_size(self, value: AttrValue, *, timeout: Timeout = None) -> None:
11291161
"""
@@ -1144,50 +1176,7 @@ def expect_size(self, value: AttrValue, *, timeout: Timeout = None) -> None:
11441176
)
11451177

11461178

1147-
class InputSelect(_InputSelectBase):
1148-
"""Controller for :func:`shiny.ui.input_select`."""
1149-
1150-
def __init__(self, page: Page, id: str) -> None:
1151-
"""
1152-
Initializes the input select.
1153-
1154-
Parameters
1155-
----------
1156-
page
1157-
The page where the input select is located.
1158-
id
1159-
The id of the input select.
1160-
"""
1161-
super().__init__(
1162-
page,
1163-
id=id,
1164-
select_class=".form-select",
1165-
)
1166-
1167-
# selectize: bool = False,
1168-
def expect_selectize(self, value: bool, *, timeout: Timeout = None) -> None:
1169-
"""
1170-
Expect the input select to be selectize.
1171-
1172-
Parameters
1173-
----------
1174-
value
1175-
Whether the input select is selectize.
1176-
timeout
1177-
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
1178-
"""
1179-
# class_=None if selectize else "form-select",
1180-
_expect_class_to_have_value(
1181-
self.loc,
1182-
"form-select",
1183-
has_class=not value,
1184-
timeout=timeout,
1185-
)
1186-
1187-
1188-
class InputSelectize(
1189-
UiWithLabel,
1190-
):
1179+
class InputSelectize(InputSelectWidthM, UiWithLabel):
11911180
"""Controller for :func:`shiny.ui.input_selectize`."""
11921181

11931182
def __init__(self, page: Page, id: str) -> None:
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from shiny.express import input, render, ui
2+
3+
ui.page_opts(title="Select Inputs Kitchensink")
4+
5+
fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"]
6+
fruits_dict = {
7+
"apple": "Apple",
8+
"banana": "Banana",
9+
"cherry": "Cherry",
10+
"date": "Date",
11+
"elderberry": "Elderberry",
12+
}
13+
fruits_grouped_dict = {
14+
"Citrus": {
15+
"Orange": "Sweet and tangy",
16+
"Lemon": "Zesty and refreshing",
17+
"Lime": "Bright and tart",
18+
},
19+
"Berries": {
20+
"Strawberry": "Juicy and sweet",
21+
"Blueberry": "Tiny and antioxidant-rich",
22+
"Raspberry": "Delicate and slightly tart",
23+
},
24+
}
25+
26+
27+
with ui.card():
28+
ui.input_select("basic_select", "Default select", fruits)
29+
30+
@render.code
31+
def basic_result_txt():
32+
return input.basic_select()
33+
34+
35+
with ui.card():
36+
ui.input_select("multi_select", "Multiple Select", fruits, multiple=True)
37+
38+
@render.code
39+
def multi_result_txt():
40+
return ", ".join(input.multi_select())
41+
42+
43+
with ui.card():
44+
ui.input_select(
45+
"select_with_selected", "Select with selected", fruits, selected="Cherry"
46+
)
47+
48+
@render.code
49+
def select_with_selected_txt():
50+
return str(input.select_with_selected())
51+
52+
53+
with ui.card():
54+
ui.input_select("width_select", "Select with Custom Width", fruits, width="400px")
55+
56+
@render.code
57+
def width_result_txt():
58+
return str(input.width_select())
59+
60+
61+
with ui.card():
62+
ui.input_select(
63+
"select_with_labels",
64+
"Select with labels",
65+
fruits_dict,
66+
)
67+
68+
@render.code
69+
def select_with_labels_txt():
70+
return str(input.select_with_labels())
71+
72+
73+
with ui.card():
74+
ui.input_select(
75+
"select_with_custom_size_and_dict",
76+
"Select with custom size and dict",
77+
fruits_grouped_dict,
78+
size="4",
79+
)
80+
81+
@render.code
82+
def select_with_custom_size_and_dict_txt():
83+
return str(input.select_with_custom_size_and_dict())

0 commit comments

Comments
 (0)