Skip to content

Commit 641d2cc

Browse files
committed
Fix broken tests
1 parent 1b87812 commit 641d2cc

File tree

6 files changed

+61
-70
lines changed

6 files changed

+61
-70
lines changed

pytest.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ python_files = test_*.py
44
python_classes = Test*
55
python_functions = test_*
66
asyncio_mode = auto
7+
asyncio_default_test_loop_scope = session
8+
asyncio_default_fixture_loop_scope = session
79

810
markers =
911
unit: marks tests as unit tests

stagehand/handlers/extract_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,4 @@ async def _extract_page_text(self) -> ExtractResult:
183183
output_string = tree["simplified"]
184184
output_dict = {"page_text": output_string}
185185
validated_model = EmptyExtractSchema.model_validate(output_dict)
186-
return ExtractResult(data=validated_model).data
186+
return ExtractResult(data=validated_model)

tests/conftest.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,6 @@
1111
# Set up pytest-asyncio as the default
1212
pytest_plugins = ["pytest_asyncio"]
1313

14-
15-
@pytest.fixture(scope="session")
16-
def event_loop():
17-
"""
18-
Create an instance of the default event loop for each test session.
19-
This helps with running async tests.
20-
"""
21-
policy = asyncio.get_event_loop_policy()
22-
loop = policy.new_event_loop()
23-
yield loop
24-
loop.close()
25-
26-
2714
@pytest.fixture
2815
def mock_stagehand_config():
2916
"""Provide a mock StagehandConfig for testing"""

tests/e2e/test_act_integration.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,17 +161,17 @@ async def test_selecting_option_custom_input_local(self, local_stagehand):
161161
await stagehand.page.goto("https://browserbase.github.io/stagehand-eval-sites/sites/expand-dropdown/")
162162

163163
# Select an option from the dropdown.
164-
await stagehand.page.act("Click the 'Select a Country' dropdown")
164+
await stagehand.page.act("Click on the text 'Select a country'")
165165

166166
# Wait for dropdown to expand
167-
await asyncio.sleep(1)
167+
await asyncio.sleep(2)
168168

169169
# We are expecting stagehand to click the dropdown to expand it, and therefore
170170
# the available options should now be contained in the full a11y tree.
171171

172172
# To test, we'll grab the full a11y tree, and make sure it contains 'Canada'
173173
extraction = await stagehand.page.extract()
174-
assert "Canada" in extraction.data
174+
assert "Canada" in extraction.data.page_text
175175

176176
@pytest.mark.asyncio
177177
@pytest.mark.local
@@ -193,7 +193,7 @@ async def test_selecting_option_hidden_input_local(self, local_stagehand):
193193

194194
# To test, we'll grab the full a11y tree, and make sure it contains 'Green'
195195
extraction = await stagehand.page.extract()
196-
assert "Green" in extraction.data
196+
assert "Green" in extraction.data.page_text
197197

198198
@pytest.mark.asyncio
199199
@pytest.mark.local

tests/e2e/test_workflows.py

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ async def test_search_and_extract_workflow(self, mock_stagehand_config, sample_h
5151
stagehand._playwright = playwright
5252
stagehand._browser = browser
5353
stagehand._context = context
54-
stagehand.page = MagicMock()
55-
stagehand.page.goto = AsyncMock()
56-
stagehand.page.act = AsyncMock(return_value=ActResult(
54+
stagehand._page = MagicMock()
55+
stagehand._page.goto = AsyncMock()
56+
stagehand._page.act = AsyncMock(return_value=ActResult(
5757
success=True,
5858
message="Search executed",
5959
action="search"
6060
))
61-
stagehand.page.extract = AsyncMock(return_value={
61+
stagehand._page.extract = AsyncMock(return_value={
6262
"title": "OpenAI Search Results",
6363
"results": [
6464
{"title": "OpenAI Official Website", "url": "https://openai.com"},
@@ -82,9 +82,9 @@ async def test_search_and_extract_workflow(self, mock_stagehand_config, sample_h
8282
assert extracted_data["results"][0]["title"] == "OpenAI Official Website"
8383

8484
# Verify calls were made
85-
stagehand.page.goto.assert_called_with("https://google.com")
86-
stagehand.page.act.assert_called_with("search for openai")
87-
stagehand.page.extract.assert_called_with("extract search results")
85+
stagehand._page.goto.assert_called_with("https://google.com")
86+
stagehand._page.act.assert_called_with("search for openai")
87+
stagehand._page.extract.assert_called_with("extract search results")
8888

8989
finally:
9090
stagehand._closed = True
@@ -149,22 +149,22 @@ def form_response_generator(messages, **kwargs):
149149
stagehand._playwright = playwright
150150
stagehand._browser = browser
151151
stagehand._context = context
152-
stagehand.page = MagicMock()
153-
stagehand.page.goto = AsyncMock()
154-
stagehand.page.act = AsyncMock()
155-
stagehand.page.extract = AsyncMock()
152+
stagehand._page = MagicMock()
153+
stagehand._page.goto = AsyncMock()
154+
stagehand._page.act = AsyncMock()
155+
stagehand._page.extract = AsyncMock()
156156
stagehand._initialized = True
157-
157+
158158
# Mock act responses
159-
stagehand.page.act.side_effect = [
159+
stagehand._page.act.side_effect = [
160160
ActResult(success=True, message="Username filled", action="fill"),
161161
ActResult(success=True, message="Email filled", action="fill"),
162162
ActResult(success=True, message="Password filled", action="fill"),
163163
ActResult(success=True, message="Form submitted", action="click")
164164
]
165165

166166
# Mock success verification
167-
stagehand.page.extract.return_value = {"success": True, "message": "Registration successful!"}
167+
stagehand._page.extract.return_value = {"success": True, "message": "Registration successful!"}
168168

169169
try:
170170
# Execute form filling workflow
@@ -189,7 +189,7 @@ def form_response_generator(messages, **kwargs):
189189
assert verification["success"] is True
190190

191191
# Verify all steps were executed
192-
assert stagehand.page.act.call_count == 4
192+
assert stagehand._page.act.call_count == 4
193193

194194
finally:
195195
stagehand._closed = True
@@ -235,10 +235,10 @@ async def test_observe_then_act_workflow(self, mock_stagehand_config):
235235
stagehand._playwright = playwright
236236
stagehand._browser = browser
237237
stagehand._context = context
238-
stagehand.page = MagicMock()
239-
stagehand.page.goto = AsyncMock()
240-
stagehand.page.observe = AsyncMock()
241-
stagehand.page.act = AsyncMock()
238+
stagehand._page = MagicMock()
239+
stagehand._page.goto = AsyncMock()
240+
stagehand._page.observe = AsyncMock()
241+
stagehand._page.act = AsyncMock()
242242
stagehand._initialized = True
243243

244244
# Mock observe results
@@ -278,8 +278,8 @@ async def test_observe_then_act_workflow(self, mock_stagehand_config):
278278
)
279279
]
280280

281-
stagehand.page.observe.side_effect = [nav_buttons, add_to_cart_buttons]
282-
stagehand.page.act.return_value = ActResult(
281+
stagehand._page.observe.side_effect = [nav_buttons, add_to_cart_buttons]
282+
stagehand._page.act.return_value = ActResult(
283283
success=True,
284284
message="Button clicked",
285285
action="click"
@@ -307,8 +307,8 @@ async def test_observe_then_act_workflow(self, mock_stagehand_config):
307307
assert add_to_cart_result.success is True
308308

309309
# Verify method calls
310-
assert stagehand.page.observe.call_count == 2
311-
assert stagehand.page.act.call_count == 2
310+
assert stagehand._page.observe.call_count == 2
311+
assert stagehand._page.act.call_count == 2
312312

313313
finally:
314314
stagehand._closed = True
@@ -370,10 +370,10 @@ async def test_multi_page_navigation_workflow(self, mock_stagehand_config):
370370
stagehand._playwright = playwright
371371
stagehand._browser = browser
372372
stagehand._context = context
373-
stagehand.page = MagicMock()
374-
stagehand.page.goto = AsyncMock()
375-
stagehand.page.extract = AsyncMock()
376-
stagehand.page.act = AsyncMock()
373+
stagehand._page = MagicMock()
374+
stagehand._page.goto = AsyncMock()
375+
stagehand._page.extract = AsyncMock()
376+
stagehand._page.act = AsyncMock()
377377
stagehand._initialized = True
378378

379379
# Mock page responses
@@ -403,9 +403,9 @@ def navigation_side_effect(url):
403403
else:
404404
current_page[0] = "/products"
405405

406-
stagehand.page.extract.side_effect = lambda inst: extract_response(inst)
407-
stagehand.page.goto.side_effect = navigation_side_effect
408-
stagehand.page.act.return_value = ActResult(
406+
stagehand._page.extract.side_effect = lambda inst: extract_response(inst)
407+
stagehand._page.goto.side_effect = navigation_side_effect
408+
stagehand._page.act.return_value = ActResult(
409409
success=True,
410410
message="Navigation successful",
411411
action="click"
@@ -434,8 +434,8 @@ def navigation_side_effect(url):
434434
assert len(details["specs"]) == 3
435435

436436
# Verify navigation flow
437-
assert stagehand.page.goto.call_count == 2
438-
assert stagehand.page.extract.call_count == 2
437+
assert stagehand._page.goto.call_count == 2
438+
assert stagehand._page.extract.call_count == 2
439439

440440
finally:
441441
stagehand._closed = True
@@ -457,9 +457,9 @@ async def test_error_recovery_workflow(self, mock_stagehand_config):
457457
stagehand._playwright = playwright
458458
stagehand._browser = browser
459459
stagehand._context = context
460-
stagehand.page = MagicMock()
461-
stagehand.page.goto = AsyncMock()
462-
stagehand.page.act = AsyncMock()
460+
stagehand._page = MagicMock()
461+
stagehand._page.goto = AsyncMock()
462+
stagehand._page.act = AsyncMock()
463463
stagehand._initialized = True
464464

465465
# Simulate intermittent failures and recovery
@@ -481,7 +481,7 @@ def act_with_failures(*args, **kwargs):
481481
action="click"
482482
)
483483

484-
stagehand.page.act.side_effect = act_with_failures
484+
stagehand._page.act.side_effect = act_with_failures
485485

486486
try:
487487
await stagehand.page.goto("https://example.com")
@@ -498,7 +498,7 @@ def act_with_failures(*args, **kwargs):
498498

499499
assert success is True
500500
assert failure_count == 3 # 2 failures + 1 success
501-
assert stagehand.page.act.call_count == 3
501+
assert stagehand._page.act.call_count == 3
502502

503503
finally:
504504
stagehand._closed = True
@@ -538,10 +538,10 @@ async def test_browserbase_session_workflow(self, mock_browserbase_config):
538538
# Mock the browser connection parts
539539
stagehand._client = http_client
540540
stagehand.session_id = "test-bb-session"
541-
stagehand.page = MagicMock()
542-
stagehand.page.goto = AsyncMock()
543-
stagehand.page.act = AsyncMock()
544-
stagehand.page.extract = AsyncMock()
541+
stagehand._page = MagicMock()
542+
stagehand._page.goto = AsyncMock()
543+
stagehand._page.act = AsyncMock()
544+
stagehand._page.extract = AsyncMock()
545545
stagehand._initialized = True
546546

547547
# Mock page methods to use server
@@ -561,8 +561,8 @@ async def mock_extract(instruction, **kwargs):
561561
)
562562
return response.json()
563563

564-
stagehand.page.act = mock_act
565-
stagehand.page.extract = mock_extract
564+
stagehand._page.act = mock_act
565+
stagehand._page.extract = mock_extract
566566

567567
try:
568568
# Execute Browserbase workflow
@@ -616,9 +616,9 @@ class ProductList(BaseModel):
616616
stagehand._playwright = playwright
617617
stagehand._browser = browser
618618
stagehand._context = context
619-
stagehand.page = MagicMock()
620-
stagehand.page.goto = AsyncMock()
621-
stagehand.page.extract = AsyncMock()
619+
stagehand._page = MagicMock()
620+
stagehand._page.goto = AsyncMock()
621+
stagehand._page.extract = AsyncMock()
622622
stagehand._initialized = True
623623

624624
# Mock structured extraction responses
@@ -642,7 +642,7 @@ class ProductList(BaseModel):
642642
"total_count": 2
643643
}
644644

645-
stagehand.page.extract.return_value = mock_product_data
645+
stagehand._page.extract.return_value = mock_product_data
646646

647647
try:
648648
await stagehand.page.goto("https://electronics-store.com")
@@ -671,7 +671,7 @@ class ProductList(BaseModel):
671671
assert product2["in_stock"] is False
672672

673673
# Verify extract was called with schema
674-
stagehand.page.extract.assert_called_once()
674+
stagehand._page.extract.assert_called_once()
675675

676676
finally:
677677
stagehand._closed = True
@@ -696,8 +696,8 @@ async def test_concurrent_operations_workflow(self, mock_stagehand_config):
696696
stagehand._playwright = playwright
697697
stagehand._browser = browser
698698
stagehand._context = context
699-
stagehand.page = MagicMock()
700-
stagehand.page.extract = AsyncMock()
699+
stagehand._page = MagicMock()
700+
stagehand._page.extract = AsyncMock()
701701
stagehand._initialized = True
702702

703703
# Mock multiple concurrent extractions
@@ -707,7 +707,7 @@ async def test_concurrent_operations_workflow(self, mock_stagehand_config):
707707
{"section": "footer", "content": "Footer content"}
708708
]
709709

710-
stagehand.page.extract.side_effect = extraction_responses
710+
stagehand._page.extract.side_effect = extraction_responses
711711

712712
try:
713713
# Execute concurrent extractions
@@ -727,7 +727,7 @@ async def test_concurrent_operations_workflow(self, mock_stagehand_config):
727727
assert results[2]["section"] == "footer"
728728

729729
# Verify all extractions were called
730-
assert stagehand.page.extract.call_count == 3
730+
assert stagehand._page.extract.call_count == 3
731731

732732
finally:
733733
stagehand._closed = True

tests/unit/test_client_initialization.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ def test_init_with_model_api_key_in_env(self):
235235
client = Stagehand(config=config)
236236
assert client.model_api_key == "test-model-api-key"
237237

238+
@mock.patch.dict(os.environ, {}, clear=True)
238239
def test_init_with_custom_llm(self):
239240
config = StagehandConfig(
240241
env="LOCAL",
@@ -245,6 +246,7 @@ def test_init_with_custom_llm(self):
245246
assert client.model_client_options["apiKey"] == "custom-llm-key"
246247
assert client.model_client_options["baseURL"] == "https://custom-llm.com"
247248

249+
@mock.patch.dict(os.environ, {}, clear=True)
248250
def test_init_with_custom_llm_override(self):
249251
config = StagehandConfig(
250252
env="LOCAL",

0 commit comments

Comments
 (0)