1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15- import json
1615from pathlib import Path
1716from types import SimpleNamespace
1817from typing import TYPE_CHECKING , Dict , List , Optional , Pattern , Sequence , Union , cast
3837 HarMode ,
3938 ReducedMotion ,
4039 ServiceWorkersPolicy ,
41- async_readfile ,
4240 locals_to_params ,
4341 make_dirs_for_file ,
44- prepare_record_har_options ,
4542)
46- from playwright ._impl ._network import serialize_headers , to_client_certificates_protocol
4743from playwright ._impl ._page import Page
4844
4945if TYPE_CHECKING : # pragma: no cover
@@ -65,12 +61,41 @@ def __init__(
6561 self ._cr_tracing_path : Optional [str ] = None
6662
6763 self ._contexts : List [BrowserContext ] = []
64+ self ._traces_dir : Optional [str ] = None
65+ self ._channel .on (
66+ "context" ,
67+ lambda context : self ._did_create_context (cast (BrowserContext , context )),
68+ )
6869 self ._channel .on ("close" , lambda _ : self ._on_close ())
6970 self ._close_reason : Optional [str ] = None
7071
7172 def __repr__ (self ) -> str :
7273 return f"<Browser type={ self ._browser_type } version={ self .version } >"
7374
75+ def connect_to_browser_type (
76+ self ,
77+ browser_type : BrowserType ,
78+ traces_dir : Optional [str ] = None ,
79+ ) -> None :
80+ # Note: when using connect(), `browserType` is different from `this.parent`.
81+ # This is why browser type is not wired up in the constructor, and instead this separate method is called later on.
82+ self ._browser_type = browser_type
83+ self ._traces_dir = traces_dir
84+ for context in self ._contexts :
85+ context ._tracing ._traces_dir = traces_dir
86+ browser_type ._playwright .selectors ._contextsForSelectors .append (context )
87+
88+ def _did_create_context (self , context : BrowserContext ) -> None :
89+ context ._browser = self
90+ self ._contexts .append (context )
91+ # Note: when connecting to a browser, initial contexts arrive before `_browserType` is set,
92+ # and will be configured later in `ConnectToBrowserType`.
93+ if self ._browser_type :
94+ context ._tracing ._traces_dir = self ._traces_dir
95+ self ._browser_type ._playwright .selectors ._contextsForSelectors .append (
96+ context
97+ )
98+
7499 def _on_close (self ) -> None :
75100 self ._is_connected = False
76101 self .emit (Browser .Events .Disconnected , self )
@@ -126,11 +151,19 @@ async def new_context(
126151 clientCertificates : List [ClientCertificate ] = None ,
127152 ) -> BrowserContext :
128153 params = locals_to_params (locals ())
129- await prepare_browser_context_params (params )
154+ await self . _browser_type . prepare_browser_context_params (params )
130155
131156 channel = await self ._channel .send ("newContext" , params )
132157 context = cast (BrowserContext , from_channel (channel ))
133- self ._browser_type ._did_create_context (context , params , {})
158+ await context .initialize_har_from_options (
159+ {
160+ "recordHarPath" : recordHarPath ,
161+ "recordHarContent" : recordHarContent ,
162+ "recordHarOmitContent" : recordHarOmitContent ,
163+ "recordHarUrlFilter" : recordHarUrlFilter ,
164+ "recordHarMode" : recordHarMode ,
165+ }
166+ )
134167 return context
135168
136169 async def new_page (
@@ -181,6 +214,7 @@ async def inner() -> Page:
181214 context ._owner_page = page
182215 return page
183216
217+ # TODO: Args
184218 return await self ._connection .wrap_api_call (inner )
185219
186220 async def close (self , reason : str = None ) -> None :
@@ -226,43 +260,3 @@ async def stop_tracing(self) -> bytes:
226260 f .write (buffer )
227261 self ._cr_tracing_path = None
228262 return buffer
229-
230-
231- async def prepare_browser_context_params (params : Dict ) -> None :
232- if params .get ("noViewport" ):
233- del params ["noViewport" ]
234- params ["noDefaultViewport" ] = True
235- if "defaultBrowserType" in params :
236- del params ["defaultBrowserType" ]
237- if "extraHTTPHeaders" in params :
238- params ["extraHTTPHeaders" ] = serialize_headers (params ["extraHTTPHeaders" ])
239- if "recordHarPath" in params :
240- params ["recordHar" ] = prepare_record_har_options (params )
241- del params ["recordHarPath" ]
242- if "recordVideoDir" in params :
243- params ["recordVideo" ] = {"dir" : Path (params ["recordVideoDir" ]).absolute ()}
244- if "recordVideoSize" in params :
245- params ["recordVideo" ]["size" ] = params ["recordVideoSize" ]
246- del params ["recordVideoSize" ]
247- del params ["recordVideoDir" ]
248- if "storageState" in params :
249- storageState = params ["storageState" ]
250- if not isinstance (storageState , dict ):
251- params ["storageState" ] = json .loads (
252- (await async_readfile (storageState )).decode ()
253- )
254- if params .get ("colorScheme" , None ) == "null" :
255- params ["colorScheme" ] = "no-override"
256- if params .get ("reducedMotion" , None ) == "null" :
257- params ["reducedMotion" ] = "no-override"
258- if params .get ("forcedColors" , None ) == "null" :
259- params ["forcedColors" ] = "no-override"
260- if params .get ("contrast" , None ) == "null" :
261- params ["contrast" ] = "no-override"
262- if "acceptDownloads" in params :
263- params ["acceptDownloads" ] = "accept" if params ["acceptDownloads" ] else "deny"
264-
265- if "clientCertificates" in params :
266- params ["clientCertificates" ] = await to_client_certificates_protocol (
267- params ["clientCertificates" ]
268- )
0 commit comments