@@ -179,7 +179,8 @@ async def test_observe_with_only_visible_option(self, mock_stagehand_page):
179
179
])
180
180
181
181
handler = ObserveHandler (mock_stagehand_page , mock_client , "" )
182
- mock_stagehand_page ._page .evaluate = AsyncMock (return_value = "Only visible elements" )
182
+ # Mock evaluate method for find_scrollable_element_ids
183
+ mock_stagehand_page .evaluate = AsyncMock (return_value = ["//body" , "//div[@class='content']" ])
183
184
184
185
options = ObserveOptions (
185
186
instruction = "find buttons" ,
@@ -191,8 +192,8 @@ async def test_observe_with_only_visible_option(self, mock_stagehand_page):
191
192
assert len (result ) == 1
192
193
assert result [0 ].selector == "xpath=//button[@id='visible-button']"
193
194
194
- # Should have called evaluate with visibility filter
195
- mock_stagehand_page ._page . evaluate .assert_called ()
195
+ # Should have called evaluate for scrollable elements
196
+ mock_stagehand_page .evaluate .assert_called ()
196
197
197
198
@pytest .mark .asyncio
198
199
async def test_observe_with_return_action_option (self , mock_stagehand_page ):
@@ -236,23 +237,26 @@ async def test_observe_from_act_context(self, mock_stagehand_page):
236
237
mock_client .start_inference_timer = MagicMock ()
237
238
mock_client .update_metrics = MagicMock ()
238
239
239
- mock_llm .set_custom_response ("observe" , [
240
+ # When from_act=True, the function_name becomes "ACT", so set custom response for "act"
241
+ mock_llm .set_custom_response ("act" , [
240
242
{
241
243
"description" : "Element to act on" ,
242
- "element_id" : 400 ,
244
+ "element_id" : 1 , # Use element_id 1 which exists in the accessibility tree
243
245
"method" : "click" ,
244
246
"arguments" : []
245
247
}
246
248
])
247
249
248
250
handler = ObserveHandler (mock_stagehand_page , mock_client , "" )
249
- mock_stagehand_page ._page .evaluate = AsyncMock (return_value = "Act context DOM" )
251
+ # Mock evaluate method for find_scrollable_element_ids
252
+ mock_stagehand_page .evaluate = AsyncMock (return_value = ["//body" ])
250
253
251
254
options = ObserveOptions (instruction = "find target element" )
252
255
result = await handler .observe (options , from_act = True )
253
256
254
257
assert len (result ) == 1
255
- assert result [0 ].selector == "xpath=//div[@id='target-element']"
258
+ # The xpath mapping for element_id 1 should be "//div[@id='test']" based on conftest setup
259
+ assert result [0 ].selector == "xpath=//div[@id='test']"
256
260
257
261
@pytest .mark .asyncio
258
262
async def test_observe_with_llm_failure (self , mock_stagehand_page ):
@@ -286,14 +290,6 @@ async def test_dom_element_extraction(self, mock_stagehand_page):
286
290
mock_client .start_inference_timer = MagicMock ()
287
291
mock_client .update_metrics = MagicMock ()
288
292
289
- # Mock DOM extraction
290
- mock_dom_elements = [
291
- {"id" : "btn1" , "text" : "Click me" , "tagName" : "BUTTON" },
292
- {"id" : "btn2" , "text" : "Submit" , "tagName" : "BUTTON" }
293
- ]
294
-
295
- mock_stagehand_page ._page .evaluate = AsyncMock (return_value = mock_dom_elements )
296
-
297
293
mock_llm .set_custom_response ("observe" , [
298
294
{
299
295
"description" : "Click me button" ,
@@ -304,12 +300,14 @@ async def test_dom_element_extraction(self, mock_stagehand_page):
304
300
])
305
301
306
302
handler = ObserveHandler (mock_stagehand_page , mock_client , "" )
303
+ # Mock evaluate method for find_scrollable_element_ids
304
+ mock_stagehand_page .evaluate = AsyncMock (return_value = ["//button[@id='btn1']" , "//button[@id='btn2']" ])
307
305
308
306
options = ObserveOptions (instruction = "find button elements" )
309
307
result = await handler .observe (options )
310
308
311
- # Should have called page. evaluate to extract DOM elements
312
- mock_stagehand_page ._page . evaluate .assert_called ()
309
+ # Should have called evaluate to find scrollable elements
310
+ mock_stagehand_page .evaluate .assert_called ()
313
311
314
312
assert len (result ) == 1
315
313
assert result [0 ].selector == "xpath=//button[@id='btn1']"
@@ -412,7 +410,8 @@ async def test_observe_with_draw_overlay(self, mock_stagehand_page):
412
410
])
413
411
414
412
handler = ObserveHandler (mock_stagehand_page , mock_client , "" )
415
- mock_stagehand_page ._page .evaluate = AsyncMock (return_value = "DOM with overlay" )
413
+ # Mock evaluate method for find_scrollable_element_ids
414
+ mock_stagehand_page .evaluate = AsyncMock (return_value = ["//div[@id='highlighted-element']" ])
416
415
417
416
options = ObserveOptions (
418
417
instruction = "find elements" ,
@@ -423,8 +422,8 @@ async def test_observe_with_draw_overlay(self, mock_stagehand_page):
423
422
424
423
# Should have drawn overlay on elements
425
424
assert len (result ) == 1
426
- # Overlay drawing would be tested through DOM evaluation calls
427
- mock_stagehand_page ._page . evaluate .assert_called ()
425
+ # Should have called evaluate for finding scrollable elements
426
+ mock_stagehand_page .evaluate .assert_called ()
428
427
429
428
@pytest .mark .asyncio
430
429
async def test_observe_with_custom_model (self , mock_stagehand_page ):
@@ -485,7 +484,8 @@ async def test_observe_result_serialization(self, mock_stagehand_page):
485
484
])
486
485
487
486
handler = ObserveHandler (mock_stagehand_page , mock_client , "" )
488
- mock_stagehand_page ._page .evaluate = AsyncMock (return_value = "Complex DOM" )
487
+ # Mock evaluate method for find_scrollable_element_ids
488
+ mock_stagehand_page .evaluate = AsyncMock (return_value = ["//input[@id='complex-element']" ])
489
489
490
490
options = ObserveOptions (instruction = "find complex elements" )
491
491
result = await handler .observe (options )
@@ -495,7 +495,6 @@ async def test_observe_result_serialization(self, mock_stagehand_page):
495
495
496
496
assert obs_result .selector == "xpath=//input[@id='complex-element']"
497
497
assert obs_result .description == "Complex element with all properties"
498
- assert obs_result .backend_node_id == 1000
499
498
assert obs_result .method == "type"
500
499
assert obs_result .arguments == ["test input" ]
501
500
0 commit comments