1111from idom import html
1212from idom .config import IDOM_DEBUG_MODE
1313from idom .core .component import component
14- from idom .core .hooks import use_effect , use_state
14+ from idom .core .hooks import create_context , use_context , use_effect , use_state
1515from idom .core .layout import Layout , LayoutEvent , LayoutUpdate
1616from idom .testing import (
1717 HookCatcher ,
2020 capture_idom_logs ,
2121)
2222from idom .utils import Ref
23- from tests .tooling .hooks import use_toggle
23+ from tests .tooling .hooks import use_force_render , use_toggle
2424
2525
2626@pytest .fixture (autouse = True )
@@ -1123,83 +1123,6 @@ def Child():
11231123 assert did_unmount .current
11241124
11251125
1126- class ComponentShouldRender :
1127- def __init__ (self , child , should_render ):
1128- self .child = child or html .div ()
1129- self .should_render = should_render
1130- self .key = None
1131- self .type = self .__class__
1132-
1133- def render (self ):
1134- return html .div (self .child )
1135-
1136-
1137- async def test_component_should_render_always_true ():
1138- render_count = idom .Ref (0 )
1139- root_hook = HookCatcher ()
1140-
1141- @idom .component
1142- @root_hook .capture
1143- def Root ():
1144- return ComponentShouldRender (SomeComponent (), should_render = lambda new : True )
1145-
1146- @idom .component
1147- def SomeComponent ():
1148- render_count .current += 1
1149- return html .div ()
1150-
1151- async with idom .Layout (Root ()) as layout :
1152- for _ in range (4 ):
1153- await layout .render ()
1154- root_hook .latest .schedule_render ()
1155-
1156- assert render_count .current == 4
1157-
1158-
1159- async def test_component_should_render_always_false ():
1160- render_count = idom .Ref (0 )
1161- root_hook = HookCatcher ()
1162-
1163- @idom .component
1164- @root_hook .capture
1165- def Root ():
1166- return ComponentShouldRender (SomeComponent (), should_render = lambda new : False )
1167-
1168- @idom .component
1169- def SomeComponent ():
1170- render_count .current += 1
1171- return html .div ()
1172-
1173- async with idom .Layout (Root ()) as layout :
1174- for _ in range (4 ):
1175- await layout .render ()
1176- root_hook .latest .schedule_render ()
1177-
1178- assert render_count .current == 1
1179-
1180-
1181- async def test_component_error_in_should_render_is_handled_gracefully ():
1182- root_hook = HookCatcher ()
1183-
1184- @idom .component
1185- @root_hook .capture
1186- def Root ():
1187- def bad_should_render (new ):
1188- raise ValueError ("The error message" )
1189-
1190- return ComponentShouldRender (html .div (), should_render = bad_should_render )
1191-
1192- with assert_idom_did_log (
1193- match_message = r".* component failed to check if .* should be rendered" ,
1194- error_type = ValueError ,
1195- match_error = "The error message" ,
1196- ):
1197- async with idom .Layout (Root ()) as layout :
1198- await layout .render ()
1199- root_hook .latest .schedule_render ()
1200- await layout .render ()
1201-
1202-
12031126async def test_does_render_children_after_component ():
12041127 """Regression test for bug where layout was appending children to a stale ref
12051128
@@ -1221,7 +1144,6 @@ def Child():
12211144
12221145 async with idom .Layout (Parent ()) as layout :
12231146 update = await layout .render ()
1224- print (update .new )
12251147 assert update .new == {
12261148 "tagName" : "" ,
12271149 "children" : [
@@ -1238,3 +1160,34 @@ def Child():
12381160 }
12391161 ],
12401162 }
1163+
1164+
1165+ async def test_remove_context_provider_consumer_without_changing_context_value ():
1166+ Context = idom .create_context (None )
1167+ toggle_remove_child = None
1168+ schedule_removed_child_render = None
1169+
1170+ @component
1171+ def Parent ():
1172+ nonlocal toggle_remove_child
1173+ remove_child , toggle_remove_child = use_toggle ()
1174+ return Context (html .div () if remove_child else Child (), value = None )
1175+
1176+ @component
1177+ def Child ():
1178+ nonlocal schedule_removed_child_render
1179+ schedule_removed_child_render = use_force_render ()
1180+ return None
1181+
1182+ async with idom .Layout (Parent ()) as layout :
1183+ await layout .render ()
1184+
1185+ # If the context provider does not render its children then internally tracked
1186+ # state for the removed child component might not be cleaned up propperly
1187+ toggle_remove_child ()
1188+ await layout .render ()
1189+
1190+ # If this removed child component has state which has not been cleaned up
1191+ # correctly, scheduling a render for it might cause an error.
1192+ schedule_removed_child_render ()
1193+ await layout .render ()
0 commit comments