88from stagehand .schemas import ExtractOptions
99
1010
11- skip_if_no_creds = pytest .mark .skipif (
12- not (os .getenv ("BROWSERBASE_API_KEY" ) and os .getenv ("BROWSERBASE_PROJECT_ID" )),
13- reason = "Browserbase credentials are not available for API integration tests" ,
14- )
15-
16-
1711class Article (BaseModel ):
1812 """Schema for article extraction tests"""
1913 title : str = Field (..., description = "The title of the article" )
2014 summary : str = Field (None , description = "A brief summary or description of the article" )
2115
2216
23- @pytest_asyncio .fixture (scope = "module" )
24- @skip_if_no_creds
25- async def stagehand_api ():
26- """Provide a lightweight Stagehand instance pointing to the Browserbase API."""
27- config = StagehandConfig (
28- env = "BROWSERBASE" ,
29- api_key = os .getenv ("BROWSERBASE_API_KEY" ),
30- project_id = os .getenv ("BROWSERBASE_PROJECT_ID" ),
31- headless = True ,
32- verbose = 0 ,
33- )
34- sh = Stagehand (config = config )
35- await sh .init ()
36- yield sh
37- await sh .close ()
17+ class TestStagehandAPIIntegration :
18+ """Integration tests for Stagehand Python SDK in BROWSERBASE API mode."""
3819
20+ @pytest .fixture (scope = "class" )
21+ def browserbase_config (self ):
22+ """Configuration for BROWSERBASE mode testing"""
23+ return StagehandConfig (
24+ env = "BROWSERBASE" ,
25+ api_key = os .getenv ("BROWSERBASE_API_KEY" ),
26+ project_id = os .getenv ("BROWSERBASE_PROJECT_ID" ),
27+ model_name = "gpt-4o" ,
28+ headless = False ,
29+ verbose = 2 ,
30+ model_client_options = {"apiKey" : os .getenv ("MODEL_API_KEY" ) or os .getenv ("OPENAI_API_KEY" )},
31+ )
3932
40- @skip_if_no_creds
41- @pytest .mark .integration
42- @pytest .mark .api
43- @pytest .mark .asyncio
44- async def test_stagehand_api_initialization (stagehand_api ):
45- """Ensure that Stagehand initializes correctly against the Browserbase API."""
46- assert stagehand_api .session_id is not None
33+ @pytest_asyncio .fixture
34+ async def stagehand_api (self , browserbase_config ):
35+ """Create a Stagehand instance for BROWSERBASE API testing"""
36+ if not (os .getenv ("BROWSERBASE_API_KEY" ) and os .getenv ("BROWSERBASE_PROJECT_ID" )):
37+ pytest .skip ("Browserbase credentials not available" )
38+
39+ stagehand = Stagehand (config = browserbase_config )
40+ await stagehand .init ()
41+ yield stagehand
42+ await stagehand .close ()
4743
44+ @pytest .mark .asyncio
45+ @pytest .mark .integration
46+ @pytest .mark .api
47+ @pytest .mark .skipif (
48+ not (os .getenv ("BROWSERBASE_API_KEY" ) and os .getenv ("BROWSERBASE_PROJECT_ID" )),
49+ reason = "Browserbase credentials are not available for API integration tests" ,
50+ )
51+ async def test_stagehand_api_initialization (self , stagehand_api ):
52+ """Ensure that Stagehand initializes correctly against the Browserbase API."""
53+ assert stagehand_api .session_id is not None
4854
49- @skip_if_no_creds
50- @pytest .mark .integration
51- @pytest .mark .api
52- @pytest .mark .asyncio
53- async def test_api_extract_functionality (stagehand_api ):
54- """Test core extract functionality in API mode - extracted from e2e tests."""
55- stagehand = stagehand_api
56-
57- # Navigate to a content-rich page
58- await stagehand .page .goto ("https://news.ycombinator.com" )
59-
60- # Test simple text-based extraction
61- titles_text = await stagehand .page .extract (
62- "Extract the titles of the first 3 articles on the page as a JSON array"
55+ @pytest .mark .asyncio
56+ @pytest .mark .integration
57+ @pytest .mark .api
58+ @pytest .mark .skipif (
59+ not (os .getenv ("BROWSERBASE_API_KEY" ) and os .getenv ("BROWSERBASE_PROJECT_ID" )),
60+ reason = "Browserbase credentials are not available for API integration tests" ,
6361 )
64-
65- # Verify extraction worked
66- assert titles_text is not None
67-
68- # Test schema-based extraction
69- extract_options = ExtractOptions (
70- instruction = "Extract the first article's title and any available summary" ,
71- schema_definition = Article
62+ async def test_api_observe_and_act_workflow (self , stagehand_api ):
63+ """Test core observe and act workflow in API mode - replicated from local tests."""
64+ stagehand = stagehand_api
65+
66+ # Navigate to a form page for testing
67+ await stagehand .page .goto ("https://httpbin.org/forms/post" )
68+
69+ # Test OBSERVE primitive: Find form elements
70+ form_elements = await stagehand .page .observe ("Find all form input elements" )
71+
72+ # Verify observations
73+ assert form_elements is not None
74+ assert len (form_elements ) > 0
75+
76+ # Verify observation structure
77+ for obs in form_elements :
78+ assert hasattr (obs , "selector" )
79+ assert obs .selector # Not empty
80+
81+ # Test ACT primitive: Fill form fields
82+ await stagehand .page .act ("Fill the customer name field with 'API Integration Test'" )
83+ await stagehand .page .act ("Fill the telephone field with '555-API'" )
84+ await stagehand .page .act ("Fill the email field with 'api@integration.test'" )
85+
86+ # Verify actions worked by observing filled fields
87+ filled_fields = await stagehand .page .observe ("Find all filled form input fields" )
88+ assert filled_fields is not None
89+ assert len (filled_fields ) > 0
90+
91+ # Test interaction with specific elements
92+ customer_field = await stagehand .page .observe ("Find the customer name input field" )
93+ assert customer_field is not None
94+ assert len (customer_field ) > 0
95+
96+ @pytest .mark .asyncio
97+ @pytest .mark .integration
98+ @pytest .mark .api
99+ @pytest .mark .skipif (
100+ not (os .getenv ("BROWSERBASE_API_KEY" ) and os .getenv ("BROWSERBASE_PROJECT_ID" )),
101+ reason = "Browserbase credentials are not available for API integration tests" ,
102+ )
103+ async def test_api_basic_navigation_and_observe (self , stagehand_api ):
104+ """Test basic navigation and observe functionality in API mode - replicated from local tests."""
105+ stagehand = stagehand_api
106+
107+ # Navigate to a simple page
108+ await stagehand .page .goto ("https://example.com" )
109+
110+ # Observe elements on the page
111+ observations = await stagehand .page .observe ("Find all the links on the page" )
112+
113+ # Verify we got some observations
114+ assert observations is not None
115+ assert len (observations ) > 0
116+
117+ # Verify observation structure
118+ for obs in observations :
119+ assert hasattr (obs , "selector" )
120+ assert obs .selector # Not empty
121+
122+ @pytest .mark .asyncio
123+ @pytest .mark .integration
124+ @pytest .mark .api
125+ @pytest .mark .skipif (
126+ not (os .getenv ("BROWSERBASE_API_KEY" ) and os .getenv ("BROWSERBASE_PROJECT_ID" )),
127+ reason = "Browserbase credentials are not available for API integration tests" ,
72128 )
73-
74- article_data = await stagehand .page .extract (extract_options )
75- assert article_data is not None
76-
77- # Validate the extracted data structure (Browserbase format)
78- if hasattr (article_data , 'data' ) and article_data .data :
79- # BROWSERBASE mode format
80- article = Article .model_validate (article_data .data )
81- assert article .title
82- assert len (article .title ) > 0
83- elif hasattr (article_data , 'title' ):
84- # Fallback format
85- article = Article .model_validate (article_data .model_dump ())
86- assert article .title
87- assert len (article .title ) > 0
88-
89- # Verify API session is active
90- assert stagehand .session_id is not None
129+ async def test_api_extraction_functionality (self , stagehand_api ):
130+ """Test extraction functionality in API mode - replicated from local tests."""
131+ stagehand = stagehand_api
132+
133+ # Navigate to a content-rich page
134+ await stagehand .page .goto ("https://news.ycombinator.com" )
135+
136+ # Test simple text-based extraction
137+ titles_text = await stagehand .page .extract (
138+ "Extract the titles of the first 3 articles on the page as a JSON array"
139+ )
140+
141+ # Verify extraction worked
142+ assert titles_text is not None
143+
144+ # Test schema-based extraction
145+ extract_options = ExtractOptions (
146+ instruction = "Extract the first article's title and any available summary" ,
147+ schema_definition = Article
148+ )
149+
150+ article_data = await stagehand .page .extract (extract_options )
151+ assert article_data is not None
152+
153+ # Validate the extracted data structure (Browserbase format)
154+ if hasattr (article_data , 'data' ) and article_data .data :
155+ # BROWSERBASE mode format
156+ article = Article .model_validate (article_data .data )
157+ assert article .title
158+ assert len (article .title ) > 0
159+ elif hasattr (article_data , 'title' ):
160+ # Fallback format
161+ article = Article .model_validate (article_data .model_dump ())
162+ assert article .title
163+ assert len (article .title ) > 0
164+
165+ # Verify API session is active
166+ assert stagehand .session_id is not None
0 commit comments