Skip to content

Commit a45cb4c

Browse files
authored
chore(roll): roll Playwright to 1.34.0-alpha-may-17-2023 (#1924)
1 parent 177855e commit a45cb4c

17 files changed

+750
-77
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H
66
| :--- | :---: | :---: | :---: |
77
| Chromium <!-- GEN:chromium-version -->113.0.5672.53<!-- GEN:stop --> ||||
88
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> ||||
9-
| Firefox <!-- GEN:firefox-version -->112.0<!-- GEN:stop --> ||||
9+
| Firefox <!-- GEN:firefox-version -->113.0<!-- GEN:stop --> ||||
1010

1111
## Documentation
1212

playwright/_impl/_browser.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,15 @@ async def new_page(
167167
recordHarContent: HarContentPolicy = None,
168168
) -> Page:
169169
params = locals_to_params(locals())
170-
context = await self.new_context(**params)
171-
page = await context.new_page()
172-
page._owned_context = context
173-
context._owner_page = page
174-
return page
170+
171+
async def inner() -> Page:
172+
context = await self.new_context(**params)
173+
page = await context.new_page()
174+
page._owned_context = context
175+
context._owner_page = page
176+
return page
177+
178+
return await self._connection.wrap_api_call(inner)
175179

176180
async def close(self) -> None:
177181
if self._is_closed_or_closing:

playwright/_impl/_browser_context.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
from_channel,
4545
from_nullable_channel,
4646
)
47+
from playwright._impl._console_message import ConsoleMessage
48+
from playwright._impl._dialog import Dialog
4749
from playwright._impl._event_context_manager import EventContextManagerImpl
4850
from playwright._impl._fetch import APIRequestContext
4951
from playwright._impl._frame import Frame
@@ -82,6 +84,8 @@ class BrowserContext(ChannelOwner):
8284
Events = SimpleNamespace(
8385
BackgroundPage="backgroundpage",
8486
Close="close",
87+
Console="console",
88+
Dialog="dialog",
8589
Page="page",
8690
ServiceWorker="serviceworker",
8791
Request="request",
@@ -136,6 +140,14 @@ def __init__(
136140
"serviceWorker",
137141
lambda params: self._on_service_worker(from_channel(params["worker"])),
138142
)
143+
self._channel.on(
144+
"console",
145+
lambda params: self._on_console_message(from_channel(params["message"])),
146+
)
147+
148+
self._channel.on(
149+
"dialog", lambda params: self._on_dialog(from_channel(params["dialog"]))
150+
)
139151
self._channel.on(
140152
"request",
141153
lambda params: self._on_request(
@@ -174,6 +186,8 @@ def __init__(
174186
)
175187
self._set_event_to_subscription_mapping(
176188
{
189+
BrowserContext.Events.Console: "console",
190+
BrowserContext.Events.Dialog: "dialog",
177191
BrowserContext.Events.Request: "request",
178192
BrowserContext.Events.Response: "response",
179193
BrowserContext.Events.RequestFinished: "requestFinished",
@@ -507,6 +521,27 @@ def _on_request_finished(
507521
if response:
508522
response._finished_future.set_result(True)
509523

524+
def _on_console_message(self, message: ConsoleMessage) -> None:
525+
self.emit(BrowserContext.Events.Console, message)
526+
page = message.page
527+
if page:
528+
page.emit(Page.Events.Console, message)
529+
530+
def _on_dialog(self, dialog: Dialog) -> None:
531+
has_listeners = self.emit(BrowserContext.Events.Dialog, dialog)
532+
page = dialog.page
533+
if page:
534+
has_listeners = page.emit(Page.Events.Dialog, dialog) or has_listeners
535+
if not has_listeners:
536+
# Although we do similar handling on the server side, we still need this logic
537+
# on the client side due to a possible race condition between two async calls:
538+
# a) removing "dialog" listener subscription (client->server)
539+
# b) actual "dialog" event (server->client)
540+
if dialog.type == "beforeunload":
541+
asyncio.create_task(dialog.accept())
542+
else:
543+
asyncio.create_task(dialog.dismiss())
544+
510545
def _on_request(self, request: Request, page: Optional[Page]) -> None:
511546
self.emit(BrowserContext.Events.Request, request)
512547
if page:

playwright/_impl/_connection.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,11 @@ def _set_event_to_subscription_mapping(self, mapping: Dict[str, str]) -> None:
161161
def _update_subscription(self, event: str, enabled: bool) -> None:
162162
protocol_event = self._event_to_subscription_mapping.get(event)
163163
if protocol_event:
164-
self._channel.send_no_reply(
165-
"updateSubscription", {"event": protocol_event, "enabled": enabled}
164+
self._connection.wrap_api_call_sync(
165+
lambda: self._channel.send_no_reply(
166+
"updateSubscription", {"event": protocol_event, "enabled": enabled}
167+
),
168+
True,
166169
)
167170

168171
def _add_event_handler(self, event: str, k: Any, v: Any) -> None:

playwright/_impl/_console_message.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,29 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Dict, List
15+
from typing import TYPE_CHECKING, Dict, List, Optional
1616

1717
from playwright._impl._api_structures import SourceLocation
18-
from playwright._impl._connection import ChannelOwner, from_channel
18+
from playwright._impl._connection import (
19+
ChannelOwner,
20+
from_channel,
21+
from_nullable_channel,
22+
)
1923
from playwright._impl._js_handle import JSHandle
2024

25+
if TYPE_CHECKING: # pragma: no cover
26+
from playwright._impl._page import Page
27+
2128

2229
class ConsoleMessage(ChannelOwner):
2330
def __init__(
2431
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
2532
) -> None:
2633
super().__init__(parent, type, guid, initializer)
34+
# Note: currently, we only report console messages for pages and they always have a page.
35+
# However, in the future we might report console messages for service workers or something else,
36+
# where page() would be null.
37+
self._page: Optional["Page"] = from_nullable_channel(initializer.get("page"))
2738

2839
def __repr__(self) -> str:
2940
return f"<ConsoleMessage type={self.type} text={self.text}>"
@@ -46,3 +57,7 @@ def args(self) -> List[JSHandle]:
4657
@property
4758
def location(self) -> SourceLocation:
4859
return self._initializer["location"]
60+
61+
@property
62+
def page(self) -> Optional["Page"]:
63+
return self._page

playwright/_impl/_dialog.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,21 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Dict
15+
from typing import TYPE_CHECKING, Dict, Optional
1616

17-
from playwright._impl._connection import ChannelOwner
17+
from playwright._impl._connection import ChannelOwner, from_nullable_channel
1818
from playwright._impl._helper import locals_to_params
1919

20+
if TYPE_CHECKING: # pragma: no cover
21+
from playwright._impl._page import Page
22+
2023

2124
class Dialog(ChannelOwner):
2225
def __init__(
2326
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
2427
) -> None:
2528
super().__init__(parent, type, guid, initializer)
29+
self._page: Optional["Page"] = from_nullable_channel(initializer.get("page"))
2630

2731
def __repr__(self) -> str:
2832
return f"<Dialog type={self.type} message={self.message} default_value={self.default_value}>"
@@ -39,6 +43,10 @@ def message(self) -> str:
3943
def default_value(self) -> str:
4044
return self._initializer["defaultValue"]
4145

46+
@property
47+
def page(self) -> Optional["Page"]:
48+
return self._page
49+
4250
async def accept(self, promptText: str = None) -> None:
4351
await self._channel.send("accept", locals_to_params(locals()))
4452

playwright/_impl/_locator.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,14 @@ def or_(self, locator: "Locator") -> "Locator":
356356
self._selector + " >> internal:or=" + json.dumps(locator._selector),
357357
)
358358

359+
def and_(self, locator: "Locator") -> "Locator":
360+
if locator._frame != self._frame:
361+
raise Error("Locators must belong to the same frame.")
362+
return Locator(
363+
self._frame,
364+
self._selector + " >> internal:and=" + json.dumps(locator._selector),
365+
)
366+
359367
async def focus(self, timeout: float = None) -> None:
360368
params = locals_to_params(locals())
361369
return await self._frame.focus(self._selector, strict=True, **params)

playwright/_impl/_page.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
from_nullable_channel,
4949
)
5050
from playwright._impl._console_message import ConsoleMessage
51-
from playwright._impl._dialog import Dialog
5251
from playwright._impl._download import Download
5352
from playwright._impl._element_handle import ElementHandle
5453
from playwright._impl._event_context_manager import EventContextManagerImpl
@@ -159,14 +158,7 @@ def __init__(
159158
lambda params: self._on_binding(from_channel(params["binding"])),
160159
)
161160
self._channel.on("close", lambda _: self._on_close())
162-
self._channel.on(
163-
"console",
164-
lambda params: self.emit(
165-
Page.Events.Console, from_channel(params["message"])
166-
),
167-
)
168161
self._channel.on("crash", lambda _: self._on_crash())
169-
self._channel.on("dialog", lambda params: self._on_dialog(params))
170162
self._channel.on("download", lambda params: self._on_download(params))
171163
self._channel.on(
172164
"fileChooser",
@@ -223,6 +215,8 @@ def __init__(
223215

224216
self._set_event_to_subscription_mapping(
225217
{
218+
Page.Events.Console: "console",
219+
Page.Events.Dialog: "dialog",
226220
Page.Events.Request: "request",
227221
Page.Events.Response: "response",
228222
Page.Events.RequestFinished: "requestFinished",
@@ -286,16 +280,6 @@ def _on_close(self) -> None:
286280
def _on_crash(self) -> None:
287281
self.emit(Page.Events.Crash, self)
288282

289-
def _on_dialog(self, params: Any) -> None:
290-
dialog = cast(Dialog, from_channel(params["dialog"]))
291-
if self.listeners(Page.Events.Dialog):
292-
self.emit(Page.Events.Dialog, dialog)
293-
else:
294-
if dialog.type == "beforeunload":
295-
asyncio.create_task(dialog.accept())
296-
else:
297-
asyncio.create_task(dialog.dismiss())
298-
299283
def _on_download(self, params: Any) -> None:
300284
url = params["url"]
301285
suggested_filename = params["suggestedFilename"]

0 commit comments

Comments
 (0)