Skip to content

Commit

Permalink
tests(input_numeric): Add kitchensink tests for more input components (
Browse files Browse the repository at this point in the history
  • Loading branch information
karangattu authored Oct 1, 2024
1 parent 4f71720 commit 2e019cd
Show file tree
Hide file tree
Showing 28 changed files with 658 additions and 53 deletions.
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Added `.expect_widths()` to `NavsetPillList` in `shiny.playwright.controllers` for testing `ui.navset_pill_list(widths=)`. (#1668)

* Added `.expect_title()` for `Popover` controller (#1683)
* Added `.expect_title()` for `Popover` in `shiny.playwright.controllers` (#1683)

* Added `.expect_disabled()` for `InputActionButton` in `shiny.playwright.controllers` (#1705)

* Small improvements to the default pulse busy indicator to better blend with any background. It's also now slightly smaller by default.(#1707)

Expand All @@ -37,11 +39,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* `ui.Theme()` now works correctly on Windows when the theme requires Sass compilation. (thanks @yuuuxt, #1684)

* Fixed the `InputSlider` playwright controller's `.expect_width()` to check the `width` property within the `style` attribute. (#1691)
* Fixed multiple input controllers (`InputSlider`, `InputDate`, `InputDateRange`, `InputCheckbox`, and `InputCheckboxGroup`) in `shiny.playwright.controller` to check the `width` property within the `style` attribute. (#1691, #1696, #1702)

* Fixed multiple input controllers (`InputSwitch`, `InputRadioButtons`, `InputNumeric`, `InputText`, `InputTextArea`, `InputPassword`, `InputActionButton`, and `InputActionLink`) in `shiny.playwright.controller` to correctly validate the `width` style property in `.expect_width(). (#1705)

* Fixed the `InputDate` and `InputDateRange` playwright controllers to check the `width` property within the `style` attribute. (#1696)
* Fixed input controller `InputTextArea` in `shiny.playwright.controller` to correctly validate the `resize` style property in `.expect_resize()`. (#1705)

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

* Fixed a bug in `ui.conditional_panel()` that would cause the panel to repeatedly show/hide itself when the provided condition did not evaluate to a boolean value. (#1707)

Expand Down
50 changes: 38 additions & 12 deletions shiny/playwright/controller/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,11 +333,10 @@ def expect_label(
playwright_expect(self.loc_label).to_have_text(value, timeout=timeout)


class WidthLocM:
class WidthLocStlyeM:
"""
A mixin class representing the `.loc`'s width.
A mixin class that provides methods to control the width of input action buttons and action links.
This class provides methods to expect the width attribute of a DOM element.
"""

def expect_width(
Expand All @@ -356,24 +355,24 @@ def expect_width(
timeout
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
"""
_expect_attribute_to_have_value(self.loc, "width", value=value, timeout=timeout)
_expect_style_to_have_value(self.loc, "width", value, timeout=timeout)


class WidthContainerM:
class WidthLocM:
"""
A mixin class representing the container's width.
A mixin class representing the `.loc`'s width.
This class provides methods to expect the width attribute of a DOM element's container.
This class provides methods to expect the width attribute of a DOM element.
"""

def expect_width(
self: UiWithContainerP,
self: UiBaseP,
value: AttrValue,
*,
timeout: Timeout = None,
) -> None:
"""
Expect the `width` attribute of a input's container to have a specific value.
Expect the `width` attribute of a DOM element to have a specific value.
Parameters
----------
Expand All @@ -382,9 +381,36 @@ def expect_width(
timeout
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
"""
_expect_attribute_to_have_value(
self.loc_container, "width", value=value, timeout=timeout
)
_expect_attribute_to_have_value(self.loc, "width", value=value, timeout=timeout)


# # Currently not being used, hence commenting
# class WidthContainerM:
# """
# A mixin class representing the container's width.

# This class provides methods to expect the width attribute of a DOM element's container.
# """

# def expect_width(
# self: UiWithContainerP,
# value: AttrValue,
# *,
# timeout: Timeout = None,
# ) -> None:
# """
# Expect the `width` attribute of a input's container to have a specific value.

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


class WidthContainerStyleM:
Expand Down
27 changes: 24 additions & 3 deletions shiny/playwright/controller/_input_buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@
expect_attribute_to_have_value as _expect_attribute_to_have_value,
)
from ..expect._internal import expect_style_to_have_value as _expect_style_to_have_value
from ._base import InputActionBase, UiBase, UiWithLabel, WidthLocM, _expect_multiple
from ._base import (
InputActionBase,
UiBase,
UiWithLabel,
WidthLocStlyeM,
_expect_multiple,
)


class InputActionButton(
WidthLocM,
WidthLocStlyeM,
InputActionBase,
):
"""Controller for :func:`shiny.ui.input_action_button`."""
Expand All @@ -43,6 +49,21 @@ def __init__(
loc=f"button#{id}.action-button.shiny-bound-input",
)

def expect_disabled(self, value: bool, *, timeout: Timeout = None):
"""
Expect the input action button to be disabled.
Parameters
----------
value
The expected value of the `disabled` attribute.
timeout
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
"""
_expect_attribute_to_have_value(
self.loc, "disabled", "" if value else None, timeout=timeout
)


class InputDarkMode(UiBase):
"""Controller for :func:`shiny.ui.input_dark_mode`."""
Expand Down Expand Up @@ -131,7 +152,7 @@ def expect_attribute(self, value: str, *, timeout: Timeout = None):


class InputTaskButton(
WidthLocM,
WidthLocStlyeM,
InputActionBase,
):
"""Controller for :func:`shiny.ui.input_task_button`."""
Expand Down
42 changes: 8 additions & 34 deletions shiny/playwright/controller/_input_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,14 @@
from ._base import (
Resize,
UiBaseP,
UiWithContainerP,
UiWithLabel,
WidthLocM,
WidthContainerStyleM,
all_missing,
not_is_missing,
set_text,
)


class InputDateWidthM:
"""
A mixin class for input date width.
This mixin class provides methods to expect the width of input date elements.
"""

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 _SetTextM:
def set(self: UiBaseP, value: str, *, timeout: Timeout = None) -> None:
"""
Expand Down Expand Up @@ -91,7 +65,7 @@ def expect_value(
class InputNumeric(
_SetTextM,
_ExpectTextInputValueM,
WidthLocM,
WidthContainerStyleM,
UiWithLabel,
):
"""Controller for :func:`shiny.ui.input_numeric`."""
Expand Down Expand Up @@ -242,7 +216,7 @@ def expect_autocomplete(
class InputText(
_SetTextM,
_ExpectTextInputValueM,
WidthLocM,
WidthContainerStyleM,
_ExpectPlaceholderAttrM,
_ExpectAutocompleteAttrM,
_ExpectSpellcheckAttrM,
Expand Down Expand Up @@ -271,6 +245,7 @@ def __init__(self, page: Page, id: str) -> None:
class InputPassword(
_SetTextM,
_ExpectTextInputValueM,
WidthContainerStyleM,
_ExpectPlaceholderAttrM,
UiWithLabel,
):
Expand Down Expand Up @@ -316,6 +291,7 @@ def expect_width(

class InputTextArea(
_SetTextM,
WidthContainerStyleM,
_ExpectTextInputValueM,
_ExpectPlaceholderAttrM,
_ExpectAutocompleteAttrM,
Expand Down Expand Up @@ -421,9 +397,7 @@ def expect_resize(
timeout
The maximum time to wait for the expectation to be fulfilled. Defaults to `None`.
"""
_expect_attribute_to_have_value(
self.loc, "resize", value=value, timeout=timeout
)
_expect_style_to_have_value(self.loc, "resize", value=value, timeout=timeout)

def expect_autoresize(
self,
Expand All @@ -450,7 +424,7 @@ def expect_autoresize(


class _DateBase(
InputDateWidthM,
WidthContainerStyleM,
_SetTextM,
UiWithLabel,
):
Expand Down Expand Up @@ -694,7 +668,7 @@ def __init__(self, page: Page, id: str) -> None:
)


class InputDateRange(InputDateWidthM, UiWithLabel):
class InputDateRange(WidthContainerStyleM, UiWithLabel):
"""Controller for :func:`shiny.ui.input_date_range`."""

loc_separator: Locator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from faicons import icon_svg

from shiny.express import input, render, ui

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

with ui.layout_columns():
with ui.card():
ui.h3("Default Action Button")
ui.input_action_button("default", label="Default button")

@render.code
def default_txt():
return f"Button clicked {input.default()} times"

with ui.card():
ui.h3("With Custom Width")
ui.input_action_button("width", "Wide button", width="200px")

@render.code
def width_txt():
return f"Button clicked {input.width()} times"

with ui.card():
ui.h3("With Icon")
ui.input_action_button(
"icon", "Button with icon", icon=icon_svg("trash-arrow-up")
)

@render.code
def icon_txt():
return f"Button clicked {input.icon()} times"

with ui.card():
ui.h3("Disabled Button")
ui.input_action_button("disabled", "Disabled button", disabled=True)

@render.code
def disabled_txt():
return f"Button clicked {input.disabled()} times"
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from playwright.sync_api import Page
from playwright.sync_api import expect as playwright_expect

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


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

default = controller.InputActionButton(page, "default")
default.expect_label("Default button")
default.expect_disabled(False)
controller.OutputCode(page, "default_txt").expect_value("Button clicked 0 times")
default.click()
controller.OutputCode(page, "default_txt").expect_value("Button clicked 1 times")

width = controller.InputActionButton(page, "width")
width.expect_width("200px")

disabled = controller.InputActionButton(page, "disabled")
disabled.expect_disabled(True)
# Disabled button should not have an icon
playwright_expect(disabled.loc.locator("svg.fa")).to_have_count(0)

icon = controller.InputActionButton(page, "icon")
playwright_expect(icon.loc.locator("svg.fa")).to_have_count(1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from faicons import icon_svg

from shiny.express import input, render, ui

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

with ui.layout_columns():
with ui.card():
ui.input_action_link("default", label="Default action link")

@render.code
def default_txt():
return f"Link clicked {input.default()} times"

with ui.card():
ui.input_action_link("icon", "Link with icon", icon=icon_svg("trash-arrow-up"))

@render.code
def icon_txt():
return f"Link clicked {input.icon()} times"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from playwright.sync_api import Page
from playwright.sync_api import expect as playwright_expect

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


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

default = controller.InputActionLink(page, "default")
default.expect_label("Default action link")
playwright_expect(default.loc.locator("svg.fa")).to_have_count(0)
controller.OutputCode(page, "default_txt").expect_value("Link clicked 0 times")
default.click()
controller.OutputCode(page, "default_txt").expect_value("Link clicked 1 times")

icon = controller.InputActionLink(page, "icon")
playwright_expect(icon.loc.locator("svg.fa")).to_have_count(1)
Loading

0 comments on commit 2e019cd

Please sign in to comment.