@@ -150,9 +150,10 @@ async def test_attach_frame_navigated_listener(self, mock_browser_context, mock_
150150 assert mock_cdp_session .on .call_args [0 ][0 ] == "Page.frameNavigated"
151151
152152 @pytest .mark .asyncio
153- async def test_frame_id_in_api_calls (self , mock_page , mock_stagehand ):
153+ async def test_frame_id_in_api_calls (self , mock_page , mock_stagehand , mock_browser_context ):
154154 """Test that frame ID is included in API payloads."""
155- stagehand_page = StagehandPage (mock_page , mock_stagehand )
155+ context = StagehandContext (mock_browser_context , mock_stagehand )
156+ stagehand_page = StagehandPage (mock_page , mock_stagehand , context )
156157 stagehand_page .update_root_frame_id ("test-frame-123" )
157158
158159 # Mock the stagehand client for API mode
@@ -202,6 +203,7 @@ async def test_frame_navigation_event_handling(self, mock_browser_context, mock_
202203 event_handler = mock_cdp_session .on .call_args [0 ][1 ]
203204
204205 # Simulate frame navigation event
206+ # The event handler schedules async work, so we need to wait for it
205207 new_frame_id = "frame-new"
206208 event_handler ({
207209 "frame" : {
@@ -210,6 +212,9 @@ async def test_frame_navigation_event_handling(self, mock_browser_context, mock_
210212 }
211213 })
212214
215+ # Wait for async tasks to complete
216+ await asyncio .sleep (0.1 )
217+
213218 # Verify old frame ID was unregistered and new one registered
214219 assert initial_frame_id not in context .frame_id_map
215220 assert new_frame_id in context .frame_id_map
@@ -300,29 +305,10 @@ async def test_frame_id_race_condition_prevention(self, mock_browser_context, mo
300305 context = StagehandContext (mock_browser_context , mock_stagehand )
301306 stagehand_page = StagehandPage (mock_page , mock_stagehand , context )
302307
303- # Track call order
304- call_order = []
305-
306- async def mock_register (frame_id , page ):
307- call_order .append (f"register_{ frame_id } " )
308- # Simulate some async work
309- await asyncio .sleep (0.01 )
310- context .frame_id_map [frame_id ] = page
311-
312- async def mock_unregister (frame_id ):
313- call_order .append (f"unregister_{ frame_id } " )
314- # Simulate some async work
315- await asyncio .sleep (0.01 )
316- if frame_id in context .frame_id_map :
317- del context .frame_id_map [frame_id ]
318-
319- # Temporarily replace methods
320- original_register = context .register_frame_id
321- original_unregister = context .unregister_frame_id
322- context .register_frame_id = mock_register
323- context .unregister_frame_id = mock_unregister
324-
325- try :
308+ # Track actual calls to the real methods through patching
309+ with patch .object (context , 'register_frame_id' , wraps = context .register_frame_id ) as mock_reg , \
310+ patch .object (context , 'unregister_frame_id' , wraps = context .unregister_frame_id ) as mock_unreg :
311+
326312 # Simulate multiple concurrent frame navigations
327313 tasks = [
328314 context ._handle_frame_navigated (
@@ -334,14 +320,10 @@ async def mock_unregister(frame_id):
334320
335321 await asyncio .gather (* tasks )
336322
337- # Verify operations were serialized (no interleaving)
338- # Each frame should be registered without interruption
339- assert len (call_order ) == 6 # 3 unregisters + 3 registers
340-
341- finally :
342- # Restore original methods
343- context .register_frame_id = original_register
344- context .unregister_frame_id = original_unregister
323+ # Verify methods were called the expected number of times
324+ # Each navigation causes an unregister (if there's an old frame) and a register
325+ assert mock_reg .call_count == 3 # 3 registers
326+ assert mock_unreg .call_count >= 2 # At least 2 unregisters (first might not have old frame)
345327
346328 @pytest .mark .asyncio
347329 async def test_weak_reference_cleanup (self , mock_browser_context , mock_stagehand , mock_page ):
0 commit comments