diff --git a/CHANGELOG.md b/CHANGELOG.md index db516d0fa..6e29a5bd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,9 @@ 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` controller's `.expect_width()` to check the `width` property within the `style` attribute. (#1691) +* Fixed the `InputSlider` playwright controller's `.expect_width()` to check the `width` property within the `style` attribute. (#1691) + +* Fixed the `InputDate` and `InputDateRange` playwright controllers to check the `width` property within the `style` attribute. (#1696) ## [1.1.0] - 2024-09-03 diff --git a/shiny/api-examples/input_date/app-core.py b/shiny/api-examples/input_date/app-core.py index 8717487db..44b3189a0 100644 --- a/shiny/api-examples/input_date/app-core.py +++ b/shiny/api-examples/input_date/app-core.py @@ -3,26 +3,43 @@ from shiny import App, Inputs, Outputs, Session, ui app_ui = ui.page_fluid( - ui.input_date("date1", "Date:", value="2016-02-29"), + ui.input_date("date1", "Has default date:", value="2016-02-29"), # Default value is the date in client's time zone - ui.input_date("date2", "Date:"), + ui.input_date("date2", "Client's current date:"), # value is always yyyy-mm-dd, even if the display format is different - ui.input_date("date3", "Date:", value="2016-02-29", format="mm/dd/yy"), + ui.input_date("date3", "Format mm/dd/yy:", value="2016-02-29", format="mm/dd/yy"), # Pass in a Date object - ui.input_date("date4", "Date:", value=date(2016, 2, 29)), + ui.input_date("date4", "Default uses date object:", value=date(2016, 2, 29)), # Use different language and different first day of week - ui.input_date("date5", "Date:", language="ru", weekstart=1), + ui.input_date( + "date5", + "Language is German and the week starts on Monday:", + language="ru", + weekstart=1, + ), # Start with decade view instead of default month view - ui.input_date("date6", "Date:", startview="decade"), + ui.input_date("date6", "Start Date picker in Decade view:", startview="decade"), # Disable Mondays and Tuesdays. - ui.input_date("date7", "Date:", daysofweekdisabled=[1, 2]), + ui.input_date("date7", "Disable Monday and Tuesday:", daysofweekdisabled=[1, 2]), # Disable specific dates. ui.input_date( "date8", - "Date:", + "Disable specific dates:", value="2016-02-29", datesdisabled=["2016-03-01", "2016-03-02"], ), + # Set min and max dates. + ui.input_date( + "date9", + "Set min and max dates:", + value="2016-02-03", + min="2016-02-01", + max="2016-02-29", + ), + # Set width of the date field + ui.input_date("date10", "Set width of text input:", width="600px"), + # Set autoclose to false + ui.input_date("date11", "Auto close is disabled:", autoclose=False), ) diff --git a/shiny/api-examples/input_date/app-express.py b/shiny/api-examples/input_date/app-express.py index bd696beb3..23f2def73 100644 --- a/shiny/api-examples/input_date/app-express.py +++ b/shiny/api-examples/input_date/app-express.py @@ -2,23 +2,40 @@ from shiny.express import ui -ui.input_date("date1", "Date:", value="2016-02-29") +ui.input_date("date1", "Has default date:", value="2016-02-29") # Default value is the date in client's time zone -ui.input_date("date2", "Date:") +ui.input_date("date2", "Client's current date:") # value is always yyyy-mm-dd, even if the display format is different -ui.input_date("date3", "Date:", value="2016-02-29", format="mm/dd/yy") +ui.input_date("date3", "Format mm/dd/yy:", value="2016-02-29", format="mm/dd/yy") # Pass in a Date object -ui.input_date("date4", "Date:", value=date(2016, 2, 29)) +ui.input_date("date4", "Default uses date object:", value=date(2016, 2, 29)) # Use different language and different first day of week -ui.input_date("date5", "Date:", language="ru", weekstart=1) +ui.input_date( + "date5", + "Language is German and the week starts on Monday:", + language="ru", + weekstart=1, +) # Start with decade view instead of default month view -ui.input_date("date6", "Date:", startview="decade") +ui.input_date("date6", "Start Date picker in Decade view:", startview="decade") # Disable Mondays and Tuesdays. -ui.input_date("date7", "Date:", daysofweekdisabled=[1, 2]) +ui.input_date("date7", "Disable Monday and Tuesday:", daysofweekdisabled=[1, 2]) # Disable specific dates. ui.input_date( "date8", - "Date:", + "Disable specific dates:", value="2016-02-29", datesdisabled=["2016-03-01", "2016-03-02"], ) +# Set min and max dates. +ui.input_date( + "date9", + "Set min and max dates:", + value="2016-02-03", + min="2016-02-01", + max="2016-02-29", +) +# Set width of the date field +ui.input_date("date10", "Set width of text input:", width="600px") +# Set autoclose to false +ui.input_date("date11", "Auto close is disabled:", autoclose=False) diff --git a/shiny/api-examples/input_date_range/app-core.py b/shiny/api-examples/input_date_range/app-core.py index 07b4bcbac..77baf2c34 100644 --- a/shiny/api-examples/input_date_range/app-core.py +++ b/shiny/api-examples/input_date_range/app-core.py @@ -3,16 +3,17 @@ from shiny import App, Inputs, Outputs, Session, ui app_ui = ui.page_fluid( + # Default start and end is the current date in the client's time zone + ui.input_date_range("daterange1", "Date range:"), + # Set start and end dates ui.input_date_range( - "daterange1", "Date range:", start="2001-01-01", end="2010-12-31" + "daterange2", "Set start and end date:", start="2001-01-01", end="2010-12-31" ), - # Default start and end is the current date in the client's time zone - ui.input_date_range("daterange2", "Date range:"), - # start and end are always specified in yyyy-mm-dd, even if the display + # Start and end are always specified in yyyy-mm-dd, even if the display # format is different ui.input_date_range( "daterange3", - "Date range:", + "Min, max, start, and end dates are set with custom format and separator:", start="2001-01-01", end="2010-12-31", min="2001-01-01", @@ -22,12 +23,26 @@ ), # Pass in Date objects ui.input_date_range( - "daterange4", "Date range:", start=date(2001, 1, 1), end=date(2010, 12, 31) + "daterange4", + "Default start and end use date objects:", + start=date(2001, 1, 1), + end=date(2010, 12, 31), ), # Use different language and different first day of week - ui.input_date_range("daterange5", "Date range:", language="de", weekstart=1), + ui.input_date_range( + "daterange5", + "Language is German and we starts on Monday:", + language="de", + weekstart=1, + ), # Start with decade view instead of default month view - ui.input_date_range("daterange6", "Date range:", startview="decade"), + ui.input_date_range( + "daterange6", "Start Date picker in Decade view:", startview="decade" + ), + # Set width of the daterange field + ui.input_date_range("daterange7", "Set width of text input:", width="600px"), + # Set autoclose to false + ui.input_date_range("daterange8", "Auto close is disabled:", autoclose=False), ) diff --git a/shiny/api-examples/input_date_range/app-express.py b/shiny/api-examples/input_date_range/app-express.py index 66f79c5c4..7e7074560 100644 --- a/shiny/api-examples/input_date_range/app-express.py +++ b/shiny/api-examples/input_date_range/app-express.py @@ -2,14 +2,17 @@ from shiny.express import ui -ui.input_date_range("daterange1", "Date range:", start="2001-01-01", end="2010-12-31") # Default start and end is the current date in the client's time zone -ui.input_date_range("daterange2", "Date range:") -# start and end are always specified in yyyy-mm-dd, even if the display +ui.input_date_range("daterange1", "Date range:") +# Set start and end dates +ui.input_date_range( + "daterange2", "Set start and end date:", start="2001-01-01", end="2010-12-31" +) +# Start and end are always specified in yyyy-mm-dd, even if the display # format is different ui.input_date_range( "daterange3", - "Date range:", + "Min, max, start, and end dates are set with custom format and separator:", start="2001-01-01", end="2010-12-31", min="2001-01-01", @@ -19,9 +22,23 @@ ) # Pass in Date objects ui.input_date_range( - "daterange4", "Date range:", start=date(2001, 1, 1), end=date(2010, 12, 31) + "daterange4", + "Default start and end use date objects:", + start=date(2001, 1, 1), + end=date(2010, 12, 31), ) # Use different language and different first day of week -ui.input_date_range("daterange5", "Date range:", language="de", weekstart=1) +ui.input_date_range( + "daterange5", + "Language is German and we starts on Monday:", + language="de", + weekstart=1, +) # Start with decade view instead of default month view -ui.input_date_range("daterange6", "Date range:", startview="decade") +ui.input_date_range( + "daterange6", "Start Date picker in Decade view:", startview="decade" +) +# Set width of the daterange field +ui.input_date_range("daterange7", "Set width of text input:", width="600px") +# Set autoclose to false +ui.input_date_range("daterange8", "Auto close is disabled:", autoclose=False) diff --git a/shiny/playwright/controller/_accordion.py b/shiny/playwright/controller/_accordion.py index d5981e156..890b03bde 100644 --- a/shiny/playwright/controller/_accordion.py +++ b/shiny/playwright/controller/_accordion.py @@ -229,7 +229,7 @@ def expect_width(self, value: StyleValue, *, timeout: Timeout = None) -> None: value The expected width. timeout - The maximum time to wait for the width to be visible and interactable. Defaults to `None`. + 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) diff --git a/shiny/playwright/controller/_input_buttons.py b/shiny/playwright/controller/_input_buttons.py index e55e8cbfe..59326ee62 100644 --- a/shiny/playwright/controller/_input_buttons.py +++ b/shiny/playwright/controller/_input_buttons.py @@ -420,7 +420,7 @@ def expect_width(self, value: StyleValue, *, timeout: Timeout = None) -> None: value The expected value of the width. timeout - The timeout for the expectation. Defaults to `None`. + 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) diff --git a/shiny/playwright/controller/_input_controls.py b/shiny/playwright/controller/_input_controls.py index 663cd039e..54fc5ac12 100644 --- a/shiny/playwright/controller/_input_controls.py +++ b/shiny/playwright/controller/_input_controls.py @@ -211,7 +211,7 @@ def expect_width(self, value: str, *, timeout: Timeout = None) -> None: value The expected width. timeout - The maximum time to wait for the width to be visible and interactable. Defaults to `None`. + 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) diff --git a/shiny/playwright/controller/_input_fields.py b/shiny/playwright/controller/_input_fields.py index 1054e2207..affa9cee7 100644 --- a/shiny/playwright/controller/_input_fields.py +++ b/shiny/playwright/controller/_input_fields.py @@ -17,8 +17,8 @@ from ._base import ( Resize, UiBaseP, + UiWithContainerP, UiWithLabel, - WidthContainerM, WidthLocM, all_missing, not_is_missing, @@ -26,6 +26,31 @@ ) +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: """ @@ -425,8 +450,8 @@ def expect_autoresize( class _DateBase( + InputDateWidthM, _SetTextM, - WidthContainerM, UiWithLabel, ): @@ -669,7 +694,7 @@ def __init__(self, page: Page, id: str) -> None: ) -class InputDateRange(WidthContainerM, UiWithLabel): +class InputDateRange(InputDateWidthM, UiWithLabel): """Controller for :func:`shiny.ui.input_date_range`.""" loc_separator: Locator @@ -933,8 +958,6 @@ def expect_separator( """ playwright_expect(self.loc_separator).to_have_text(value, timeout=timeout) - # width: Optional[str] = None, - # autoclose: bool = True, def expect_autoclose( self, diff --git a/tests/playwright/shiny/inputs/test_input_date.py b/tests/playwright/shiny/inputs/test_input_date.py index 38e8f74f8..57786ce73 100644 --- a/tests/playwright/shiny/inputs/test_input_date.py +++ b/tests/playwright/shiny/inputs/test_input_date.py @@ -5,7 +5,7 @@ from typing import Literal from conftest import create_doc_example_core_fixture -from playwright.sync_api import Page, expect +from playwright.sync_api import Page from shiny.playwright import controller from shiny.run import ShinyAppProc @@ -17,7 +17,6 @@ def expect_date( date: controller.InputDate, value: str | Literal["today"] = "today", *, - label: str = "Date:", autoclose: bool = True, datesdisabled: typing.Optional[list[str]] = None, daysofweekdisabled: typing.Optional[list[int]] = None, @@ -47,9 +46,7 @@ def test_input_date_kitchen(page: Page, app: ShinyAppProc) -> None: page.goto(app.url) date1 = controller.InputDate(page, "date1") - - date1.expect_label("Date:") - expect(date1.loc_label).to_have_text("Date:") + date1.expect_label("Has default date:") expect_date(date1, "2016-02-29") @@ -75,3 +72,14 @@ def test_input_date_kitchen(page: Page, app: ShinyAppProc) -> None: "2016-02-29", datesdisabled=["2016-03-01", "2016-03-02"], ) + + expect_date( + controller.InputDate(page, "date9"), + "2016-02-03", + min_date="2016-02-01", + max_date="2016-02-29", + ) + + expect_date(controller.InputDate(page, "date10"), width="600px") + + expect_date(controller.InputDate(page, "date11"), autoclose=False) diff --git a/tests/playwright/shiny/inputs/test_input_date_range.py b/tests/playwright/shiny/inputs/test_input_date_range.py index e5f9c7a6e..ed9d5bac6 100644 --- a/tests/playwright/shiny/inputs/test_input_date_range.py +++ b/tests/playwright/shiny/inputs/test_input_date_range.py @@ -5,7 +5,7 @@ from typing import Literal from conftest import create_doc_example_core_fixture -from playwright.sync_api import Page, expect +from playwright.sync_api import Page from shiny.playwright import controller from shiny.run import ShinyAppProc @@ -18,10 +18,7 @@ def expect_date_range( start_value: str | Literal["today"] = "today", end_value: str | Literal["today"] = "today", *, - label: str = "Date:", autoclose: bool = True, - datesdisabled: typing.Optional[list[str]] = None, - daysofweekdisabled: typing.Optional[list[int]] = None, format: str = "yyyy-mm-dd", language: str = "en", max_date: typing.Optional[str] = None, @@ -36,9 +33,6 @@ def expect_date_range( date.expect_value((start_value, end_value)) autoclose_str = "true" if autoclose else "false" date.expect_autoclose(autoclose_str) - # # Not supported in `input_date_range()` - # date.expect_datesdisabled(datesdisabled) - # date.expect_daysofweekdisabled(daysofweekdisabled) date.expect_format(format) date.expect_language(language) date.expect_max_date(max_date) @@ -55,14 +49,17 @@ def test_input_date_kitchen(page: Page, app: ShinyAppProc) -> None: daterange1 = controller.InputDateRange(page, "daterange1") daterange1.expect_label("Date range:") - expect(daterange1.loc_label).to_have_text("Date range:") - - expect_date_range(daterange1, "2001-01-01", "2010-12-31") - - daterange1.set(("2012-02-02", "2012-11-15")) - expect_date_range(daterange1, "2012-02-02", "2012-11-15") + today = str(datetime.date.today().strftime("%Y-%m-%d")) + tommorow = str( + (datetime.date.today() + datetime.timedelta(days=1)).strftime("%Y-%m-%d") + ) + daterange1.set((today, today)) + expect_date_range(daterange1, today, today) + daterange1.set((today, tommorow)) - expect_date_range(controller.InputDateRange(page, "daterange2")) + expect_date_range( + controller.InputDateRange(page, "daterange2"), "2001-01-01", "2010-12-31" + ) expect_date_range( controller.InputDateRange(page, "daterange3"), @@ -88,3 +85,13 @@ def test_input_date_kitchen(page: Page, app: ShinyAppProc) -> None: controller.InputDateRange(page, "daterange6"), startview="decade", ) + + expect_date_range( + controller.InputDateRange(page, "daterange7"), + width="600px", + ) + + expect_date_range( + controller.InputDateRange(page, "daterange8"), + autoclose=False, + )