Skip to content

Commit b846cee

Browse files
authored
chore: roll to 1.60.0-beta-1778142790000 (#3069)
1 parent 873c5c7 commit b846cee

36 files changed

Lines changed: 2194 additions & 226 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H
44

55
| | Linux | macOS | Windows |
66
| :--- | :---: | :---: | :---: |
7-
| Chromium <!-- GEN:chromium-version -->147.0.7727.15<!-- GEN:stop --> ||||
7+
| Chromium <!-- GEN:chromium-version -->148.0.7778.96<!-- GEN:stop --> ||||
88
| WebKit <!-- GEN:webkit-version -->26.4<!-- GEN:stop --> ||||
9-
| Firefox <!-- GEN:firefox-version -->148.0.2<!-- GEN:stop --> ||||
9+
| Firefox <!-- GEN:firefox-version -->150.0.2<!-- GEN:stop --> ||||
1010

1111
## Documentation
1212

playwright/_impl/_api_structures.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,31 @@ class ViewportSize(TypedDict):
151151

152152
class SourceLocation(TypedDict):
153153
url: str
154+
line: int
155+
column: int
154156
lineNumber: int
155157
columnNumber: int
156158

157159

160+
class WebErrorLocation(TypedDict):
161+
url: str
162+
line: int
163+
column: int
164+
165+
158166
class FilePayload(TypedDict):
159167
name: str
160168
mimeType: str
161169
buffer: bytes
162170

163171

172+
class DropPayload(TypedDict, total=False):
173+
files: Optional[
174+
Union[str, Path, FilePayload, Sequence[Union[str, Path]], Sequence[FilePayload]]
175+
]
176+
data: Optional[Dict[str, str]]
177+
178+
164179
class RemoteAddr(TypedDict):
165180
ipAddress: str
166181
port: int
@@ -216,6 +231,7 @@ class FrameExpectOptions(TypedDict, total=False):
216231
useInnerText: Optional[bool]
217232
isNot: bool
218233
timeout: Optional[float]
234+
pseudo: Optional[str]
219235

220236

221237
class FrameExpectResult(TypedDict):
@@ -330,3 +346,5 @@ class DebuggerPausedDetails(TypedDict):
330346

331347
class ScreencastFrame(TypedDict):
332348
data: bytes
349+
viewportWidth: int
350+
viewportHeight: int

playwright/_impl/_assertions.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515
import collections.abc
16-
from typing import Any, List, Optional, Pattern, Sequence, Union
16+
from typing import Any, List, Literal, Optional, Pattern, Sequence, Union
1717
from urllib.parse import urljoin
1818

1919
from playwright._impl._api_structures import (
@@ -26,6 +26,7 @@
2626
from playwright._impl._errors import Error
2727
from playwright._impl._fetch import APIResponse
2828
from playwright._impl._helper import is_textual_mime_type
29+
from playwright._impl._js_handle import parse_value
2930
from playwright._impl._locator import Locator
3031
from playwright._impl._page import Page
3132
from playwright._impl._str_utils import escape_regex_flags
@@ -71,7 +72,14 @@ async def _expect_impl(
7172
del expect_options["useInnerText"]
7273
result = await self._call_expect(expression, expect_options, title)
7374
if result["matches"] == self._is_not:
74-
actual = result.get("received")
75+
received = result.get("received") or {}
76+
if isinstance(received, dict):
77+
if "value" in received and received["value"] is not None:
78+
actual = parse_value(received["value"])
79+
else:
80+
actual = received.get("ariaSnapshot")
81+
else:
82+
actual = received
7583
if self._custom_message:
7684
out_message = self._custom_message
7785
if expected is not None:
@@ -161,6 +169,24 @@ async def not_to_have_url(
161169
__tracebackhide__ = True
162170
await self._not.to_have_url(urlOrRegExp, timeout, ignoreCase)
163171

172+
async def to_match_aria_snapshot(
173+
self, expected: str, timeout: float = None
174+
) -> None:
175+
__tracebackhide__ = True
176+
await self._expect_impl(
177+
"to.match.aria",
178+
FrameExpectOptions(expectedValue=expected, timeout=timeout),
179+
expected,
180+
"Page expected to match Aria snapshot",
181+
'Expect "to_match_aria_snapshot"',
182+
)
183+
184+
async def not_to_match_aria_snapshot(
185+
self, expected: str, timeout: float = None
186+
) -> None:
187+
__tracebackhide__ = True
188+
await self._not.to_match_aria_snapshot(expected, timeout)
189+
164190

165191
class LocatorAssertions(AssertionsBase):
166192
def __init__(
@@ -400,13 +426,17 @@ async def to_have_css(
400426
name: str,
401427
value: Union[str, Pattern[str]],
402428
timeout: float = None,
429+
pseudo: Literal["after", "before"] = None,
403430
) -> None:
404431
__tracebackhide__ = True
405432
expected_text = to_expected_text_values([value])
406433
await self._expect_impl(
407434
"to.have.css",
408435
FrameExpectOptions(
409-
expressionArg=name, expectedText=expected_text, timeout=timeout
436+
expressionArg=name,
437+
expectedText=expected_text,
438+
timeout=timeout,
439+
pseudo=pseudo,
410440
),
411441
value,
412442
"Locator expected to have CSS",

playwright/_impl/_browser.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959

6060
class Browser(ChannelOwner):
6161
Events = SimpleNamespace(
62+
Context="context",
6263
Disconnected="disconnected",
6364
)
6465

@@ -104,6 +105,7 @@ def _did_create_context(self, context: BrowserContext) -> None:
104105
# and will be configured later in `ConnectToBrowserType`.
105106
if self._browser_type:
106107
self._setup_browser_context(context)
108+
self.emit(Browser.Events.Context, context)
107109

108110
def _setup_browser_context(self, context: BrowserContext) -> None:
109111
context._tracing._traces_dir = self._traces_dir

playwright/_impl/_browser_context.py

Lines changed: 20 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
Geolocation,
3737
SetCookieParam,
3838
StorageState,
39+
WebErrorLocation,
3940
)
40-
from playwright._impl._artifact import Artifact
4141
from playwright._impl._cdp_session import CDPSession
4242
from playwright._impl._clock import Clock
4343
from playwright._impl._connection import (
@@ -57,7 +57,6 @@
5757
from playwright._impl._helper import (
5858
HarContentPolicy,
5959
HarMode,
60-
HarRecordingMetadata,
6160
RouteFromHarNotFoundPolicy,
6261
RouteHandler,
6362
RouteHandlerCallback,
@@ -95,7 +94,13 @@ class BrowserContext(ChannelOwner):
9594
Close="close",
9695
Console="console",
9796
Dialog="dialog",
97+
Download="download",
98+
FrameAttached="frameattached",
99+
FrameDetached="framedetached",
100+
FrameNavigated="framenavigated",
98101
Page="page",
102+
PageClose="pageclose",
103+
PageLoad="pageload",
99104
WebError="weberror",
100105
ServiceWorker="serviceworker",
101106
Request="request",
@@ -125,7 +130,6 @@ def __init__(
125130
self._videos_dir: Optional[str] = self._options.get("recordVideo")
126131
self._tracing = cast(Tracing, from_channel(initializer["tracing"]))
127132
self._debugger: Debugger = cast(Debugger, from_channel(initializer["debugger"]))
128-
self._har_recorders: Dict[str, HarRecordingMetadata] = {}
129133
self._request: APIRequestContext = from_channel(initializer["requestContext"])
130134
self._request._timeout_settings = self._timeout_settings
131135
self._clock = Clock(self)
@@ -171,6 +175,10 @@ def __init__(
171175
lambda params: self._on_page_error(
172176
parse_error(params["error"]["error"]),
173177
from_nullable_channel(params["page"]),
178+
cast(
179+
WebErrorLocation,
180+
params.get("location") or {"url": "", "line": 0, "column": 0},
181+
),
174182
),
175183
)
176184
self._channel.on(
@@ -321,7 +329,7 @@ async def _initialize_har_from_options(
321329
content_policy: HarContentPolicy = record_har_content or (
322330
"omit" if record_har_omit_content is True else default_policy
323331
)
324-
await self._record_into_har(
332+
await self._tracing._record_into_har(
325333
har=record_har_path,
326334
page=None,
327335
url=record_har_url_filter,
@@ -404,9 +412,7 @@ async def add_init_script(
404412
await self._channel.send("addInitScript", None, dict(source=script))
405413
)
406414

407-
async def expose_binding(
408-
self, name: str, callback: Callable, handle: bool = None
409-
) -> Disposable:
415+
async def expose_binding(self, name: str, callback: Callable) -> Disposable:
410416
for page in self._pages:
411417
if name in page._bindings:
412418
raise Error(
@@ -416,9 +422,7 @@ async def expose_binding(
416422
raise Error(f'Function "{name}" has been already registered')
417423
self._bindings[name] = callback
418424
return from_channel(
419-
await self._channel.send(
420-
"exposeBinding", None, dict(name=name, needsHandle=handle or False)
421-
)
425+
await self._channel.send("exposeBinding", None, dict(name=name))
422426
)
423427

424428
async def expose_function(self, name: str, callback: Callable) -> Disposable:
@@ -483,35 +487,6 @@ async def unroute_all(
483487
await self._unroute_internal(self._routes, [], behavior)
484488
self._dispose_har_routers()
485489

486-
async def _record_into_har(
487-
self,
488-
har: Union[Path, str],
489-
page: Optional[Page] = None,
490-
url: Union[Pattern[str], str] = None,
491-
update_content: HarContentPolicy = None,
492-
update_mode: HarMode = None,
493-
) -> None:
494-
update_content = update_content or "attach"
495-
params: Dict[str, Any] = {
496-
"options": {
497-
"zip": str(har).endswith(".zip"),
498-
"content": update_content,
499-
"urlGlob": url if isinstance(url, str) else None,
500-
"urlRegexSource": url.pattern if isinstance(url, Pattern) else None,
501-
"urlRegexFlags": (
502-
escape_regex_flags(url) if isinstance(url, Pattern) else None
503-
),
504-
"mode": update_mode or "minimal",
505-
}
506-
}
507-
if page:
508-
params["page"] = page._channel
509-
har_id = await self._channel.send("harStart", None, params)
510-
self._har_recorders[har_id] = {
511-
"path": str(har),
512-
"content": update_content,
513-
}
514-
515490
async def route_from_har(
516491
self,
517492
har: Union[Path, str],
@@ -522,7 +497,7 @@ async def route_from_har(
522497
updateMode: HarMode = None,
523498
) -> None:
524499
if update:
525-
await self._record_into_har(
500+
await self._tracing._record_into_har(
526501
har=har,
527502
page=None,
528503
url=url,
@@ -602,27 +577,7 @@ async def close(self, reason: str = None) -> None:
602577
await self.request.dispose(reason=reason)
603578

604579
async def _inner_close() -> None:
605-
for har_id, params in self._har_recorders.items():
606-
har = cast(
607-
Artifact,
608-
from_channel(
609-
await self._channel.send("harExport", None, {"harId": har_id})
610-
),
611-
)
612-
# Server side will compress artifact if content is attach or if file is .zip.
613-
is_compressed = params.get("content") == "attach" or params[
614-
"path"
615-
].endswith(".zip")
616-
need_compressed = params["path"].endswith(".zip")
617-
if is_compressed and not need_compressed:
618-
tmp_path = params["path"] + ".tmp"
619-
await har.save_as(tmp_path)
620-
await self._connection.local_utils.har_unzip(
621-
zipFile=tmp_path, harFile=params["path"]
622-
)
623-
else:
624-
await har.save_as(params["path"])
625-
await har.delete()
580+
await self._tracing._export_all_hars()
626581

627582
await self._channel._connection.wrap_api_call(_inner_close, True)
628583
await self._channel.send("close", None, {"reason": reason})
@@ -732,10 +687,12 @@ def _on_dialog(self, dialog: Dialog) -> None:
732687
else:
733688
asyncio.create_task(dialog.dismiss())
734689

735-
def _on_page_error(self, error: Error, page: Optional[Page]) -> None:
690+
def _on_page_error(
691+
self, error: Error, page: Optional[Page], location: WebErrorLocation
692+
) -> None:
736693
self.emit(
737694
BrowserContext.Events.WebError,
738-
WebError(self._loop, self._dispatcher_fiber, page, error),
695+
WebError(self._loop, self._dispatcher_fiber, page, error, location),
739696
)
740697
if page:
741698
page.emit(Page.Events.PageError, error)

playwright/_impl/_browser_type.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ async def connect_over_cdp(
201201
slowMo: float = None,
202202
headers: Dict[str, str] = None,
203203
isLocal: bool = None,
204+
noDefaults: bool = None,
204205
) -> Browser:
205206
params = locals_to_params(locals())
206207
if params.get("headers"):

playwright/_impl/_console_message.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,16 @@ def args(self) -> List[JSHandle]:
7474

7575
@property
7676
def location(self) -> SourceLocation:
77-
return self._event["location"]
77+
# Wire format uses `lineNumber`/`columnNumber`; docs expose both `line`/`column`
78+
# (legacy) and `lineNumber`/`columnNumber` (added upstream in 1.60).
79+
loc = self._event["location"]
80+
return {
81+
"url": loc["url"],
82+
"line": loc["lineNumber"],
83+
"column": loc["columnNumber"],
84+
"lineNumber": loc["lineNumber"],
85+
"columnNumber": loc["columnNumber"],
86+
}
7887

7988
@property
8089
def timestamp(self) -> float:

playwright/_impl/_fetch.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def __init__(
110110

111111
async def dispose(self, reason: str = None) -> None:
112112
self._close_reason = reason
113+
await self._tracing._export_all_hars()
113114
try:
114115
await self._channel.send("dispose", None, {"reason": reason})
115116
except Error as e:
@@ -118,6 +119,10 @@ async def dispose(self, reason: str = None) -> None:
118119
raise e
119120
self._tracing._reset_stack_counter()
120121

122+
@property
123+
def tracing(self) -> Tracing:
124+
return self._tracing
125+
121126
async def delete(
122127
self,
123128
url: str,

0 commit comments

Comments
 (0)