88
99import inspect
1010import json
11+ import os
1112import typing
1213from pathlib import Path
1314from typing import Any , Dict , List , Set , Tuple
1718# ---------------------------------------------------------------------------
1819# Locate spec files via CLOUD_REPO_PATH in .env
1920# ---------------------------------------------------------------------------
20- _SDK_REPO = Path (__file__ ).resolve ().parents [2 ] # browser-use-python/tests -> sdk repo root
21+ _SDK_REPO = (
22+ Path (__file__ ).resolve ().parents [2 ]
23+ ) # browser-use-python/tests -> sdk repo root
2124
2225
2326def _get_cloud_repo_path () -> Path :
27+ if env_path := os .environ .get ("CLOUD_REPO_PATH" ):
28+ return Path (env_path )
29+
2430 env_file = _SDK_REPO / ".env"
2531 for line in env_file .read_text ().splitlines ():
2632 line = line .strip ()
@@ -89,7 +95,10 @@ def _load_spec(path: Path) -> Dict[str, Any]:
8995 ("post" , "/skills/{skill_id}/refine" ): ("skills" , "refine" ),
9096 ("post" , "/skills/{skill_id}/rollback" ): ("skills" , "rollback" ),
9197 ("get" , "/skills/{skill_id}/executions" ): ("skills" , "executions" ),
92- ("get" , "/skills/{skill_id}/executions/{execution_id}/output" ): ("skills" , "execution_output" ),
98+ ("get" , "/skills/{skill_id}/executions/{execution_id}/output" ): (
99+ "skills" ,
100+ "execution_output" ,
101+ ),
93102 # marketplace
94103 ("get" , "/marketplace/skills" ): ("marketplace" , "list" ),
95104 ("get" , "/marketplace/skills/{skill_slug}" ): ("marketplace" , "get" ),
@@ -158,10 +167,6 @@ def test_all_spec_endpoints_mapped(self) -> None:
158167 assert not missing , f"Unmapped v2 endpoints: { missing } "
159168
160169 def test_sdk_methods_exist (self ) -> None :
161- from browser_use_sdk .v2 .client import BrowserUse
162-
163- client = BrowserUse .__new__ (BrowserUse )
164- # Manually set up resource stubs so we can inspect
165170 from browser_use_sdk .v2 import resources
166171
167172 for resource_attr , method_name in _V2_MAP .values ():
@@ -181,9 +186,7 @@ def test_sdk_methods_exist(self) -> None:
181186 f"{ cls .__name__ } missing method '{ method_name } '"
182187 )
183188 method = getattr (cls , method_name )
184- assert callable (method ), (
185- f"{ cls .__name__ } .{ method_name } is not callable"
186- )
189+ assert callable (method ), f"{ cls .__name__ } .{ method_name } is not callable"
187190
188191 def test_async_sdk_methods_exist (self ) -> None :
189192 from browser_use_sdk .v2 import resources
@@ -221,7 +224,13 @@ def test_all_spec_endpoints_mapped(self) -> None:
221224 assert not missing , f"Unmapped v3 endpoints: { missing } "
222225
223226 def test_sdk_methods_exist (self ) -> None :
224- from browser_use_sdk .v3 .resources import billing , browsers , profiles , sessions , workspaces
227+ from browser_use_sdk .v3 .resources import (
228+ billing ,
229+ browsers ,
230+ profiles ,
231+ sessions ,
232+ workspaces ,
233+ )
225234
226235 resource_classes = {
227236 "billing" : billing .Billing ,
@@ -237,7 +246,13 @@ def test_sdk_methods_exist(self) -> None:
237246 )
238247
239248 def test_async_sdk_methods_exist (self ) -> None :
240- from browser_use_sdk .v3 .resources import billing , browsers , profiles , sessions , workspaces
249+ from browser_use_sdk .v3 .resources import (
250+ billing ,
251+ browsers ,
252+ profiles ,
253+ sessions ,
254+ workspaces ,
255+ )
241256
242257 async_classes = {
243258 "billing" : billing .AsyncBilling ,
@@ -302,11 +317,7 @@ def _load(self) -> None:
302317
303318 def _get_query_params (self , method : str , path : str ) -> Set [str ]:
304319 op = self .spec ["paths" ].get (path , {}).get (method , {})
305- return {
306- p ["name" ]
307- for p in op .get ("parameters" , [])
308- if p .get ("in" ) == "query"
309- }
320+ return {p ["name" ] for p in op .get ("parameters" , []) if p .get ("in" ) == "query" }
310321
311322 def _resolve_ref (self , ref : str ) -> Dict [str , Any ]:
312323 parts = ref .lstrip ("#/" ).split ("/" )
@@ -408,10 +419,15 @@ def test_task_action_variants(self) -> None:
408419 if not method_name :
409420 missing .append (f"No SDK method mapping for action '{ action } '" )
410421 continue
411- for label , classes_fn in [("sync" , _get_resource_classes ), ("async" , _get_async_resource_classes )]:
422+ for label , classes_fn in [
423+ ("sync" , _get_resource_classes ),
424+ ("async" , _get_async_resource_classes ),
425+ ]:
412426 cls = classes_fn ()["tasks" ]
413427 if not hasattr (cls , method_name ):
414- missing .append (f"{ cls .__name__ } missing '{ method_name } ' for action '{ action } '" )
428+ missing .append (
429+ f"{ cls .__name__ } missing '{ method_name } ' for action '{ action } '"
430+ )
415431
416432 assert not missing , "Missing action variants:\n " + "\n " .join (missing )
417433
@@ -435,8 +451,14 @@ def test_v2_resources_attached(self) -> None:
435451
436452 client = BrowserUse (api_key = "test-key" )
437453 expected = [
438- "billing" , "tasks" , "sessions" , "files" ,
439- "profiles" , "browsers" , "skills" , "marketplace" ,
454+ "billing" ,
455+ "tasks" ,
456+ "sessions" ,
457+ "files" ,
458+ "profiles" ,
459+ "browsers" ,
460+ "skills" ,
461+ "marketplace" ,
440462 ]
441463 for attr in expected :
442464 assert hasattr (client , attr ), f"BrowserUse missing .{ attr } "
@@ -449,3 +471,35 @@ def test_v3_resources_attached(self) -> None:
449471 assert hasattr (client , "sessions" )
450472 assert hasattr (client , "workspaces" )
451473 client .close ()
474+
475+
476+ class TestV3SessionPayloads :
477+ def test_sessions_create_serializes_auto_heal (self ) -> None :
478+ from browser_use_sdk .v3 .resources .sessions import Sessions
479+
480+ class FakeHttp :
481+ def __init__ (self ) -> None :
482+ self .calls : list [dict [str , Any ]] = []
483+
484+ def request (self , method : str , path : str , * , json = None , params = None ):
485+ self .calls .append (
486+ {"method" : method , "path" : path , "json" : json , "params" : params }
487+ )
488+ return {
489+ "id" : "00000000-0000-0000-0000-000000000001" ,
490+ "status" : "created" ,
491+ "model" : "gemini-3-flash" ,
492+ "createdAt" : "2026-05-26T00:00:00Z" ,
493+ "updatedAt" : "2026-05-26T00:00:00Z" ,
494+ }
495+
496+ http = FakeHttp ()
497+ Sessions (http ).create (
498+ "Fetch https://httpbin.org/anything?item=@{{alpha}}" ,
499+ workspace_id = "00000000-0000-0000-0000-000000000002" ,
500+ cache_script = True ,
501+ auto_heal = False ,
502+ )
503+
504+ assert http .calls [0 ]["json" ]["cacheScript" ] is True
505+ assert http .calls [0 ]["json" ]["autoHeal" ] is False
0 commit comments