Skip to content

Commit c59ca9c

Browse files
committed
add bookmark tests for sidebar, accordion, navset
1 parent d8c91ed commit c59ca9c

File tree

7 files changed

+161
-33
lines changed

7 files changed

+161
-33
lines changed

shiny/bookmark/_restore_state.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,11 +391,11 @@ def get_current_restore_context() -> RestoreContext | None:
391391

392392

393393
@overload
394-
def restore_input(resolved_id: ResolvedId, default: Any) -> Any: ...
394+
def restore_input(resolved_id: ResolvedId, default: Optional[Any] = None) -> Any: ...
395395
@overload
396396
def restore_input(resolved_id: None, default: T) -> T: ...
397397
@add_example()
398-
def restore_input(resolved_id: ResolvedId | None, default: Any) -> Any:
398+
def restore_input(resolved_id: ResolvedId | None, default: Optional[Any] = None) -> Any:
399399
"""
400400
Restore an input value
401401

shiny/ui/_accordion.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,22 @@ def accordion(
245245
"All `accordion(*args)` must be of type `AccordionPanel` which can be created using `accordion_panel()`"
246246
)
247247

248+
# Since multiple=False requires an id, we always include one,
249+
# but only create a binding when it is provided
250+
binding_class_value: TagAttrs | None = None
251+
if id is None:
252+
id = private_random_id("bslib_accordion")
253+
binding_class_value = None
254+
else:
255+
binding_class_value = {"class": "bslib-accordion-input"}
256+
257+
accordion_id = resolve_id_or_none(id)
258+
has_restored_input = not isinstance(
259+
restore_input(accordion_id, MISSING), MISSING_TYPE
260+
)
261+
open = restore_input(accordion_id, open)
262+
print(f"restored open: {restore_input(accordion_id, MISSING)}")
263+
248264
is_open: list[bool] = []
249265
if open is None:
250266
is_open = [False for _ in panels]
@@ -256,27 +272,18 @@ def accordion(
256272
#
257273
is_open = [panel._data_value in open for panel in panels]
258274

259-
# Open the first panel by default
260-
if open is not False and len(is_open) > 0 and not any(is_open):
261-
is_open[0] = True
275+
if not has_restored_input:
276+
# Open the first panel by default
277+
if open is not False and len(is_open) > 0 and not any(is_open):
278+
is_open[0] = True
262279

263280
if (not multiple) and sum(is_open) > 1:
264281
raise ValueError("Can't select more than one panel when `multiple = False`")
265282

266-
# Since multiple=False requires an id, we always include one,
267-
# but only create a binding when it is provided
268-
binding_class_value: TagAttrs | None = None
269-
if id is None:
270-
id = private_random_id("bslib_accordion")
271-
binding_class_value = None
272-
else:
273-
binding_class_value = {"class": "bslib-accordion-input"}
274-
275-
accordion_id = resolve_id_or_none(id)
276-
for panel, open in zip(panels, is_open):
283+
for panel, panel_is_open in zip(panels, is_open):
277284
panel._accordion_id = accordion_id
278285
panel._is_multiple = multiple
279-
panel._is_open = restore_input(accordion_id, open)
286+
panel._is_open = panel_is_open
280287

281288
panel_tags = [panel.resolve() for panel in panels]
282289

shiny/ui/_sidebar.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,12 +549,17 @@ def sidebar(
549549

550550
resolved_id = resolve_id_or_none(id)
551551

552+
if resolved_id:
553+
restored_open: bool | None = restore_input(resolved_id)
554+
if restored_open is not None:
555+
open = "open" if restored_open else "closed"
556+
552557
return Sidebar(
553558
children=children,
554559
attrs=attrs,
555560
width=width,
556561
position=position,
557-
open=restore_input(resolved_id, open),
562+
open=open,
558563
id=resolved_id,
559564
title=title,
560565
fg=fg,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from playwright.sync_api import Page
2+
3+
from shiny.playwright import controller
4+
from shiny.pytest import create_app_fixture
5+
from shiny.run import ShinyAppProc
6+
7+
app = create_app_fixture(["app-express.py"])
8+
9+
10+
def test_accordion_bookmarking_demo(page: Page, app: ShinyAppProc) -> None:
11+
page.goto(app.url)
12+
13+
# Test accordion bookmarking
14+
acc_single = controller.Accordion(page, "acc_single")
15+
acc_single.expect_open(["Section A"])
16+
acc_single.set(["Section B"])
17+
18+
acc_mod = controller.Accordion(page, "first-acc_mod")
19+
acc_mod.expect_open(["Section A"])
20+
acc_mod.set(["Section C"])
21+
22+
# click bookmark button
23+
bookmark_button = controller.InputBookmarkButton(page)
24+
bookmark_button.click()
25+
26+
# reload page
27+
page.reload()
28+
29+
acc_single.expect_open(["Section B"])
30+
acc_mod.expect_open(["Section C"])
31+
32+
acc_single.set([])
33+
acc_mod.set([])
34+
35+
bookmark_button.click()
36+
37+
# reload page
38+
page.reload()
39+
40+
acc_single.expect_open([])
41+
acc_mod.expect_open([])

tests/playwright/ai_generated_apps/bookmark/navsets/app-express.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from typing import Any, Dict
22

3-
from shiny.express import expressify, module, session, ui
3+
from shiny.express import app_opts, expressify, module, session, ui
44

5-
ui.page_opts(
6-
title="Navsets kitchensink App", id="navsets_collection", bookmark_store="url"
7-
)
5+
app_opts(bookmark_store="url")
6+
7+
ui.page_opts(title="Navsets kitchensink App", id="navsets_collection")
88

99

1010
navset_configs: Dict[str, Dict[str, Dict[str, Any]]] = {
@@ -39,19 +39,10 @@ def create_navset(navset_type: str) -> None:
3939
for navset_id, params in navset_configs[navset_type].items():
4040
navset_kwargs = params.copy()
4141

42-
if "header" in navset_kwargs:
43-
header_content = navset_kwargs["header"]["content"]
44-
header_id = navset_kwargs["header"]["id"]
45-
navset_kwargs["header"] = ui.tags.div(header_content, id=f"{header_id}")
46-
47-
if "footer" in navset_kwargs:
48-
footer_content = navset_kwargs["footer"]["content"]
49-
footer_id = navset_kwargs["footer"]["id"]
50-
navset_kwargs["footer"] = ui.tags.div(footer_content, id=f"{footer_id}")
51-
5242
with navset_function(id=f"{navset_type}_{navset_id}", **navset_kwargs):
5343
for suffix in ["a", "b", "c"]:
54-
with ui.nav_panel(f"{navset_type}_{suffix}"):
44+
id = f"{navset_type}_{suffix}"
45+
with ui.nav_panel(id, value=id):
5546
ui.markdown(f"{navset_type}_{suffix} content")
5647

5748

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from playwright.sync_api import Page
2+
3+
from shiny.playwright import controller
4+
from shiny.pytest import create_app_fixture
5+
from shiny.run import ShinyAppProc
6+
7+
app = create_app_fixture(["app-express.py"])
8+
9+
10+
def test_navsets_bookmarking_demo(page: Page, app: ShinyAppProc) -> None:
11+
page.goto(app.url)
12+
13+
# Non-module navsets
14+
navset_collection = controller.NavsetTab(page, "navsets_collection")
15+
navset_collection.set("navset_underline")
16+
navset_underline = controller.NavsetUnderline(page, "navset_underline_default")
17+
navset_underline.set("navset_underline_c")
18+
navset_collection.set("navset_card_underline")
19+
navset_card_underline = controller.NavsetCardUnderline(
20+
page, "navset_card_underline_default"
21+
)
22+
navset_card_underline.set("navset_card_underline_c")
23+
24+
# module navsets
25+
mod_navset_collection = controller.NavsetTab(page, "first-navsets_collection")
26+
mod_navset_collection.set("navset_underline")
27+
mod_navset_underline = controller.NavsetUnderline(
28+
page, "first-navset_underline_default"
29+
)
30+
mod_navset_underline.set("navset_underline_c")
31+
mod_navset_collection.set("navset_card_underline")
32+
mod_navset_card_underline = controller.NavsetCardUnderline(
33+
page, "first-navset_card_underline_default"
34+
)
35+
mod_navset_card_underline.set("navset_card_underline_c")
36+
37+
# click bookmark button
38+
bookmark_button = controller.InputBookmarkButton(page)
39+
bookmark_button.click()
40+
41+
# reload page
42+
page.reload()
43+
44+
navset_card_underline.expect_value("navset_card_underline_c")
45+
navset_collection.expect_value("navset_card_underline")
46+
mod_navset_card_underline.expect_value("navset_card_underline_c")
47+
mod_navset_collection.expect_value("navset_card_underline")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from playwright.sync_api import Page
2+
3+
from shiny.playwright import controller
4+
from shiny.pytest import create_app_fixture
5+
from shiny.run import ShinyAppProc
6+
7+
app = create_app_fixture(["app-express.py"])
8+
9+
10+
def test_sidebar_bookmarking_demo(page: Page, app: ShinyAppProc) -> None:
11+
page.goto(app.url)
12+
13+
# Test sidebar bookmarking
14+
left_sidebar = controller.Sidebar(page, "sidebar_left")
15+
right_sidebar = controller.Sidebar(page, "first-sidebar_right")
16+
17+
left_sidebar.expect_open(True)
18+
right_sidebar.expect_open(True)
19+
20+
left_sidebar.set(False)
21+
right_sidebar.set(False)
22+
23+
left_sidebar.expect_open(False)
24+
right_sidebar.expect_open(False)
25+
26+
# click bookmark button
27+
bookmark_button = controller.InputBookmarkButton(page)
28+
bookmark_button.click()
29+
30+
left_sidebar.set(True)
31+
right_sidebar.set(True)
32+
33+
# reload page
34+
page.reload()
35+
36+
left_sidebar.expect_open(False)
37+
right_sidebar.expect_open(False)

0 commit comments

Comments
 (0)