11"""
2- Regression tests for issue #666: updating child components via a parent method.
2+ Regression tests for:
3+ - Issue #666: updating child components via a parent method.
4+ - Issue #685: self.parent reference not updating in child components.
35
46When a parent component's method modifies children's state (e.g., setting
57is_editing=True on all children), the changes must be persisted to cache before
68the parent re-renders so that template tags retrieve the updated children.
9+
10+ Additionally, when children are rendered via template tags during a parent's
11+ re-render, their self.parent must point to the exact in-memory parent object so
12+ that they always see the parent's current state.
713"""
814
915import shortuuid
@@ -22,12 +28,16 @@ class ChildView(UnicornView):
2228
2329class ParentView (UnicornView ):
2430 template_name = "templates/test_component.html"
31+ current_page : str = "root"
2532
2633 def begin_edit_all (self ):
2734 for child in self .children :
2835 if hasattr (child , "is_editing" ):
2936 child .is_editing = True
3037
38+ def walk (self , page : str ):
39+ self .current_page = page
40+
3141
3242PARENT_NAME = "tests.views.message.test_child_state_propagation.ParentView"
3343CHILD_NAME = "tests.views.message.test_child_state_propagation.ChildView"
@@ -79,6 +89,50 @@ def test_parent_method_child_state_persisted_in_cache(client):
7989 )
8090
8191
92+ def test_child_self_parent_is_in_memory_parent_after_create (client ):
93+ """
94+ Issue #685: when UnicornView.create() returns a cached child component,
95+ its self.parent must be the *exact same Python object* as the in-memory parent
96+ being rendered, not a stale copy restored from the Django cache.
97+
98+ We verify this by calling create() with an updated in-memory parent and
99+ checking that the returned child's .parent IS that same object.
100+ """
101+ from django .test import RequestFactory
102+
103+ from django_unicorn .components import UnicornView
104+
105+ parent_id = shortuuid .uuid ()[:8 ]
106+ child_id = f"{ parent_id } :{ CHILD_NAME } "
107+
108+ parent = ParentView (component_id = parent_id , component_name = PARENT_NAME )
109+ child = ChildView (component_id = child_id , component_name = CHILD_NAME , parent = parent )
110+
111+ # Persist to cache (simulates initial page load state)
112+ cache_full_tree (parent )
113+
114+ # Simulate the parent changing state (e.g. walk() was called)
115+ parent .current_page = "chapter-2"
116+
117+ request = RequestFactory ().get ("/" )
118+
119+ # When the parent template re-renders, the template tag calls create() for the child
120+ retrieved_child = UnicornView .create (
121+ component_id = child_id ,
122+ component_name = CHILD_NAME ,
123+ parent = parent ,
124+ request = request ,
125+ )
126+
127+ assert retrieved_child .parent is parent , (
128+ "self.parent in the child should be the exact in-memory parent object, "
129+ "not a stale cache-restored copy (issue #685)."
130+ )
131+ assert retrieved_child .parent .current_page == "chapter-2" , (
132+ "self.parent.current_page should reflect the parent's current in-memory state."
133+ )
134+
135+
82136def test_parent_method_multiple_children_all_updated_in_cache (client ):
83137 """
84138 All children must be updated in cache, not just the first one.
@@ -115,6 +169,4 @@ def test_parent_method_multiple_children_all_updated_in_cache(client):
115169 for child in [child1 , child2 , child3 ]:
116170 cached = cache .get (child .component_cache_key )
117171 assert cached is not None
118- assert cached .is_editing is True , (
119- f"Child { child .component_id } should have is_editing=True after begin_edit_all"
120- )
172+ assert cached .is_editing is True , f"Child { child .component_id } should have is_editing=True after begin_edit_all"
0 commit comments