Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Fixed the `InputSlider` controller's `.expect_width()` to check the `width` property within the `style` attribute. (#1691)

* Fixed the `InputCheckbox` and `InputCheckboxGroup` controllers' `.expect_width()` to check the `width` property within the `style` attribute. (#1702)

## [1.1.0] - 2024-09-03

### New features
Expand Down
2 changes: 1 addition & 1 deletion shiny/api-examples/input_checkbox/app-core.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from shiny import App, Inputs, Outputs, Session, render, ui

app_ui = ui.page_fluid(
ui.input_checkbox("somevalue", "Some value", False),
ui.input_checkbox("somevalue", "Some value", False, width="600px"),
ui.output_ui("value"),
)

Expand Down
75 changes: 28 additions & 47 deletions shiny/playwright/controller/_input_controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
InitLocator,
UiWithContainerP,
UiWithLabel,
WidthContainerM,
all_missing,
not_is_missing,
)
Expand All @@ -29,7 +28,30 @@
)


class _InputSliderBase(UiWithLabel):
class InputWidthControlMixin:
"""
A mixin class that provides methods to control the width of input elements, such as checkboxes, sliders and radio buttons.
"""

def expect_width(
self: UiWithContainerP,
value: AttrValue,
*,
timeout: Timeout = None,
) -> None:
"""
Expect the input select to have a specific width.
Parameters
----------
value
The expected width.
timeout
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
"""
_expect_style_to_have_value(self.loc_container, "width", value, timeout=timeout)


class _InputSliderBase(InputWidthControlMixin, UiWithLabel):

loc_irs: Locator
"""
Expand Down Expand Up @@ -202,19 +224,6 @@ def expect_max(self, value: AttrValue, *, timeout: Timeout = None) -> None:
self.loc, "data-max", value=value, timeout=timeout
)

def expect_width(self, value: str, *, timeout: Timeout = None) -> None:
"""
Expects the slider to have the specified width.

Parameters
----------
value
The expected width.
timeout
The maximum time to wait for the width to be visible and interactable. Defaults to `None`.
"""
_expect_style_to_have_value(self.loc_container, "width", value, timeout=timeout)

def expect_step(self, value: AttrValue, *, timeout: Timeout = None) -> None:
"""
Expect the input element to have the expected `step` attribute value.
Expand Down Expand Up @@ -463,7 +472,7 @@ def _handle_center(
return handle_center


class _RadioButtonCheckboxGroupBase(UiWithLabel):
class _RadioButtonCheckboxGroupBase(InputWidthControlMixin, UiWithLabel):
loc_choice_labels: Locator

def expect_choice_labels(
Expand Down Expand Up @@ -511,7 +520,6 @@ def expect_inline(self, value: bool, *, timeout: Timeout = None) -> None:


class InputRadioButtons(
WidthContainerM,
_RadioButtonCheckboxGroupBase,
):
"""Controller for :func:`shiny.ui.input_radio_buttons`."""
Expand Down Expand Up @@ -646,7 +654,7 @@ def expect_selected(


class _InputCheckboxBase(
WidthContainerM,
InputWidthControlMixin,
UiWithLabel,
):
def __init__(
Expand Down Expand Up @@ -721,7 +729,6 @@ def expect_checked(self, value: bool, *, timeout: Timeout = None) -> None:


class InputCheckboxGroup(
WidthContainerM,
_RadioButtonCheckboxGroupBase,
):
"""Controller for :func:`shiny.ui.input_checkbox_group`."""
Expand Down Expand Up @@ -935,33 +942,7 @@ def __init__(
)


class InputSelectWidthM:
"""
A base class representing the input `select` and `selectize` widths.

This class provides methods to expect the width attribute of a DOM element.
"""

def expect_width(
self: UiWithContainerP,
value: AttrValue,
*,
timeout: Timeout = None,
) -> None:
"""
Expect the input select to have a specific width.

Parameters
----------
value
The expected width.
timeout
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
"""
_expect_style_to_have_value(self.loc_container, "width", value, timeout=timeout)


class InputSelect(InputSelectWidthM, UiWithLabel):
class InputSelect(InputWidthControlMixin, UiWithLabel):
"""
Controller for :func:`shiny.ui.input_select`.

Expand Down Expand Up @@ -1188,7 +1169,7 @@ def expect_size(self, value: AttrValue, *, timeout: Timeout = None) -> None:
)


class InputSelectize(InputSelectWidthM, UiWithLabel):
class InputSelectize(InputWidthControlMixin, UiWithLabel):
"""Controller for :func:`shiny.ui.input_selectize`."""

def __init__(self, page: Page, id: str) -> None:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from shiny.express import ui

ui.page_opts(title="Checkbox Kitchen Sink", fillable=True)

with ui.layout_columns():
with ui.card():
ui.card_header("Default checkbox with label")
ui.input_checkbox("default", "Basic Checkbox")

with ui.card():
ui.card_header("Checkbox With Value")
ui.input_checkbox("value", "Checkbox with Value", value=True)

with ui.card():
ui.card_header("Checkbox With Width")
ui.input_checkbox("width", "Checkbox with Width", width="10px")
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from playwright.sync_api import Page

from shiny.playwright import controller
from shiny.run import ShinyAppProc


def test_checkbox_kitchen(page: Page, local_app: ShinyAppProc) -> None:
page.goto(local_app.url)

default = controller.InputCheckbox(page, "default")
default.expect_label("Basic Checkbox")

value = controller.InputCheckbox(page, "value")
value.expect_checked(True)

width = controller.InputCheckbox(page, "width")
width.expect_width("10px")
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from shiny.express import input, render, ui

ui.page_opts(title="Checkbox Group Kitchen Sink", fillable=True)

choices = ["Option A", "Option B", "Option C", "Option D"]

choices_dict = {
"value1": "Option A",
"value2": "Option B",
"value3": "Option C",
"value4": "Option D",
}

with ui.layout_columns():
with ui.card():
ui.card_header("Default Checkbox Group with label")
ui.input_checkbox_group("default", "Basic Checkbox Group", choices=choices)

with ui.card():
ui.card_header("With Selected Values")
ui.input_checkbox_group(
"selected",
"Selected Values",
choices=choices,
selected=["Option B", "Option C"],
)

with ui.card():
ui.card_header("With Width")
ui.input_checkbox_group("width", "Custom Width", choices=choices, width="30px")

with ui.card():
ui.card_header("Inline")
ui.input_checkbox_group(
"inline", "Inline Checkbox Group", choices=choices, inline=True
)

@render.code
def inline_val_txt():
return "You chose " + ", ".join(input.inline())

with ui.card():
ui.card_header("With dict of values")
ui.input_checkbox_group(
"dict_values",
"Dict Values",
choices=choices_dict,
)

@render.code
def dict_value_txt():
return "You chose " + ", ".join(input.dict_values())
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from playwright.sync_api import Page

from shiny.playwright import controller
from shiny.run import ShinyAppProc


def test_checkbox_group_kitchen(page: Page, local_app: ShinyAppProc) -> None:
page.goto(local_app.url)

default = controller.InputCheckboxGroup(page, "default")
default.expect_label("Basic Checkbox Group")
default.expect_selected([])

selected = controller.InputCheckboxGroup(page, "selected")
selected.expect_selected(["Option B", "Option C"])

width = controller.InputCheckboxGroup(page, "width")
width.expect_width("30px")

inline = controller.InputCheckboxGroup(page, "inline")
inline.expect_inline(True)
inline.set(["Option A", "Option D"])
inline.expect_selected(["Option A", "Option D"])

inline_code = controller.OutputCode(page, "inline_val_txt")
inline_code.expect_value("You chose Option A, Option D")

dict_values = controller.InputCheckboxGroup(page, "dict_values")
dict_values.expect_selected([])
dict_values.set(["value1", "value4"])
dict_values.expect_selected(["value1", "value4"])

dict_values_code = controller.OutputCode(page, "dict_value_txt")
dict_values_code.expect_value("You chose value1, value4")
2 changes: 0 additions & 2 deletions tests/playwright/shiny/inputs/test_input_checkbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ def test_input_checkbox_kitchen(page: Page, app: ShinyAppProc) -> None:
somevalue.expect_label("Some value")

somevalue.expect_checked(False)
somevalue.expect_width(None)

output_txt.expect.to_have_text("False")

somevalue.set(True)
Expand Down
Loading