Skip to content

Commit d68d7be

Browse files
committed
add test for cleanup error + fix flaky test
1 parent 986e7b0 commit d68d7be

File tree

3 files changed

+41
-9
lines changed

3 files changed

+41
-9
lines changed

src/py/reactpy/reactpy/core/_life_cycle_hook.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ async def affect_component_will_unmount(self) -> None:
178178
"""The component is about to be removed from the layout"""
179179
try:
180180
await asyncio.gather(*[stop() for stop in self._effect_stops])
181-
except Exception:
181+
except Exception: # nocov
182182
logger.exception("Error during effect cancellation")
183183
finally:
184184
self._effect_stops.clear()

src/py/reactpy/reactpy/core/hooks.py

-2
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,6 @@ async def stop(self) -> None:
188188
self._stop.set()
189189
try:
190190
cleanup = await self.task
191-
except CancelledError:
192-
pass
193191
except Exception:
194192
logger.exception("Error while stopping effect")
195193

src/py/reactpy/tests/test_core/test_hooks.py

+40-6
Original file line numberDiff line numberDiff line change
@@ -276,18 +276,18 @@ def double_set_state(event):
276276
first = await display.page.wait_for_selector("#first")
277277
second = await display.page.wait_for_selector("#second")
278278

279-
assert (await first.get_attribute("data-value")) == "0"
280-
assert (await second.get_attribute("data-value")) == "0"
279+
await poll(first.get_attribute("data-value")).until_equals("0")
280+
await poll(second.get_attribute("data-value")).until_equals("0")
281281

282282
await button.click()
283283

284-
assert (await first.get_attribute("data-value")) == "1"
285-
assert (await second.get_attribute("data-value")) == "1"
284+
await poll(first.get_attribute("data-value")).until_equals("1")
285+
await poll(second.get_attribute("data-value")).until_equals("1")
286286

287287
await button.click()
288288

289-
assert (await first.get_attribute("data-value")) == "2"
290-
assert (await second.get_attribute("data-value")) == "2"
289+
await poll(first.get_attribute("data-value")).until_equals("2")
290+
await poll(second.get_attribute("data-value")).until_equals("2")
291291

292292

293293
async def test_use_effect_callback_occurs_after_full_render_is_complete():
@@ -600,6 +600,40 @@ async def effect(e):
600600
await asyncio.wait_for(cleanup_ran.wait(), 1)
601601

602602

603+
async def test_use_async_effect_cleanup_task_error_handled_gradefully():
604+
component_hook = HookCatcher()
605+
effect_ran = WaitForEvent()
606+
cleanup_ran = WaitForEvent()
607+
608+
async def cleanup_task():
609+
cleanup_ran.set()
610+
raise ValueError("Something went wrong")
611+
612+
@reactpy.component
613+
@component_hook.capture
614+
def ComponentWithAsyncEffect():
615+
@reactpy.use_effect(dependencies=None) # force this to run every time
616+
async def effect(e):
617+
async with e:
618+
effect_ran.set()
619+
return cleanup_task()
620+
621+
return reactpy.html.div()
622+
623+
with assert_reactpy_did_log(
624+
match_message=r"Error while cleaning up effect",
625+
error_type=ValueError,
626+
):
627+
async with reactpy.Layout(ComponentWithAsyncEffect()) as layout:
628+
await layout.render()
629+
630+
component_hook.latest.schedule_render()
631+
632+
await layout.render()
633+
634+
await asyncio.wait_for(cleanup_ran.wait(), 1)
635+
636+
603637
async def test_use_async_effect_cancel(caplog):
604638
component_hook = HookCatcher()
605639
effect_ran = WaitForEvent()

0 commit comments

Comments
 (0)