From 81712607a3226870a7b08d38b9df0e7ef2af1d5d Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Thu, 28 Mar 2024 10:30:27 -0700 Subject: [PATCH 1/9] Add tests for shiny client errors and card kitchensink tests --- tests/playwright/controls.py | 143 ++++++++++++++++++ .../deploys/shiny-client-error/app.py | 11 ++ .../shiny-client-error/app_requirements.txt | 2 + .../test_shiny_client_error.py | 27 ++++ .../experimental/card/kitchensink/app.py | 27 ++++ .../card/kitchensink/test_card_ks.py | 63 ++++++++ 6 files changed, 273 insertions(+) create mode 100644 tests/playwright/deploys/shiny-client-error/app.py create mode 100644 tests/playwright/deploys/shiny-client-error/app_requirements.txt create mode 100644 tests/playwright/deploys/shiny-client-error/test_shiny_client_error.py create mode 100644 tests/playwright/shiny/experimental/card/kitchensink/app.py create mode 100644 tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py diff --git a/tests/playwright/controls.py b/tests/playwright/controls.py index 72ebdb3b6..df21f9ffa 100644 --- a/tests/playwright/controls.py +++ b/tests/playwright/controls.py @@ -351,22 +351,53 @@ def expect_label( class _WidthLocM: + """ + A class representing the width location mixin. + This class provides methods to expect the width attribute of an element. + """ + def expect_width( self: _InputBaseP, value: AttrValue, *, timeout: Timeout = None, ) -> None: + """ + Expect the width attribute of an element 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_attr(self.loc, "width", value=value, timeout=timeout) class _WidthContainerM: + """ + A class representing the width container mixin. + This class provides methods to expect the width attribute of an element's container. + """ def expect_width( self: _InputWithContainerP, value: AttrValue, *, timeout: Timeout = None, ) -> None: + """ + Expect the width attribute of an element'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_attr(self.loc_container, "width", value=value, timeout=timeout) @@ -2854,6 +2885,26 @@ def expect_full_screen_available( class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithContainer): + """ + Card control for shiny.ui.card - https://shiny.posit.co/py/api/core/ui.card.html + """ + + loc: Locator + """ + Locator for the card's value + """ + loc_title: Locator + """ + Locator for the card title + """ + loc_footer: Locator + """ + Locator for the card footer + """ + loc_body: Locator + """ + Locator for the card body + """ # *args: TagChild | TagAttrs | CardItem, # full_screen: bool = False, # height: CssUnit | None = None, @@ -2864,6 +2915,16 @@ class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithCon # wrapper: WrapperCallable | MISSING_TYPE | None = MISSING, # **kwargs: TagAttrValue def __init__(self, page: Page, id: str) -> None: + """ + Initializes a new instance of the Card class. + + Parameters + ---------- + page + The Playwright page object. + id + The ID of the card. + """ super().__init__( page, id=id, @@ -2890,6 +2951,16 @@ def expect_header( *, timeout: Timeout = None, ) -> None: + """ + Expects the card header to have a specific text. + + Parameters + ---------- + text + The expected text pattern or string. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ playwright_expect(self.loc_title).to_have_text( text, timeout=timeout, @@ -2909,14 +2980,86 @@ def expect_header( # ) def expect_max_height(self, value: StyleValue, *, timeout: Timeout = None) -> None: + """ + Expects the card to have a specific maximum height. + + Parameters + ---------- + value + The expected maximum height value. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ expect_to_have_style(self.loc_container, "max-height", value, timeout=timeout) def expect_min_height(self, value: StyleValue, *, timeout: Timeout = None) -> None: + """ + Expects the card to have a specific minimum height. + + Parameters + ---------- + value + The expected minimum height value. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ expect_to_have_style(self.loc_container, "min-height", value, timeout=timeout) def expect_height(self, value: StyleValue, *, timeout: Timeout = None) -> None: + """ + Expects the card to have a specific height. + + Parameters + ---------- + value + The expected height value. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ expect_to_have_style(self.loc_container, "height", value, timeout=timeout) + def expect_full_screen_available( + self, available: bool, *, timeout: Timeout = None + ) -> None: + """ + Expects the card to be available for full screen mode. + + Parameters + ---------- + available + True if the value box is expected to be available for full screen mode, False otherwise. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ + playwright_expect(self._loc_fullscreen).to_have_count( + int(available), timeout=timeout + ) + + def expect_header_exists(self, exists: bool, *, timeout: Timeout = None) -> None: + """ + Expects the card header to exist or not. + + Parameters + ---------- + exists + True if the card header is expected to exist, False otherwise. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ + playwright_expect(self.loc_title).to_have_count(int(exists), timeout=timeout) + + def expect_footer_exists(self, exists: bool, *, timeout: Timeout = None) -> None: + """ + Expects the card footer to exist or not. + + Parameters + ---------- + exists + True if the card footer is expected to exist, False otherwise. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ + playwright_expect(self.loc_footer).to_have_count(int(exists), timeout=timeout) # Experimental below diff --git a/tests/playwright/deploys/shiny-client-error/app.py b/tests/playwright/deploys/shiny-client-error/app.py new file mode 100644 index 000000000..8d9c5e9d4 --- /dev/null +++ b/tests/playwright/deploys/shiny-client-error/app.py @@ -0,0 +1,11 @@ +from shiny import reactive, render +from shiny.express import input, ui + +ui.input_action_button("same_id", "Action") +ui.input_action_button("same_id", "Action") + + +@render.text() +@reactive.event(input.same_id) +def counter(): + return f"{input.same_id()}" diff --git a/tests/playwright/deploys/shiny-client-error/app_requirements.txt b/tests/playwright/deploys/shiny-client-error/app_requirements.txt new file mode 100644 index 000000000..03309f726 --- /dev/null +++ b/tests/playwright/deploys/shiny-client-error/app_requirements.txt @@ -0,0 +1,2 @@ +git+https://github.com/posit-dev/py-htmltools.git#egg=htmltools + diff --git a/tests/playwright/deploys/shiny-client-error/test_shiny_client_error.py b/tests/playwright/deploys/shiny-client-error/test_shiny_client_error.py new file mode 100644 index 000000000..0aaaab81e --- /dev/null +++ b/tests/playwright/deploys/shiny-client-error/test_shiny_client_error.py @@ -0,0 +1,27 @@ +from playwright.sync_api import Page +from utils.deploy_utils import create_deploys_app_url_fixture, skip_if_not_chrome + +app_url = create_deploys_app_url_fixture("shiny_client_error") + + +@skip_if_not_chrome +def test_shiny_client_error(page: Page, app_url: str) -> None: + page.goto(app_url) + + assert page.locator("#same_id").count() == 2 + shiny_error_message = page.query_selector("shiny-error-message") + + # show the client error message only for local apps + if "127.0.0.1:" in app_url: + + assert shiny_error_message is not None + assert ( + shiny_error_message.get_attribute("message") + == 'The following ID was repeated:\n- "same_id": 2 inputs' + ) + assert page.get_by_role("button", name="Dismiss all").count() == 1 + assert page.get_by_role("button", name="Copy error to clipboard").count() == 1 + + # for deployed apps to shinyapps.io or connect hide the client error message + else: + assert shiny_error_message is None diff --git a/tests/playwright/shiny/experimental/card/kitchensink/app.py b/tests/playwright/shiny/experimental/card/kitchensink/app.py new file mode 100644 index 000000000..6e76d68f2 --- /dev/null +++ b/tests/playwright/shiny/experimental/card/kitchensink/app.py @@ -0,0 +1,27 @@ +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.card( + ui.card_header("Check for header"), + "This is the body of a card with default height w/ fullscreen", + ui.card_footer("Check for footer"), + full_screen=True, + id="card1", + ), + ui.card( + ui.p("This is the body without a header of a footer - No Fullscreen"), + full_screen=False, + id="card2", + ), + ui.card( + ui.card_header("Fill is False. Fullscreen is False"), + ui.h3("Max height and min height are set."), + fill=False, + max_height="500px", + min_height="200px", + id="card3", + ), +) + + +app = App(app_ui, server=None) diff --git a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py new file mode 100644 index 000000000..bfc1a8270 --- /dev/null +++ b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py @@ -0,0 +1,63 @@ +from conftest import ShinyAppProc +from controls import Card +from playwright.sync_api import Page + +def get_body_tag_name(card: Card) -> str: + body_tag_name = ( + card.loc_body.locator("*") + .nth(0) + .evaluate("el => el.tagName.toLowerCase()") + ) + return body_tag_name + + +""" +For each card we want to test +Max Height and Min Height: The tests assert the max-height and min-height CSS properties applied to the card. +Header and Footer: The tests verify the presence and content of the header and footer elements within each card. +Body Element: The tests assert the tag name used for the body element within each card (e.g., ,

,

,

,

). +Fullscreen Availability and State: The tests check whether the fullscreen feature is available for a particular card and verify its initial state (fullscreen or not). For cards with fullscreen support, the tests open and close the fullscreen mode and assert the expected behavior. +""" + +def test_card_kitchensink(page: Page, local_app: ShinyAppProc) -> None: + page.goto(local_app.url) + + card = Card(page, "card1") + card.expect_max_height(None) + card.expect_min_height(None) + card.expect_height(None) + card.expect_header("Check for header") + card.expect_footer("Check for footer") + card.expect_body( + [ + "\nThis is the body of a card with default height w/ fullscreen", + ] + ) + card.expect_full_screen(False) + card.open_full_screen() + card.expect_full_screen(True) + card.close_full_screen() + card.expect_full_screen(False) + + card = Card(page, "card2") + card.expect_max_height(None) + card.expect_min_height(None) + card.expect_height(None) + card.expect_header_exists(False) + card.expect_footer_exists(False) + card.expect_body( + ["\nThis is the body without a header of a footer - No Fullscreen\n"] + ) + assert get_body_tag_name(card) == "p" + card.expect_full_screen(False) + card.expect_full_screen_available(False) + + card = Card(page, "card3") + card.expect_max_height("500px") + card.expect_min_height("200px") + card.expect_header("Fill is False. Fullscreen is False") + card.expect_header_exists(True) + card.expect_footer_exists(False) + card.expect_body(["Max height and min height are set."]) + assert get_body_tag_name(card) == "h3" + card.expect_full_screen_available(False) From 83bc5abc4ca04a091a7a381700075838706a3258 Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Thu, 28 Mar 2024 10:30:45 -0700 Subject: [PATCH 2/9] Add linting changes --- tests/playwright/controls.py | 3 +++ .../shiny/experimental/card/kitchensink/test_card_ks.py | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/playwright/controls.py b/tests/playwright/controls.py index df21f9ffa..2fa84e548 100644 --- a/tests/playwright/controls.py +++ b/tests/playwright/controls.py @@ -381,6 +381,7 @@ class _WidthContainerM: A class representing the width container mixin. This class provides methods to expect the width attribute of an element's container. """ + def expect_width( self: _InputWithContainerP, value: AttrValue, @@ -2905,6 +2906,7 @@ class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithCon """ Locator for the card body """ + # *args: TagChild | TagAttrs | CardItem, # full_screen: bool = False, # height: CssUnit | None = None, @@ -3061,6 +3063,7 @@ def expect_footer_exists(self, exists: bool, *, timeout: Timeout = None) -> None """ playwright_expect(self.loc_footer).to_have_count(int(exists), timeout=timeout) + # Experimental below diff --git a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py index bfc1a8270..6b8a2952f 100644 --- a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py +++ b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py @@ -2,11 +2,10 @@ from controls import Card from playwright.sync_api import Page + def get_body_tag_name(card: Card) -> str: body_tag_name = ( - card.loc_body.locator("*") - .nth(0) - .evaluate("el => el.tagName.toLowerCase()") + card.loc_body.locator("*").nth(0).evaluate("el => el.tagName.toLowerCase()") ) return body_tag_name @@ -19,6 +18,7 @@ def get_body_tag_name(card: Card) -> str: Fullscreen Availability and State: The tests check whether the fullscreen feature is available for a particular card and verify its initial state (fullscreen or not). For cards with fullscreen support, the tests open and close the fullscreen mode and assert the expected behavior. """ + def test_card_kitchensink(page: Page, local_app: ShinyAppProc) -> None: page.goto(local_app.url) From 436722e4450d3a527361a19e44baa18be1b85d0e Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Thu, 28 Mar 2024 12:49:10 -0700 Subject: [PATCH 3/9] rename the test name --- .../app.py | 0 .../app_requirements.txt | 0 .../test_shiny_client_error.py | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) rename tests/playwright/deploys/{shiny-client-error => shiny-client-console-error}/app.py (100%) rename tests/playwright/deploys/{shiny-client-error => shiny-client-console-error}/app_requirements.txt (100%) rename tests/playwright/deploys/{shiny-client-error => shiny-client-console-error}/test_shiny_client_error.py (83%) diff --git a/tests/playwright/deploys/shiny-client-error/app.py b/tests/playwright/deploys/shiny-client-console-error/app.py similarity index 100% rename from tests/playwright/deploys/shiny-client-error/app.py rename to tests/playwright/deploys/shiny-client-console-error/app.py diff --git a/tests/playwright/deploys/shiny-client-error/app_requirements.txt b/tests/playwright/deploys/shiny-client-console-error/app_requirements.txt similarity index 100% rename from tests/playwright/deploys/shiny-client-error/app_requirements.txt rename to tests/playwright/deploys/shiny-client-console-error/app_requirements.txt diff --git a/tests/playwright/deploys/shiny-client-error/test_shiny_client_error.py b/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py similarity index 83% rename from tests/playwright/deploys/shiny-client-error/test_shiny_client_error.py rename to tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py index 0aaaab81e..4a2e17ac0 100644 --- a/tests/playwright/deploys/shiny-client-error/test_shiny_client_error.py +++ b/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py @@ -1,18 +1,18 @@ from playwright.sync_api import Page from utils.deploy_utils import create_deploys_app_url_fixture, skip_if_not_chrome -app_url = create_deploys_app_url_fixture("shiny_client_error") +app_url = create_deploys_app_url_fixture("shiny_client_console_error") @skip_if_not_chrome -def test_shiny_client_error(page: Page, app_url: str) -> None: +def test_shiny_client_console_error(page: Page, app_url: str) -> None: page.goto(app_url) assert page.locator("#same_id").count() == 2 shiny_error_message = page.query_selector("shiny-error-message") # show the client error message only for local apps - if "127.0.0.1:" in app_url: + if "http" in app_url: assert shiny_error_message is not None assert ( From eb3122c5ccee42e520e8232ace588668be1c63ce Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Mon, 1 Apr 2024 09:38:09 -0700 Subject: [PATCH 4/9] Add rsconnect config json for deployment test --- .../rsconnect-python/shiny-client-console-error.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/playwright/deploys/shiny-client-console-error/rsconnect-python/shiny-client-console-error.json diff --git a/tests/playwright/deploys/shiny-client-console-error/rsconnect-python/shiny-client-console-error.json b/tests/playwright/deploys/shiny-client-console-error/rsconnect-python/shiny-client-console-error.json new file mode 100644 index 000000000..27dc7bf94 --- /dev/null +++ b/tests/playwright/deploys/shiny-client-console-error/rsconnect-python/shiny-client-console-error.json @@ -0,0 +1,11 @@ +{ + "https://api.shinyapps.io": { + "server_url": "https://api.shinyapps.io", + "app_url": "https://testing-apps.shinyapps.io/shiny_client_console_error/", + "app_id": 11634266, + "app_guid": null, + "title": "shiny_client_console_error", + "app_mode": "python-shiny", + "app_store_version": 1 + } +} From a0caa359cae68694400e36d6ab3c5b44ed253bfc Mon Sep 17 00:00:00 2001 From: Karan Date: Tue, 2 Apr 2024 12:51:57 -0700 Subject: [PATCH 5/9] Apply suggestions from code review Co-authored-by: Barret Schloerke --- tests/playwright/controls.py | 24 +++++++++---------- .../test_shiny_client_error.py | 15 +++++------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/tests/playwright/controls.py b/tests/playwright/controls.py index 2fa84e548..81faf9ed8 100644 --- a/tests/playwright/controls.py +++ b/tests/playwright/controls.py @@ -352,7 +352,7 @@ def expect_label( class _WidthLocM: """ - A class representing the width location mixin. + A mixin class representing the `loc`'s width. This class provides methods to expect the width attribute of an element. """ @@ -367,18 +367,18 @@ def expect_width( Parameters ---------- - value - The expected value of the width attribute. - timeout - The maximum time to wait for the expectation to be fulfilled. - Defaults to None. + value + The expected value of the width attribute. + timeout + The maximum time to wait for the expectation to be fulfilled. + Defaults to None. """ expect_attr(self.loc, "width", value=value, timeout=timeout) class _WidthContainerM: """ - A class representing the width container mixin. + A mixin class representing the container's width. This class provides methods to expect the width attribute of an element's container. """ @@ -2887,24 +2887,24 @@ def expect_full_screen_available( class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithContainer): """ - Card control for shiny.ui.card - https://shiny.posit.co/py/api/core/ui.card.html + Card control for :func:`~shiny.ui.card` """ loc: Locator """ - Locator for the card's value + `Locator` for the card's value """ loc_title: Locator """ - Locator for the card title + `Locator` for the card title """ loc_footer: Locator """ - Locator for the card footer + `Locator` for the card footer """ loc_body: Locator """ - Locator for the card body + `Locator` for the card body """ # *args: TagChild | TagAttrs | CardItem, diff --git a/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py b/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py index 4a2e17ac0..469573689 100644 --- a/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py +++ b/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py @@ -12,16 +12,13 @@ def test_shiny_client_console_error(page: Page, app_url: str) -> None: shiny_error_message = page.query_selector("shiny-error-message") # show the client error message only for local apps - if "http" in app_url: + if "127.0.0.1" in app_url: - assert shiny_error_message is not None - assert ( - shiny_error_message.get_attribute("message") - == 'The following ID was repeated:\n- "same_id": 2 inputs' - ) - assert page.get_by_role("button", name="Dismiss all").count() == 1 - assert page.get_by_role("button", name="Copy error to clipboard").count() == 1 + expect(shiny_error_message).not_to_have_count(0) + expect(shiny_error_message).to_have_attribute("message", "'The following ID was repeated:\n- "same_id": 2 inputs'") + expect(page.get_by_role("button", name="Dismiss all")).to_have_count(1) + expect(page.get_by_role("button", name="Copy error to clipboard")).to_have_count(1) # for deployed apps to shinyapps.io or connect hide the client error message else: - assert shiny_error_message is None + expect(shiny_error_message).to_have_count(0) From c3c4b1a32e723ee5468e7b9787a0e7e74b9ef0a1 Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Tue, 2 Apr 2024 13:45:59 -0700 Subject: [PATCH 6/9] Address some more code review suggestions --- tests/playwright/controls.py | 85 ++++++++----------- .../test_shiny_client_error.py | 12 ++- .../card/kitchensink/test_card_ks.py | 11 ++- 3 files changed, 48 insertions(+), 60 deletions(-) diff --git a/tests/playwright/controls.py b/tests/playwright/controls.py index 81faf9ed8..dcf8934b1 100644 --- a/tests/playwright/controls.py +++ b/tests/playwright/controls.py @@ -2732,24 +2732,24 @@ class ValueBox( _InputWithContainer, ): """ - ValueBox control for shiny.ui.value_box - https://shiny.posit.co/py/api/core/ui.value_box.html + ValueBox control for :func:`~shiny.ui.value_box` """ loc: Locator """ - Locator for the value box's value + `Locator` for the value box's value """ loc_showcase: Locator """ - Locator for the value box showcase + `Locator` for the value box showcase """ loc_title: Locator """ - Locator for the value box title + `Locator` for the value box title """ loc_body: Locator """ - Locator for the value box body + `Locator` for the value box body """ def __init__(self, page: Page, id: str) -> None: @@ -2907,15 +2907,6 @@ class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithCon `Locator` for the card body """ - # *args: TagChild | TagAttrs | CardItem, - # full_screen: bool = False, - # height: CssUnit | None = None, - # max_height: CssUnit | None = None, - # min_height: CssUnit | None = None, - # fill: bool = True, - # class_: str | None = None, - # wrapper: WrapperCallable | MISSING_TYPE | None = MISSING, - # **kwargs: TagAttrValue def __init__(self, page: Page, id: str) -> None: """ Initializes a new instance of the Card class. @@ -2949,7 +2940,7 @@ def __init__(self, page: Page, id: str) -> None: def expect_header( self, - text: PatternOrStr, + text: PatternOrStr | None, *, timeout: Timeout = None, ) -> None: @@ -2959,14 +2950,15 @@ def expect_header( Parameters ---------- text - The expected text pattern or string. + The expected text pattern or string + Note: None if the header is expected to not exist. timeout The maximum time to wait for the expectation to pass. Defaults to None. """ - playwright_expect(self.loc_title).to_have_text( - text, - timeout=timeout, - ) + if text is None: + playwright_expect(self.loc_title).to_have_count(0, timeout=timeout) + else: + playwright_expect(self.loc_title).to_have_text(text, timeout=timeout) # def expect_body( # self, @@ -2981,6 +2973,28 @@ def expect_header( # timeout=timeout, # ) + def expect_footer( + self, + text: PatternOrStr | None, + *, + timeout: Timeout = None, + ) -> None: + """ + Expects the card footer to have a specific text. + + Parameters + ---------- + text + The expected text pattern or string + Note: None if the footer is expected to not exist. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ + if text is None: + playwright_expect(self.loc_footer).to_have_count(0, timeout=timeout) + else: + playwright_expect(self.loc_footer).to_have_text(text, timeout=timeout) + def expect_max_height(self, value: StyleValue, *, timeout: Timeout = None) -> None: """ Expects the card to have a specific maximum height. @@ -3020,7 +3034,7 @@ def expect_height(self, value: StyleValue, *, timeout: Timeout = None) -> None: """ expect_to_have_style(self.loc_container, "height", value, timeout=timeout) - def expect_full_screen_available( + def expect_full_screen_enabled( self, available: bool, *, timeout: Timeout = None ) -> None: """ @@ -3037,35 +3051,6 @@ def expect_full_screen_available( int(available), timeout=timeout ) - def expect_header_exists(self, exists: bool, *, timeout: Timeout = None) -> None: - """ - Expects the card header to exist or not. - - Parameters - ---------- - exists - True if the card header is expected to exist, False otherwise. - timeout - The maximum time to wait for the expectation to pass. Defaults to None. - """ - playwright_expect(self.loc_title).to_have_count(int(exists), timeout=timeout) - - def expect_footer_exists(self, exists: bool, *, timeout: Timeout = None) -> None: - """ - Expects the card footer to exist or not. - - Parameters - ---------- - exists - True if the card footer is expected to exist, False otherwise. - timeout - The maximum time to wait for the expectation to pass. Defaults to None. - """ - playwright_expect(self.loc_footer).to_have_count(int(exists), timeout=timeout) - - -# Experimental below - class Accordion( _WidthLocM, diff --git a/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py b/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py index 469573689..1feb6f3aa 100644 --- a/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py +++ b/tests/playwright/deploys/shiny-client-console-error/test_shiny_client_error.py @@ -1,4 +1,4 @@ -from playwright.sync_api import Page +from playwright.sync_api import Page, expect from utils.deploy_utils import create_deploys_app_url_fixture, skip_if_not_chrome app_url = create_deploys_app_url_fixture("shiny_client_console_error") @@ -9,15 +9,19 @@ def test_shiny_client_console_error(page: Page, app_url: str) -> None: page.goto(app_url) assert page.locator("#same_id").count() == 2 - shiny_error_message = page.query_selector("shiny-error-message") + shiny_error_message = page.locator("shiny-error-message") # show the client error message only for local apps if "127.0.0.1" in app_url: expect(shiny_error_message).not_to_have_count(0) - expect(shiny_error_message).to_have_attribute("message", "'The following ID was repeated:\n- "same_id": 2 inputs'") + expect(shiny_error_message).to_have_attribute( + "message", 'The following ID was repeated:\n- "same_id": 2 inputs' + ) expect(page.get_by_role("button", name="Dismiss all")).to_have_count(1) - expect(page.get_by_role("button", name="Copy error to clipboard")).to_have_count(1) + expect( + page.get_by_role("button", name="Copy error to clipboard") + ).to_have_count(1) # for deployed apps to shinyapps.io or connect hide the client error message else: diff --git a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py index 6b8a2952f..f0ec93315 100644 --- a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py +++ b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py @@ -43,21 +43,20 @@ def test_card_kitchensink(page: Page, local_app: ShinyAppProc) -> None: card.expect_max_height(None) card.expect_min_height(None) card.expect_height(None) - card.expect_header_exists(False) - card.expect_footer_exists(False) + card.expect_header(None) + card.expect_footer(None) card.expect_body( ["\nThis is the body without a header of a footer - No Fullscreen\n"] ) assert get_body_tag_name(card) == "p" card.expect_full_screen(False) - card.expect_full_screen_available(False) + card.expect_full_screen_enabled(False) card = Card(page, "card3") card.expect_max_height("500px") card.expect_min_height("200px") card.expect_header("Fill is False. Fullscreen is False") - card.expect_header_exists(True) - card.expect_footer_exists(False) + card.expect_footer(None) card.expect_body(["Max height and min height are set."]) assert get_body_tag_name(card) == "h3" - card.expect_full_screen_available(False) + card.expect_full_screen_enabled(False) From a48181a3c7e9f27b06dda925565441c178ce19a5 Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Thu, 4 Apr 2024 08:43:57 -0700 Subject: [PATCH 7/9] Fix indentation --- tests/playwright/controls.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/playwright/controls.py b/tests/playwright/controls.py index dcf8934b1..c291196e3 100644 --- a/tests/playwright/controls.py +++ b/tests/playwright/controls.py @@ -393,11 +393,11 @@ def expect_width( Parameters ---------- - value - The expected value of the width attribute. - timeout - The maximum time to wait for the expectation to be fulfilled. - Defaults to None. + value + The expected value of the width attribute. + timeout + The maximum time to wait for the expectation to be fulfilled. + Defaults to None. """ expect_attr(self.loc_container, "width", value=value, timeout=timeout) From f9a61bea6eb7ad1a8c453a3effb3d0f78c6ab8ee Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Thu, 4 Apr 2024 09:21:52 -0700 Subject: [PATCH 8/9] reduce duplication of methods to check full screen functionality --- tests/playwright/controls.py | 53 +++++++------------ .../components/card-input/test_card-input.py | 12 ++--- .../value_box/kitchensink/test_valuebox_ks.py | 16 +++--- .../value_box/smoke/test_valuebox.py | 6 +-- .../card/kitchensink/test_card_ks.py | 8 +-- .../shiny/experimental/card/test_card.py | 6 +-- 6 files changed, 42 insertions(+), 59 deletions(-) diff --git a/tests/playwright/controls.py b/tests/playwright/controls.py index c291196e3..a75449868 100644 --- a/tests/playwright/controls.py +++ b/tests/playwright/controls.py @@ -2708,7 +2708,7 @@ def close_full_screen( """ self._loc_close_button.click(timeout=timeout) - def expect_full_screen( + def expect_full_screen_open( self: _CardFullScreenLayoutP, open: bool, *, timeout: Timeout = None ) -> None: """ @@ -2725,6 +2725,23 @@ def expect_full_screen( int(open), timeout=timeout ) + def expect_full_screen_enabled( + self: _CardFullScreenLayoutP, available: bool, *, timeout: Timeout = None + ) -> None: + """ + Expects the card to be available for full screen mode. + + Parameters + ---------- + available + True if the value box is expected to be available for full screen mode, False otherwise. + timeout + The maximum time to wait for the expectation to pass. Defaults to None. + """ + playwright_expect(self._loc_fullscreen).to_have_count( + int(available), timeout=timeout + ) + class ValueBox( _WidthLocM, @@ -2867,23 +2884,6 @@ def expect_body( timeout=timeout, ) - def expect_full_screen_available( - self, available: bool, *, timeout: Timeout = None - ) -> None: - """ - Expects the value box to be available for full screen mode. - - Parameters - ---------- - available - True if the value box is expected to be available for full screen mode, False otherwise. - timeout - The maximum time to wait for the expectation to pass. Defaults to None. - """ - playwright_expect(self._loc_fullscreen).to_have_count( - int(available), timeout=timeout - ) - class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithContainer): """ @@ -3034,23 +3034,6 @@ def expect_height(self, value: StyleValue, *, timeout: Timeout = None) -> None: """ expect_to_have_style(self.loc_container, "height", value, timeout=timeout) - def expect_full_screen_enabled( - self, available: bool, *, timeout: Timeout = None - ) -> None: - """ - Expects the card to be available for full screen mode. - - Parameters - ---------- - available - True if the value box is expected to be available for full screen mode, False otherwise. - timeout - The maximum time to wait for the expectation to pass. Defaults to None. - """ - playwright_expect(self._loc_fullscreen).to_have_count( - int(available), timeout=timeout - ) - class Accordion( _WidthLocM, diff --git a/tests/playwright/shiny/components/card-input/test_card-input.py b/tests/playwright/shiny/components/card-input/test_card-input.py index 7237ff9f1..1cc794aff 100644 --- a/tests/playwright/shiny/components/card-input/test_card-input.py +++ b/tests/playwright/shiny/components/card-input/test_card-input.py @@ -24,25 +24,25 @@ def test_card_input(page: Page, app_path: str, sel_card: str, sel_vb: str) -> No out_vb = OutputCode(page, "out_value_box") # Open and close card full screen, check input value ------ - card.expect_full_screen(False) + card.expect_full_screen_open(False) out_card.expect_value("False") card.open_full_screen() - card.expect_full_screen(True) + card.expect_full_screen_open(True) out_card.expect_value("True") card.close_full_screen() - card.expect_full_screen(False) + card.expect_full_screen_open(False) out_card.expect_value("False") # Open and close value box full screen, check input value ------ - vb.expect_full_screen(False) + vb.expect_full_screen_open(False) out_vb.expect_value("False") vb.open_full_screen() - vb.expect_full_screen(True) + vb.expect_full_screen_open(True) out_vb.expect_value("True") vb.close_full_screen() - vb.expect_full_screen(False) + vb.expect_full_screen_open(False) out_vb.expect_value("False") diff --git a/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py b/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py index 9f0b759da..652aec307 100644 --- a/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py +++ b/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py @@ -57,13 +57,13 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: assert get_value_tag_name(value_box1) == "h1" assert get_value_box_bg_color(value_box1) == "rgb(193, 0, 0)" assert get_value_box_fg_color(value_box1) == "rgb(255, 255, 255)" - value_box1.expect_full_screen_available(True) - value_box1.expect_full_screen(False) + value_box1.expect_full_screen_enabled(True) + value_box1.expect_full_screen_open(False) value_box1.open_full_screen() - value_box1.expect_full_screen(True) + value_box1.expect_full_screen_open(True) value_box1.expect_body(["Inside the fullscreen"]) value_box1.close_full_screen() - value_box1.expect_full_screen(False) + value_box1.expect_full_screen_open(False) value_box2 = ValueBox(page, "valuebox2") value_box2.expect_height(None) @@ -74,7 +74,7 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box2.expect_value("Showcase left center") assert get_value_tag_name(value_box2) == "h5" assert get_value_box_bg_color(value_box2) == "rgb(0, 123, 194)" - value_box2.expect_full_screen_available(False) + value_box2.expect_full_screen_enabled(False) value_box3 = ValueBox(page, "valuebox3") value_box3.expect_height(None) @@ -84,7 +84,7 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box3.expect_title("No theme w/ Fullscreen") value_box3.expect_value("Showcase bottom") assert get_value_tag_name(value_box3) == "h3" - value_box3.expect_full_screen_available(True) + value_box3.expect_full_screen_enabled(True) assert get_value_box_bg_color(value_box3) == "rgb(255, 255, 255)" value_box4 = ValueBox(page, "valuebox4") @@ -93,7 +93,7 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box4.expect_value("No theme - only defaults") assert get_title_tag_name(value_box4) == "p" assert get_title_tag_name(value_box4) == "p" - value_box4.expect_full_screen_available(False) + value_box4.expect_full_screen_enabled(False) assert get_value_box_bg_color(value_box4) == "rgb(255, 255, 255)" value_box5 = ValueBox(page, "valuebox5") @@ -102,6 +102,6 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box5.expect_title("No showcase w/ showcase layout") value_box5.expect_value("Red text - fill is False") assert get_value_tag_name(value_box5) == "p" - value_box5.expect_full_screen_available(False) + value_box5.expect_full_screen_enabled(False) assert get_value_box_bg_color(value_box5) == "rgb(255, 255, 255)" assert get_value_box_fg_color(value_box5) == "rgb(193, 0, 0)" diff --git a/tests/playwright/shiny/components/value_box/smoke/test_valuebox.py b/tests/playwright/shiny/components/value_box/smoke/test_valuebox.py index d9bf7129b..0458f1c87 100644 --- a/tests/playwright/shiny/components/value_box/smoke/test_valuebox.py +++ b/tests/playwright/shiny/components/value_box/smoke/test_valuebox.py @@ -9,9 +9,9 @@ def test_valuebox(page: Page, local_app: ShinyAppProc, value_box_id: str) -> Non page.goto(local_app.url) value_box = ValueBox(page, value_box_id) - value_box.expect_full_screen(False) + value_box.expect_full_screen_open(False) value_box.open_full_screen() - value_box.expect_full_screen(True) + value_box.expect_full_screen_open(True) if value_box_id == "valuebox1": value_box.expect_height(None) value_box.expect_title("KPI Title") @@ -29,4 +29,4 @@ def test_valuebox(page: Page, local_app: ShinyAppProc, value_box_id: str) -> Non ) assert title_tag_name == "p" value_box.close_full_screen() - value_box.expect_full_screen(False) + value_box.expect_full_screen_open(False) diff --git a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py index f0ec93315..b6eb9a461 100644 --- a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py +++ b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py @@ -33,11 +33,11 @@ def test_card_kitchensink(page: Page, local_app: ShinyAppProc) -> None: "\nThis is the body of a card with default height w/ fullscreen", ] ) - card.expect_full_screen(False) + card.expect_full_screen_open(False) card.open_full_screen() - card.expect_full_screen(True) + card.expect_full_screen_open(True) card.close_full_screen() - card.expect_full_screen(False) + card.expect_full_screen_open(False) card = Card(page, "card2") card.expect_max_height(None) @@ -49,7 +49,7 @@ def test_card_kitchensink(page: Page, local_app: ShinyAppProc) -> None: ["\nThis is the body without a header of a footer - No Fullscreen\n"] ) assert get_body_tag_name(card) == "p" - card.expect_full_screen(False) + card.expect_full_screen_open(False) card.expect_full_screen_enabled(False) card = Card(page, "card3") diff --git a/tests/playwright/shiny/experimental/card/test_card.py b/tests/playwright/shiny/experimental/card/test_card.py index a86bed4fa..6c49f4e0b 100644 --- a/tests/playwright/shiny/experimental/card/test_card.py +++ b/tests/playwright/shiny/experimental/card/test_card.py @@ -19,8 +19,8 @@ def test_card(page: Page, local_app: ShinyAppProc) -> None: "\nThis is still the body.\n", ] ) - card.expect_full_screen(False) + card.expect_full_screen_open(False) card.open_full_screen() - card.expect_full_screen(True) + card.expect_full_screen_open(True) card.close_full_screen() - card.expect_full_screen(False) + card.expect_full_screen_open(False) From 0b09979ed95e12e624850a7d201edd942ca3618a Mon Sep 17 00:00:00 2001 From: Karan Gathani Date: Thu, 4 Apr 2024 11:37:43 -0700 Subject: [PATCH 9/9] change the name of methd --- tests/playwright/controls.py | 2 +- .../value_box/kitchensink/test_valuebox_ks.py | 10 +++++----- .../experimental/card/kitchensink/test_card_ks.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/playwright/controls.py b/tests/playwright/controls.py index a75449868..986fc460f 100644 --- a/tests/playwright/controls.py +++ b/tests/playwright/controls.py @@ -2725,7 +2725,7 @@ def expect_full_screen_open( int(open), timeout=timeout ) - def expect_full_screen_enabled( + def expect_full_screen_available( self: _CardFullScreenLayoutP, available: bool, *, timeout: Timeout = None ) -> None: """ diff --git a/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py b/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py index 652aec307..776571cdf 100644 --- a/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py +++ b/tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py @@ -57,7 +57,7 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: assert get_value_tag_name(value_box1) == "h1" assert get_value_box_bg_color(value_box1) == "rgb(193, 0, 0)" assert get_value_box_fg_color(value_box1) == "rgb(255, 255, 255)" - value_box1.expect_full_screen_enabled(True) + value_box1.expect_full_screen_available(True) value_box1.expect_full_screen_open(False) value_box1.open_full_screen() value_box1.expect_full_screen_open(True) @@ -74,7 +74,7 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box2.expect_value("Showcase left center") assert get_value_tag_name(value_box2) == "h5" assert get_value_box_bg_color(value_box2) == "rgb(0, 123, 194)" - value_box2.expect_full_screen_enabled(False) + value_box2.expect_full_screen_available(False) value_box3 = ValueBox(page, "valuebox3") value_box3.expect_height(None) @@ -84,7 +84,7 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box3.expect_title("No theme w/ Fullscreen") value_box3.expect_value("Showcase bottom") assert get_value_tag_name(value_box3) == "h3" - value_box3.expect_full_screen_enabled(True) + value_box3.expect_full_screen_available(True) assert get_value_box_bg_color(value_box3) == "rgb(255, 255, 255)" value_box4 = ValueBox(page, "valuebox4") @@ -93,7 +93,7 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box4.expect_value("No theme - only defaults") assert get_title_tag_name(value_box4) == "p" assert get_title_tag_name(value_box4) == "p" - value_box4.expect_full_screen_enabled(False) + value_box4.expect_full_screen_available(False) assert get_value_box_bg_color(value_box4) == "rgb(255, 255, 255)" value_box5 = ValueBox(page, "valuebox5") @@ -102,6 +102,6 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None: value_box5.expect_title("No showcase w/ showcase layout") value_box5.expect_value("Red text - fill is False") assert get_value_tag_name(value_box5) == "p" - value_box5.expect_full_screen_enabled(False) + value_box5.expect_full_screen_available(False) assert get_value_box_bg_color(value_box5) == "rgb(255, 255, 255)" assert get_value_box_fg_color(value_box5) == "rgb(193, 0, 0)" diff --git a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py index b6eb9a461..a11130dca 100644 --- a/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py +++ b/tests/playwright/shiny/experimental/card/kitchensink/test_card_ks.py @@ -50,7 +50,7 @@ def test_card_kitchensink(page: Page, local_app: ShinyAppProc) -> None: ) assert get_body_tag_name(card) == "p" card.expect_full_screen_open(False) - card.expect_full_screen_enabled(False) + card.expect_full_screen_available(False) card = Card(page, "card3") card.expect_max_height("500px") @@ -59,4 +59,4 @@ def test_card_kitchensink(page: Page, local_app: ShinyAppProc) -> None: card.expect_footer(None) card.expect_body(["Max height and min height are set."]) assert get_body_tag_name(card) == "h3" - card.expect_full_screen_enabled(False) + card.expect_full_screen_available(False)