Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/reactpy/executors/pyscript/layout_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ def update_model(update, root_model):
if update["path"]:
set_pointer(root_model, update["path"], update["model"])
else:
# clear old keys first, dict.update() alone would keep stale "children" around when the new model doesn't have any
root_model.clear()
root_model.update(update["model"])

def render_html(self, layout, model):
Expand Down
20 changes: 20 additions & 0 deletions tests/test_pyscript/pyscript_components/root_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from reactpy import component, hooks, html


@component
def root():
count, set_count = hooks.use_state(0)

def increment(event):
set_count(count + 1)

# crash on purpose after a few clicks, same as the real bug report
if count == 3:
raise ValueError("This error should hide the root component")

return html.div(
html.button(
{"onClick": increment, "id": "incr", "data-count": count}, "Increment"
),
html.p(f"PyScript Count: {count}"),
)
27 changes: 27 additions & 0 deletions tests/test_pyscript/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,33 @@ def CustomRootName():
await display.page.wait_for_selector("#incr[data-count='3']")


async def test_root_component_error_hides_component(display: DisplayFixture):
"""A crash in the root render should hide it, not leave stale content stuck
on the page."""

@reactpy.component
def Counter():
return pyscript_component(
Path(__file__).parent / "pyscript_components" / "root_error.py",
initial=html.div({"id": "loading"}, "Loading..."),
)

await display.show(Counter)

await display.page.wait_for_selector("#loading")
await display.page.wait_for_selector("#incr")

await display.page.click("#incr")
await display.page.wait_for_selector("#incr[data-count='1']")

await display.page.click("#incr")
await display.page.wait_for_selector("#incr[data-count='2']")

# this click flips count to 3 -> root component raises -> button should vanish
await display.page.click("#incr")
await display.page.wait_for_selector("#incr", state="detached")


def test_bad_file_path():
with pytest.raises(ValueError):
pyscript_component(initial=html.div({"id": "loading"}, "Loading...")).render()