Skip to content

Commit 791f772

Browse files
test: Add tests for client error console and card kitchensink (#1262)
Co-authored-by: Barret Schloerke <[email protected]>
1 parent 05fd6b3 commit 791f772

File tree

11 files changed

+308
-53
lines changed

11 files changed

+308
-53
lines changed

tests/playwright/controls.py

Lines changed: 152 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -351,22 +351,54 @@ def expect_label(
351351

352352

353353
class _WidthLocM:
354+
"""
355+
A mixin class representing the `loc`'s width.
356+
This class provides methods to expect the width attribute of an element.
357+
"""
358+
354359
def expect_width(
355360
self: _InputBaseP,
356361
value: AttrValue,
357362
*,
358363
timeout: Timeout = None,
359364
) -> None:
365+
"""
366+
Expect the width attribute of an element to have a specific value.
367+
368+
Parameters
369+
----------
370+
value
371+
The expected value of the width attribute.
372+
timeout
373+
The maximum time to wait for the expectation to be fulfilled.
374+
Defaults to None.
375+
"""
360376
expect_attr(self.loc, "width", value=value, timeout=timeout)
361377

362378

363379
class _WidthContainerM:
380+
"""
381+
A mixin class representing the container's width.
382+
This class provides methods to expect the width attribute of an element's container.
383+
"""
384+
364385
def expect_width(
365386
self: _InputWithContainerP,
366387
value: AttrValue,
367388
*,
368389
timeout: Timeout = None,
369390
) -> None:
391+
"""
392+
Expect the width attribute of an element's container to have a specific value.
393+
394+
Parameters
395+
----------
396+
value
397+
The expected value of the width attribute.
398+
timeout
399+
The maximum time to wait for the expectation to be fulfilled.
400+
Defaults to None.
401+
"""
370402
expect_attr(self.loc_container, "width", value=value, timeout=timeout)
371403

372404

@@ -2676,7 +2708,7 @@ def close_full_screen(
26762708
"""
26772709
self._loc_close_button.click(timeout=timeout)
26782710

2679-
def expect_full_screen(
2711+
def expect_full_screen_open(
26802712
self: _CardFullScreenLayoutP, open: bool, *, timeout: Timeout = None
26812713
) -> None:
26822714
"""
@@ -2693,31 +2725,48 @@ def expect_full_screen(
26932725
int(open), timeout=timeout
26942726
)
26952727

2728+
def expect_full_screen_available(
2729+
self: _CardFullScreenLayoutP, available: bool, *, timeout: Timeout = None
2730+
) -> None:
2731+
"""
2732+
Expects the card to be available for full screen mode.
2733+
2734+
Parameters
2735+
----------
2736+
available
2737+
True if the value box is expected to be available for full screen mode, False otherwise.
2738+
timeout
2739+
The maximum time to wait for the expectation to pass. Defaults to None.
2740+
"""
2741+
playwright_expect(self._loc_fullscreen).to_have_count(
2742+
int(available), timeout=timeout
2743+
)
2744+
26962745

26972746
class ValueBox(
26982747
_WidthLocM,
26992748
_CardFullScreenM,
27002749
_InputWithContainer,
27012750
):
27022751
"""
2703-
ValueBox control for shiny.ui.value_box - https://shiny.posit.co/py/api/core/ui.value_box.html
2752+
ValueBox control for :func:`~shiny.ui.value_box`
27042753
"""
27052754

27062755
loc: Locator
27072756
"""
2708-
Locator for the value box's value
2757+
`Locator` for the value box's value
27092758
"""
27102759
loc_showcase: Locator
27112760
"""
2712-
Locator for the value box showcase
2761+
`Locator` for the value box showcase
27132762
"""
27142763
loc_title: Locator
27152764
"""
2716-
Locator for the value box title
2765+
`Locator` for the value box title
27172766
"""
27182767
loc_body: Locator
27192768
"""
2720-
Locator for the value box body
2769+
`Locator` for the value box body
27212770
"""
27222771

27232772
def __init__(self, page: Page, id: str) -> None:
@@ -2835,35 +2884,40 @@ def expect_body(
28352884
timeout=timeout,
28362885
)
28372886

2838-
def expect_full_screen_available(
2839-
self, available: bool, *, timeout: Timeout = None
2840-
) -> None:
2887+
2888+
class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithContainer):
2889+
"""
2890+
Card control for :func:`~shiny.ui.card`
2891+
"""
2892+
2893+
loc: Locator
2894+
"""
2895+
`Locator` for the card's value
2896+
"""
2897+
loc_title: Locator
2898+
"""
2899+
`Locator` for the card title
2900+
"""
2901+
loc_footer: Locator
2902+
"""
2903+
`Locator` for the card footer
2904+
"""
2905+
loc_body: Locator
2906+
"""
2907+
`Locator` for the card body
2908+
"""
2909+
2910+
def __init__(self, page: Page, id: str) -> None:
28412911
"""
2842-
Expects the value box to be available for full screen mode.
2912+
Initializes a new instance of the Card class.
28432913
28442914
Parameters
28452915
----------
2846-
available
2847-
True if the value box is expected to be available for full screen mode, False otherwise.
2848-
timeout
2849-
The maximum time to wait for the expectation to pass. Defaults to None.
2916+
page
2917+
The Playwright page object.
2918+
id
2919+
The ID of the card.
28502920
"""
2851-
playwright_expect(self._loc_fullscreen).to_have_count(
2852-
int(available), timeout=timeout
2853-
)
2854-
2855-
2856-
class Card(_WidthLocM, _CardFooterM, _CardBodyM, _CardFullScreenM, _InputWithContainer):
2857-
# *args: TagChild | TagAttrs | CardItem,
2858-
# full_screen: bool = False,
2859-
# height: CssUnit | None = None,
2860-
# max_height: CssUnit | None = None,
2861-
# min_height: CssUnit | None = None,
2862-
# fill: bool = True,
2863-
# class_: str | None = None,
2864-
# wrapper: WrapperCallable | MISSING_TYPE | None = MISSING,
2865-
# **kwargs: TagAttrValue
2866-
def __init__(self, page: Page, id: str) -> None:
28672921
super().__init__(
28682922
page,
28692923
id=id,
@@ -2886,14 +2940,25 @@ def __init__(self, page: Page, id: str) -> None:
28862940

28872941
def expect_header(
28882942
self,
2889-
text: PatternOrStr,
2943+
text: PatternOrStr | None,
28902944
*,
28912945
timeout: Timeout = None,
28922946
) -> None:
2893-
playwright_expect(self.loc_title).to_have_text(
2894-
text,
2895-
timeout=timeout,
2896-
)
2947+
"""
2948+
Expects the card header to have a specific text.
2949+
2950+
Parameters
2951+
----------
2952+
text
2953+
The expected text pattern or string
2954+
Note: None if the header is expected to not exist.
2955+
timeout
2956+
The maximum time to wait for the expectation to pass. Defaults to None.
2957+
"""
2958+
if text is None:
2959+
playwright_expect(self.loc_title).to_have_count(0, timeout=timeout)
2960+
else:
2961+
playwright_expect(self.loc_title).to_have_text(text, timeout=timeout)
28972962

28982963
# def expect_body(
28992964
# self,
@@ -2908,17 +2973,66 @@ def expect_header(
29082973
# timeout=timeout,
29092974
# )
29102975

2976+
def expect_footer(
2977+
self,
2978+
text: PatternOrStr | None,
2979+
*,
2980+
timeout: Timeout = None,
2981+
) -> None:
2982+
"""
2983+
Expects the card footer to have a specific text.
2984+
2985+
Parameters
2986+
----------
2987+
text
2988+
The expected text pattern or string
2989+
Note: None if the footer is expected to not exist.
2990+
timeout
2991+
The maximum time to wait for the expectation to pass. Defaults to None.
2992+
"""
2993+
if text is None:
2994+
playwright_expect(self.loc_footer).to_have_count(0, timeout=timeout)
2995+
else:
2996+
playwright_expect(self.loc_footer).to_have_text(text, timeout=timeout)
2997+
29112998
def expect_max_height(self, value: StyleValue, *, timeout: Timeout = None) -> None:
2999+
"""
3000+
Expects the card to have a specific maximum height.
3001+
3002+
Parameters
3003+
----------
3004+
value
3005+
The expected maximum height value.
3006+
timeout
3007+
The maximum time to wait for the expectation to pass. Defaults to None.
3008+
"""
29123009
expect_to_have_style(self.loc_container, "max-height", value, timeout=timeout)
29133010

29143011
def expect_min_height(self, value: StyleValue, *, timeout: Timeout = None) -> None:
3012+
"""
3013+
Expects the card to have a specific minimum height.
3014+
3015+
Parameters
3016+
----------
3017+
value
3018+
The expected minimum height value.
3019+
timeout
3020+
The maximum time to wait for the expectation to pass. Defaults to None.
3021+
"""
29153022
expect_to_have_style(self.loc_container, "min-height", value, timeout=timeout)
29163023

29173024
def expect_height(self, value: StyleValue, *, timeout: Timeout = None) -> None:
2918-
expect_to_have_style(self.loc_container, "height", value, timeout=timeout)
2919-
3025+
"""
3026+
Expects the card to have a specific height.
29203027
2921-
# Experimental below
3028+
Parameters
3029+
----------
3030+
value
3031+
The expected height value.
3032+
timeout
3033+
The maximum time to wait for the expectation to pass. Defaults to None.
3034+
"""
3035+
expect_to_have_style(self.loc_container, "height", value, timeout=timeout)
29223036

29233037

29243038
class Accordion(
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from shiny import reactive, render
2+
from shiny.express import input, ui
3+
4+
ui.input_action_button("same_id", "Action")
5+
ui.input_action_button("same_id", "Action")
6+
7+
8+
@render.text()
9+
@reactive.event(input.same_id)
10+
def counter():
11+
return f"{input.same_id()}"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
git+https://github.com/posit-dev/py-htmltools.git#egg=htmltools
2+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"https://api.shinyapps.io": {
3+
"server_url": "https://api.shinyapps.io",
4+
"app_url": "https://testing-apps.shinyapps.io/shiny_client_console_error/",
5+
"app_id": 11634266,
6+
"app_guid": null,
7+
"title": "shiny_client_console_error",
8+
"app_mode": "python-shiny",
9+
"app_store_version": 1
10+
}
11+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from playwright.sync_api import Page, expect
2+
from utils.deploy_utils import create_deploys_app_url_fixture, skip_if_not_chrome
3+
4+
app_url = create_deploys_app_url_fixture("shiny_client_console_error")
5+
6+
7+
@skip_if_not_chrome
8+
def test_shiny_client_console_error(page: Page, app_url: str) -> None:
9+
page.goto(app_url)
10+
11+
assert page.locator("#same_id").count() == 2
12+
shiny_error_message = page.locator("shiny-error-message")
13+
14+
# show the client error message only for local apps
15+
if "127.0.0.1" in app_url:
16+
17+
expect(shiny_error_message).not_to_have_count(0)
18+
expect(shiny_error_message).to_have_attribute(
19+
"message", 'The following ID was repeated:\n- "same_id": 2 inputs'
20+
)
21+
expect(page.get_by_role("button", name="Dismiss all")).to_have_count(1)
22+
expect(
23+
page.get_by_role("button", name="Copy error to clipboard")
24+
).to_have_count(1)
25+
26+
# for deployed apps to shinyapps.io or connect hide the client error message
27+
else:
28+
expect(shiny_error_message).to_have_count(0)

tests/playwright/shiny/components/card-input/test_card-input.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,25 @@ def test_card_input(page: Page, app_path: str, sel_card: str, sel_vb: str) -> No
2424
out_vb = OutputCode(page, "out_value_box")
2525

2626
# Open and close card full screen, check input value ------
27-
card.expect_full_screen(False)
27+
card.expect_full_screen_open(False)
2828
out_card.expect_value("False")
2929

3030
card.open_full_screen()
31-
card.expect_full_screen(True)
31+
card.expect_full_screen_open(True)
3232
out_card.expect_value("True")
3333

3434
card.close_full_screen()
35-
card.expect_full_screen(False)
35+
card.expect_full_screen_open(False)
3636
out_card.expect_value("False")
3737

3838
# Open and close value box full screen, check input value ------
39-
vb.expect_full_screen(False)
39+
vb.expect_full_screen_open(False)
4040
out_vb.expect_value("False")
4141

4242
vb.open_full_screen()
43-
vb.expect_full_screen(True)
43+
vb.expect_full_screen_open(True)
4444
out_vb.expect_value("True")
4545

4646
vb.close_full_screen()
47-
vb.expect_full_screen(False)
47+
vb.expect_full_screen_open(False)
4848
out_vb.expect_value("False")

tests/playwright/shiny/components/value_box/kitchensink/test_valuebox_ks.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ def test_valuebox(page: Page, local_app: ShinyAppProc) -> None:
5858
assert get_value_box_bg_color(value_box1) == "rgb(193, 0, 0)"
5959
assert get_value_box_fg_color(value_box1) == "rgb(255, 255, 255)"
6060
value_box1.expect_full_screen_available(True)
61-
value_box1.expect_full_screen(False)
61+
value_box1.expect_full_screen_open(False)
6262
value_box1.open_full_screen()
63-
value_box1.expect_full_screen(True)
63+
value_box1.expect_full_screen_open(True)
6464
value_box1.expect_body(["Inside the fullscreen"])
6565
value_box1.close_full_screen()
66-
value_box1.expect_full_screen(False)
66+
value_box1.expect_full_screen_open(False)
6767

6868
value_box2 = ValueBox(page, "valuebox2")
6969
value_box2.expect_height(None)

0 commit comments

Comments
 (0)