playwright-browserstack 1.62.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- playwright/__init__.py +19 -0
- playwright/__main__.py +33 -0
- playwright/_impl/__init__.py +0 -0
- playwright/_impl/__pyinstaller/__init__.py +20 -0
- playwright/_impl/__pyinstaller/hook-playwright.async_api.py +17 -0
- playwright/_impl/__pyinstaller/hook-playwright.sync_api.py +17 -0
- playwright/_impl/_android.py +704 -0
- playwright/_impl/_api_structures.py +365 -0
- playwright/_impl/_artifact.py +87 -0
- playwright/_impl/_assertions.py +1124 -0
- playwright/_impl/_async_base.py +105 -0
- playwright/_impl/_browser.py +293 -0
- playwright/_impl/_browser_context.py +754 -0
- playwright/_impl/_browser_type.py +368 -0
- playwright/_impl/_cdp_session.py +46 -0
- playwright/_impl/_clock.py +104 -0
- playwright/_impl/_connection.py +764 -0
- playwright/_impl/_console_message.py +98 -0
- playwright/_impl/_credentials.py +57 -0
- playwright/_impl/_debugger.py +54 -0
- playwright/_impl/_dialog.py +63 -0
- playwright/_impl/_disposable.py +96 -0
- playwright/_impl/_download.py +64 -0
- playwright/_impl/_driver.py +41 -0
- playwright/_impl/_element_handle.py +480 -0
- playwright/_impl/_errors.py +64 -0
- playwright/_impl/_event_context_manager.py +33 -0
- playwright/_impl/_fetch.py +626 -0
- playwright/_impl/_file_chooser.py +57 -0
- playwright/_impl/_form_data.py +34 -0
- playwright/_impl/_frame.py +985 -0
- playwright/_impl/_glob.py +65 -0
- playwright/_impl/_greenlets.py +49 -0
- playwright/_impl/_har_router.py +122 -0
- playwright/_impl/_helper.py +601 -0
- playwright/_impl/_impl_to_api_mapping.py +158 -0
- playwright/_impl/_input.py +111 -0
- playwright/_impl/_js_handle.py +336 -0
- playwright/_impl/_json_pipe.py +97 -0
- playwright/_impl/_local_utils.py +95 -0
- playwright/_impl/_locator.py +1024 -0
- playwright/_impl/_map.py +31 -0
- playwright/_impl/_network.py +1017 -0
- playwright/_impl/_object_factory.py +116 -0
- playwright/_impl/_page.py +1637 -0
- playwright/_impl/_path_utils.py +27 -0
- playwright/_impl/_playwright.py +68 -0
- playwright/_impl/_screencast.py +177 -0
- playwright/_impl/_selectors.py +67 -0
- playwright/_impl/_set_input_files_helpers.py +158 -0
- playwright/_impl/_str_utils.py +76 -0
- playwright/_impl/_stream.py +46 -0
- playwright/_impl/_sync_base.py +151 -0
- playwright/_impl/_tracing.py +281 -0
- playwright/_impl/_transport.py +184 -0
- playwright/_impl/_video.py +56 -0
- playwright/_impl/_waiter.py +197 -0
- playwright/_impl/_web_error.py +48 -0
- playwright/_impl/_web_storage.py +58 -0
- playwright/_impl/_writable_stream.py +42 -0
- playwright/_repo_version.py +24 -0
- playwright/async_api/__init__.py +275 -0
- playwright/async_api/_android_generated.py +462 -0
- playwright/async_api/_context_manager.py +57 -0
- playwright/async_api/_generated.py +23875 -0
- playwright/driver/LICENSE +2946 -0
- playwright/driver/README.md +1 -0
- playwright/driver/node.exe +0 -0
- playwright/driver/package/LICENSE +202 -0
- playwright/driver/package/NOTICE +5 -0
- playwright/driver/package/README.md +3 -0
- playwright/driver/package/ThirdPartyNotices.txt +13 -0
- playwright/driver/package/bin/install_media_pack.ps1 +5 -0
- playwright/driver/package/bin/install_webkit_wsl.ps1 +33 -0
- playwright/driver/package/bin/reinstall_chrome_beta_linux.sh +42 -0
- playwright/driver/package/bin/reinstall_chrome_beta_mac.sh +13 -0
- playwright/driver/package/bin/reinstall_chrome_beta_win.ps1 +24 -0
- playwright/driver/package/bin/reinstall_chrome_stable_linux.sh +42 -0
- playwright/driver/package/bin/reinstall_chrome_stable_mac.sh +12 -0
- playwright/driver/package/bin/reinstall_chrome_stable_win.ps1 +24 -0
- playwright/driver/package/bin/reinstall_msedge_beta_linux.sh +48 -0
- playwright/driver/package/bin/reinstall_msedge_beta_mac.sh +11 -0
- playwright/driver/package/bin/reinstall_msedge_beta_win.ps1 +23 -0
- playwright/driver/package/bin/reinstall_msedge_dev_linux.sh +48 -0
- playwright/driver/package/bin/reinstall_msedge_dev_mac.sh +11 -0
- playwright/driver/package/bin/reinstall_msedge_dev_win.ps1 +23 -0
- playwright/driver/package/bin/reinstall_msedge_stable_linux.sh +48 -0
- playwright/driver/package/bin/reinstall_msedge_stable_mac.sh +11 -0
- playwright/driver/package/bin/reinstall_msedge_stable_win.ps1 +24 -0
- playwright/driver/package/browsers.json +75 -0
- playwright/driver/package/cli.js +21 -0
- playwright/driver/package/index.d.ts +17 -0
- playwright/driver/package/index.js +17 -0
- playwright/driver/package/index.mjs +28 -0
- playwright/driver/package/lib/bootstrap.js +88 -0
- playwright/driver/package/lib/coreBundle.js +74830 -0
- playwright/driver/package/lib/entry/cliDaemon.js +5 -0
- playwright/driver/package/lib/entry/dashboardApp.js +3 -0
- playwright/driver/package/lib/entry/mcp.js +10 -0
- playwright/driver/package/lib/entry/oopBrowserDownload.js +3 -0
- playwright/driver/package/lib/package.js +50 -0
- playwright/driver/package/lib/server/chromium/appIcon.png +0 -0
- playwright/driver/package/lib/server/electron/loader.js +118 -0
- playwright/driver/package/lib/serverRegistry.js +7347 -0
- playwright/driver/package/lib/serverRegistry.js.LICENSE +354 -0
- playwright/driver/package/lib/tools/cli-client/channelSessions.js +141 -0
- playwright/driver/package/lib/tools/cli-client/cli.js +6 -0
- playwright/driver/package/lib/tools/cli-client/help.json +708 -0
- playwright/driver/package/lib/tools/cli-client/minimist.js +128 -0
- playwright/driver/package/lib/tools/cli-client/output.js +343 -0
- playwright/driver/package/lib/tools/cli-client/program.js +404 -0
- playwright/driver/package/lib/tools/cli-client/registry.js +176 -0
- playwright/driver/package/lib/tools/cli-client/session.js +258 -0
- playwright/driver/package/lib/tools/dashboard/appIcon.png +0 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/SKILL.md +420 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
- playwright/driver/package/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/SKILL.md +143 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/migration.md +85 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/react.md +67 -0
- playwright/driver/package/lib/tools/skills/playwright-component-testing/references/vue.md +75 -0
- playwright/driver/package/lib/tools/skills/playwright-trace/SKILL.md +171 -0
- playwright/driver/package/lib/tools/utils/extension.js +101 -0
- playwright/driver/package/lib/tools/utils/socketConnection.js +108 -0
- playwright/driver/package/lib/utilsBundle.js +90764 -0
- playwright/driver/package/lib/utilsBundle.js.LICENSE +2179 -0
- playwright/driver/package/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
- playwright/driver/package/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/index-CyWAfh-p.js +11 -0
- playwright/driver/package/lib/vite/dashboard/assets/index-DhC616m4.css +1 -0
- playwright/driver/package/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
- playwright/driver/package/lib/vite/dashboard/index.html +29 -0
- playwright/driver/package/lib/vite/dashboard/playwright-logo.svg +24 -0
- playwright/driver/package/lib/vite/htmlReport/index.html +16 -0
- playwright/driver/package/lib/vite/htmlReport/report.css +2 -0
- playwright/driver/package/lib/vite/htmlReport/report.js +32 -0
- playwright/driver/package/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
- playwright/driver/package/lib/vite/recorder/assets/codeMirrorModule-CwYYHbcZ.js +32 -0
- playwright/driver/package/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
- playwright/driver/package/lib/vite/recorder/assets/index-DYjdXIbE.js +129 -0
- playwright/driver/package/lib/vite/recorder/assets/index-l_lX622x.css +1 -0
- playwright/driver/package/lib/vite/recorder/index.html +29 -0
- playwright/driver/package/lib/vite/recorder/playwright-logo.svg +9 -0
- playwright/driver/package/lib/vite/traceViewer/assets/codeMirrorModule-By56iMx7.js +32 -0
- playwright/driver/package/lib/vite/traceViewer/assets/defaultSettingsView-B34OrIms.js +181 -0
- playwright/driver/package/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
- playwright/driver/package/lib/vite/traceViewer/assets/xtermModule-COQkjINf.js +7 -0
- playwright/driver/package/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
- playwright/driver/package/lib/vite/traceViewer/defaultSettingsView.BLFoOugd.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/index.Dl36UVQT.js +1 -0
- playwright/driver/package/lib/vite/traceViewer/index.html +44 -0
- playwright/driver/package/lib/vite/traceViewer/manifest.webmanifest +16 -0
- playwright/driver/package/lib/vite/traceViewer/playwright-logo.svg +9 -0
- playwright/driver/package/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
- playwright/driver/package/lib/vite/traceViewer/snapshot.html +10 -0
- playwright/driver/package/lib/vite/traceViewer/sw.bundle.js +4 -0
- playwright/driver/package/lib/vite/traceViewer/uiMode.C7UW1sC9.css +1 -0
- playwright/driver/package/lib/vite/traceViewer/uiMode.D962mr9b.js +5 -0
- playwright/driver/package/lib/vite/traceViewer/uiMode.html +18 -0
- playwright/driver/package/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
- playwright/driver/package/lib/webp_codec.LICENSE +173 -0
- playwright/driver/package/lib/webp_codec.wasm +0 -0
- playwright/driver/package/lib/xdg-open +1267 -0
- playwright/driver/package/package.json +34 -0
- playwright/driver/package/types/protocol.d.ts +24842 -0
- playwright/driver/package/types/structs.d.ts +47 -0
- playwright/driver/package/types/types.d.ts +26188 -0
- playwright/py.typed +0 -0
- playwright/sync_api/__init__.py +275 -0
- playwright/sync_api/_android_generated.py +494 -0
- playwright/sync_api/_context_manager.py +98 -0
- playwright/sync_api/_generated.py +24045 -0
- playwright_browserstack-1.62.0.dist-info/METADATA +82 -0
- playwright_browserstack-1.62.0.dist-info/RECORD +192 -0
- playwright_browserstack-1.62.0.dist-info/WHEEL +5 -0
- playwright_browserstack-1.62.0.dist-info/entry_points.txt +5 -0
- playwright_browserstack-1.62.0.dist-info/licenses/LICENSE +202 -0
- playwright_browserstack-1.62.0.dist-info/licenses/LICENSE.txt +51 -0
- playwright_browserstack-1.62.0.dist-info/licenses/NOTICE +18 -0
- playwright_browserstack-1.62.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1637 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
import base64
|
|
17
|
+
import inspect
|
|
18
|
+
import re
|
|
19
|
+
import sys
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from types import SimpleNamespace
|
|
22
|
+
from typing import (
|
|
23
|
+
TYPE_CHECKING,
|
|
24
|
+
Any,
|
|
25
|
+
Awaitable,
|
|
26
|
+
Callable,
|
|
27
|
+
Dict,
|
|
28
|
+
List,
|
|
29
|
+
Literal,
|
|
30
|
+
Optional,
|
|
31
|
+
Pattern,
|
|
32
|
+
Sequence,
|
|
33
|
+
Union,
|
|
34
|
+
cast,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
from playwright._impl._api_structures import (
|
|
38
|
+
AriaRole,
|
|
39
|
+
FilePayload,
|
|
40
|
+
FloatRect,
|
|
41
|
+
PdfMargins,
|
|
42
|
+
Position,
|
|
43
|
+
ViewportSize,
|
|
44
|
+
)
|
|
45
|
+
from playwright._impl._artifact import Artifact
|
|
46
|
+
from playwright._impl._clock import Clock
|
|
47
|
+
from playwright._impl._connection import (
|
|
48
|
+
ChannelOwner,
|
|
49
|
+
from_channel,
|
|
50
|
+
from_nullable_channel,
|
|
51
|
+
)
|
|
52
|
+
from playwright._impl._console_message import ConsoleMessage
|
|
53
|
+
from playwright._impl._disposable import Disposable, DisposableStub
|
|
54
|
+
from playwright._impl._download import Download
|
|
55
|
+
from playwright._impl._element_handle import ElementHandle, determine_screenshot_type
|
|
56
|
+
from playwright._impl._errors import Error, TargetClosedError, is_target_closed_error
|
|
57
|
+
from playwright._impl._event_context_manager import EventContextManagerImpl
|
|
58
|
+
from playwright._impl._file_chooser import FileChooser
|
|
59
|
+
from playwright._impl._frame import Frame
|
|
60
|
+
from playwright._impl._greenlets import LocatorHandlerGreenlet
|
|
61
|
+
from playwright._impl._har_router import HarRouter
|
|
62
|
+
from playwright._impl._helper import (
|
|
63
|
+
ColorScheme,
|
|
64
|
+
Contrast,
|
|
65
|
+
DocumentLoadState,
|
|
66
|
+
ForcedColors,
|
|
67
|
+
HarMode,
|
|
68
|
+
KeyboardModifier,
|
|
69
|
+
MouseButton,
|
|
70
|
+
ReducedMotion,
|
|
71
|
+
RouteFromHarNotFoundPolicy,
|
|
72
|
+
RouteHandler,
|
|
73
|
+
RouteHandlerCallback,
|
|
74
|
+
TimeoutSettings,
|
|
75
|
+
URLMatch,
|
|
76
|
+
URLMatchRequest,
|
|
77
|
+
URLMatchResponse,
|
|
78
|
+
WebSocketRouteHandlerCallback,
|
|
79
|
+
async_readfile,
|
|
80
|
+
async_writefile,
|
|
81
|
+
locals_to_params,
|
|
82
|
+
make_dirs_for_file,
|
|
83
|
+
parse_error,
|
|
84
|
+
serialize_error,
|
|
85
|
+
url_matches,
|
|
86
|
+
)
|
|
87
|
+
from playwright._impl._input import Keyboard, Mouse, Touchscreen
|
|
88
|
+
from playwright._impl._js_handle import (
|
|
89
|
+
JSHandle,
|
|
90
|
+
Serializable,
|
|
91
|
+
add_source_url_to_script,
|
|
92
|
+
parse_result,
|
|
93
|
+
serialize_argument,
|
|
94
|
+
)
|
|
95
|
+
from playwright._impl._network import (
|
|
96
|
+
Request,
|
|
97
|
+
Response,
|
|
98
|
+
Route,
|
|
99
|
+
WebSocketRoute,
|
|
100
|
+
WebSocketRouteHandler,
|
|
101
|
+
serialize_headers,
|
|
102
|
+
)
|
|
103
|
+
from playwright._impl._screencast import Screencast
|
|
104
|
+
from playwright._impl._video import Video
|
|
105
|
+
from playwright._impl._waiter import Waiter
|
|
106
|
+
from playwright._impl._web_storage import WebStorage
|
|
107
|
+
|
|
108
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
109
|
+
from playwright._impl._browser_context import BrowserContext
|
|
110
|
+
from playwright._impl._fetch import APIRequestContext
|
|
111
|
+
from playwright._impl._locator import FrameLocator, Locator
|
|
112
|
+
from playwright._impl._network import WebSocket
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class LocatorHandler:
|
|
116
|
+
locator: "Locator"
|
|
117
|
+
handler: Union[Callable[["Locator"], Any], Callable[..., Any]]
|
|
118
|
+
times: Union[int, None]
|
|
119
|
+
|
|
120
|
+
def __init__(
|
|
121
|
+
self, locator: "Locator", handler: Callable[..., Any], times: Union[int, None]
|
|
122
|
+
) -> None:
|
|
123
|
+
self.locator = locator
|
|
124
|
+
self._handler = handler
|
|
125
|
+
self.times = times
|
|
126
|
+
|
|
127
|
+
def __call__(self) -> Any:
|
|
128
|
+
arg_count = len(inspect.signature(self._handler).parameters)
|
|
129
|
+
if arg_count == 0:
|
|
130
|
+
return self._handler()
|
|
131
|
+
return self._handler(self.locator)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class Page(ChannelOwner):
|
|
135
|
+
Events = SimpleNamespace(
|
|
136
|
+
Close="close",
|
|
137
|
+
Crash="crash",
|
|
138
|
+
Console="console",
|
|
139
|
+
Dialog="dialog",
|
|
140
|
+
Download="download",
|
|
141
|
+
FileChooser="filechooser",
|
|
142
|
+
DOMContentLoaded="domcontentloaded",
|
|
143
|
+
PageError="pageerror",
|
|
144
|
+
Request="request",
|
|
145
|
+
Response="response",
|
|
146
|
+
RequestFailed="requestfailed",
|
|
147
|
+
RequestFinished="requestfinished",
|
|
148
|
+
FrameAttached="frameattached",
|
|
149
|
+
FrameDetached="framedetached",
|
|
150
|
+
FrameNavigated="framenavigated",
|
|
151
|
+
Load="load",
|
|
152
|
+
Popup="popup",
|
|
153
|
+
WebSocket="websocket",
|
|
154
|
+
Worker="worker",
|
|
155
|
+
)
|
|
156
|
+
keyboard: Keyboard
|
|
157
|
+
mouse: Mouse
|
|
158
|
+
touchscreen: Touchscreen
|
|
159
|
+
|
|
160
|
+
def __init__(
|
|
161
|
+
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
|
|
162
|
+
) -> None:
|
|
163
|
+
super().__init__(parent, type, guid, initializer)
|
|
164
|
+
self._browser_context = cast("BrowserContext", parent)
|
|
165
|
+
self.keyboard = Keyboard(self._channel)
|
|
166
|
+
self.mouse = Mouse(self._channel)
|
|
167
|
+
self.touchscreen = Touchscreen(self._channel)
|
|
168
|
+
|
|
169
|
+
self._main_frame: Frame = from_channel(initializer["mainFrame"])
|
|
170
|
+
self._main_frame._page = self
|
|
171
|
+
self._frames = [self._main_frame]
|
|
172
|
+
self._viewport_size: Optional[ViewportSize] = initializer.get("viewportSize")
|
|
173
|
+
self._is_closed = False
|
|
174
|
+
self._workers: List["Worker"] = []
|
|
175
|
+
self._bindings: Dict[str, Any] = {}
|
|
176
|
+
self._routes: List[RouteHandler] = []
|
|
177
|
+
self._web_socket_routes: List[WebSocketRouteHandler] = []
|
|
178
|
+
self._owned_context: Optional["BrowserContext"] = None
|
|
179
|
+
self._timeout_settings: TimeoutSettings = TimeoutSettings(
|
|
180
|
+
self._browser_context._timeout_settings
|
|
181
|
+
)
|
|
182
|
+
self._video: Video = Video(
|
|
183
|
+
self,
|
|
184
|
+
cast(Optional[Artifact], from_nullable_channel(initializer.get("video"))),
|
|
185
|
+
)
|
|
186
|
+
self._screencast: Screencast = Screencast(self)
|
|
187
|
+
self._local_storage = WebStorage(self, "local")
|
|
188
|
+
self._session_storage = WebStorage(self, "session")
|
|
189
|
+
self._opener = cast("Page", from_nullable_channel(initializer.get("opener")))
|
|
190
|
+
self._close_reason: Optional[str] = None
|
|
191
|
+
self._close_was_called = False
|
|
192
|
+
self._har_routers: List[HarRouter] = []
|
|
193
|
+
self._locator_handlers: Dict[str, LocatorHandler] = {}
|
|
194
|
+
|
|
195
|
+
self._channel.on(
|
|
196
|
+
"bindingCall",
|
|
197
|
+
lambda params: self._on_binding(from_channel(params["binding"])),
|
|
198
|
+
)
|
|
199
|
+
self._channel.on("close", lambda _: self._on_close())
|
|
200
|
+
self._channel.on("crash", lambda _: self._on_crash())
|
|
201
|
+
self._channel.on("download", lambda params: self._on_download(params))
|
|
202
|
+
self._channel.on(
|
|
203
|
+
"fileChooser",
|
|
204
|
+
lambda params: self.emit(
|
|
205
|
+
Page.Events.FileChooser,
|
|
206
|
+
FileChooser(
|
|
207
|
+
self, from_channel(params["element"]), params["isMultiple"]
|
|
208
|
+
),
|
|
209
|
+
),
|
|
210
|
+
)
|
|
211
|
+
self._channel.on(
|
|
212
|
+
"frameAttached",
|
|
213
|
+
lambda params: self._on_frame_attached(from_channel(params["frame"])),
|
|
214
|
+
)
|
|
215
|
+
self._channel.on(
|
|
216
|
+
"frameDetached",
|
|
217
|
+
lambda params: self._on_frame_detached(from_channel(params["frame"])),
|
|
218
|
+
)
|
|
219
|
+
self._channel.on(
|
|
220
|
+
"locatorHandlerTriggered",
|
|
221
|
+
lambda params: self._loop.create_task(
|
|
222
|
+
self._on_locator_handler_triggered(params["uid"])
|
|
223
|
+
),
|
|
224
|
+
)
|
|
225
|
+
self._channel.on(
|
|
226
|
+
"route",
|
|
227
|
+
lambda params: self._loop.create_task(
|
|
228
|
+
self._on_route(from_channel(params["route"]))
|
|
229
|
+
),
|
|
230
|
+
)
|
|
231
|
+
self._channel.on(
|
|
232
|
+
"webSocketRoute",
|
|
233
|
+
lambda params: self._loop.create_task(
|
|
234
|
+
self._on_web_socket_route(from_channel(params["webSocketRoute"]))
|
|
235
|
+
),
|
|
236
|
+
)
|
|
237
|
+
self._channel.on("viewportSizeChanged", self._on_viewport_size_changed)
|
|
238
|
+
self._channel.on(
|
|
239
|
+
"webSocket",
|
|
240
|
+
lambda params: self.emit(
|
|
241
|
+
Page.Events.WebSocket, from_channel(params["webSocket"])
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
self._channel.on(
|
|
245
|
+
"worker", lambda params: self._on_worker(from_channel(params["worker"]))
|
|
246
|
+
)
|
|
247
|
+
self._closed_or_crashed_future: asyncio.Future = asyncio.Future()
|
|
248
|
+
self.on(
|
|
249
|
+
Page.Events.Close,
|
|
250
|
+
lambda _: (
|
|
251
|
+
self._closed_or_crashed_future.set_result(
|
|
252
|
+
self._close_error_with_reason()
|
|
253
|
+
)
|
|
254
|
+
if not self._closed_or_crashed_future.done()
|
|
255
|
+
else None
|
|
256
|
+
),
|
|
257
|
+
)
|
|
258
|
+
self.on(
|
|
259
|
+
Page.Events.Crash,
|
|
260
|
+
lambda _: (
|
|
261
|
+
self._closed_or_crashed_future.set_result(TargetClosedError())
|
|
262
|
+
if not self._closed_or_crashed_future.done()
|
|
263
|
+
else None
|
|
264
|
+
),
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
self._set_event_to_subscription_mapping(
|
|
268
|
+
{
|
|
269
|
+
Page.Events.Console: "console",
|
|
270
|
+
Page.Events.Dialog: "dialog",
|
|
271
|
+
Page.Events.Request: "request",
|
|
272
|
+
Page.Events.Response: "response",
|
|
273
|
+
Page.Events.RequestFinished: "requestFinished",
|
|
274
|
+
Page.Events.RequestFailed: "requestFailed",
|
|
275
|
+
Page.Events.FileChooser: "fileChooser",
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
def __repr__(self) -> str:
|
|
280
|
+
return f"<Page url={self.url!r}>"
|
|
281
|
+
|
|
282
|
+
def _on_frame_attached(self, frame: Frame) -> None:
|
|
283
|
+
frame._page = self
|
|
284
|
+
self._frames.append(frame)
|
|
285
|
+
self.emit(Page.Events.FrameAttached, frame)
|
|
286
|
+
self._browser_context.emit("frameattached", frame)
|
|
287
|
+
|
|
288
|
+
def _on_frame_detached(self, frame: Frame) -> None:
|
|
289
|
+
self._frames.remove(frame)
|
|
290
|
+
frame._detached = True
|
|
291
|
+
self.emit(Page.Events.FrameDetached, frame)
|
|
292
|
+
self._browser_context.emit("framedetached", frame)
|
|
293
|
+
|
|
294
|
+
async def _on_route(self, route: Route) -> None:
|
|
295
|
+
route._context = self.context
|
|
296
|
+
route_handlers = self._routes.copy()
|
|
297
|
+
for route_handler in route_handlers:
|
|
298
|
+
# If the page was closed we stall all requests right away.
|
|
299
|
+
if self._close_was_called or self.context._closing_or_closed:
|
|
300
|
+
return
|
|
301
|
+
if not route_handler.matches(route.request.url):
|
|
302
|
+
continue
|
|
303
|
+
if route_handler not in self._routes:
|
|
304
|
+
continue
|
|
305
|
+
if route_handler.will_expire:
|
|
306
|
+
self._routes.remove(route_handler)
|
|
307
|
+
try:
|
|
308
|
+
handled = await route_handler.handle(route)
|
|
309
|
+
finally:
|
|
310
|
+
if len(self._routes) == 0:
|
|
311
|
+
|
|
312
|
+
async def _update_interceptor_patterns_ignore_exceptions() -> None:
|
|
313
|
+
try:
|
|
314
|
+
await self._update_interception_patterns()
|
|
315
|
+
except Error:
|
|
316
|
+
pass
|
|
317
|
+
|
|
318
|
+
asyncio.create_task(
|
|
319
|
+
self._connection.wrap_api_call(
|
|
320
|
+
_update_interceptor_patterns_ignore_exceptions, True
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
if handled:
|
|
324
|
+
return
|
|
325
|
+
await self._browser_context._on_route(route)
|
|
326
|
+
|
|
327
|
+
async def _on_web_socket_route(self, web_socket_route: WebSocketRoute) -> None:
|
|
328
|
+
route_handler = next(
|
|
329
|
+
(
|
|
330
|
+
route_handler
|
|
331
|
+
for route_handler in self._web_socket_routes
|
|
332
|
+
if route_handler.matches(web_socket_route.url)
|
|
333
|
+
),
|
|
334
|
+
None,
|
|
335
|
+
)
|
|
336
|
+
if route_handler:
|
|
337
|
+
await route_handler.handle(web_socket_route)
|
|
338
|
+
else:
|
|
339
|
+
await self._browser_context._on_web_socket_route(web_socket_route)
|
|
340
|
+
|
|
341
|
+
def _on_binding(self, binding_call: "BindingCall") -> None:
|
|
342
|
+
func = self._bindings.get(binding_call._initializer["name"])
|
|
343
|
+
if func:
|
|
344
|
+
asyncio.create_task(binding_call.call(func))
|
|
345
|
+
self._browser_context._on_binding(binding_call)
|
|
346
|
+
|
|
347
|
+
def _on_worker(self, worker: "Worker") -> None:
|
|
348
|
+
self._workers.append(worker)
|
|
349
|
+
worker._page = self
|
|
350
|
+
self.emit(Page.Events.Worker, worker)
|
|
351
|
+
|
|
352
|
+
def _on_close(self) -> None:
|
|
353
|
+
self._is_closed = True
|
|
354
|
+
if self in self._browser_context._pages:
|
|
355
|
+
self._browser_context._pages.remove(self)
|
|
356
|
+
self._dispose_har_routers()
|
|
357
|
+
self.emit(Page.Events.Close, self)
|
|
358
|
+
self._browser_context.emit("pageclose", self)
|
|
359
|
+
|
|
360
|
+
def _on_crash(self) -> None:
|
|
361
|
+
self.emit(Page.Events.Crash, self)
|
|
362
|
+
|
|
363
|
+
def _on_download(self, params: Any) -> None:
|
|
364
|
+
url = params["url"]
|
|
365
|
+
suggested_filename = params["suggestedFilename"]
|
|
366
|
+
artifact = cast(Artifact, from_channel(params["artifact"]))
|
|
367
|
+
download = Download(self, url, suggested_filename, artifact)
|
|
368
|
+
self.emit(Page.Events.Download, download)
|
|
369
|
+
self._browser_context.emit("download", download)
|
|
370
|
+
|
|
371
|
+
def _on_viewport_size_changed(self, params: Any) -> None:
|
|
372
|
+
self._viewport_size = params["viewportSize"]
|
|
373
|
+
|
|
374
|
+
@property
|
|
375
|
+
def context(self) -> "BrowserContext":
|
|
376
|
+
return self._browser_context
|
|
377
|
+
|
|
378
|
+
@property
|
|
379
|
+
def clock(self) -> Clock:
|
|
380
|
+
return self._browser_context.clock
|
|
381
|
+
|
|
382
|
+
async def opener(self) -> Optional["Page"]:
|
|
383
|
+
if self._opener and self._opener.is_closed():
|
|
384
|
+
return None
|
|
385
|
+
return self._opener
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
def main_frame(self) -> Frame:
|
|
389
|
+
return self._main_frame
|
|
390
|
+
|
|
391
|
+
def frame(self, name: str = None, url: URLMatch = None) -> Optional[Frame]:
|
|
392
|
+
for frame in self._frames:
|
|
393
|
+
if name and frame.name == name:
|
|
394
|
+
return frame
|
|
395
|
+
if url and url_matches(self._browser_context._base_url, frame.url, url):
|
|
396
|
+
return frame
|
|
397
|
+
|
|
398
|
+
return None
|
|
399
|
+
|
|
400
|
+
@property
|
|
401
|
+
def frames(self) -> List[Frame]:
|
|
402
|
+
return self._frames.copy()
|
|
403
|
+
|
|
404
|
+
def set_default_navigation_timeout(self, timeout: float) -> None:
|
|
405
|
+
self._timeout_settings.set_default_navigation_timeout(timeout)
|
|
406
|
+
|
|
407
|
+
def set_default_timeout(self, timeout: float) -> None:
|
|
408
|
+
self._timeout_settings.set_default_timeout(timeout)
|
|
409
|
+
|
|
410
|
+
async def query_selector(
|
|
411
|
+
self,
|
|
412
|
+
selector: str,
|
|
413
|
+
strict: bool = None,
|
|
414
|
+
) -> Optional[ElementHandle]:
|
|
415
|
+
return await self._main_frame.query_selector(selector, strict)
|
|
416
|
+
|
|
417
|
+
async def query_selector_all(self, selector: str) -> List[ElementHandle]:
|
|
418
|
+
return await self._main_frame.query_selector_all(selector)
|
|
419
|
+
|
|
420
|
+
async def wait_for_selector(
|
|
421
|
+
self,
|
|
422
|
+
selector: str,
|
|
423
|
+
timeout: float = None,
|
|
424
|
+
state: Literal["attached", "detached", "hidden", "visible"] = None,
|
|
425
|
+
strict: bool = None,
|
|
426
|
+
) -> Optional[ElementHandle]:
|
|
427
|
+
return await self._main_frame.wait_for_selector(**locals_to_params(locals()))
|
|
428
|
+
|
|
429
|
+
async def is_checked(
|
|
430
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
431
|
+
) -> bool:
|
|
432
|
+
return await self._main_frame.is_checked(**locals_to_params(locals()))
|
|
433
|
+
|
|
434
|
+
async def is_disabled(
|
|
435
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
436
|
+
) -> bool:
|
|
437
|
+
return await self._main_frame.is_disabled(**locals_to_params(locals()))
|
|
438
|
+
|
|
439
|
+
async def is_editable(
|
|
440
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
441
|
+
) -> bool:
|
|
442
|
+
return await self._main_frame.is_editable(**locals_to_params(locals()))
|
|
443
|
+
|
|
444
|
+
async def is_enabled(
|
|
445
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
446
|
+
) -> bool:
|
|
447
|
+
return await self._main_frame.is_enabled(**locals_to_params(locals()))
|
|
448
|
+
|
|
449
|
+
async def is_hidden(
|
|
450
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
451
|
+
) -> bool:
|
|
452
|
+
# timeout is deprecated and does nothing
|
|
453
|
+
return await self._main_frame.is_hidden(selector=selector, strict=strict)
|
|
454
|
+
|
|
455
|
+
async def is_visible(
|
|
456
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
457
|
+
) -> bool:
|
|
458
|
+
# timeout is deprecated and does nothing
|
|
459
|
+
return await self._main_frame.is_visible(selector=selector, strict=strict)
|
|
460
|
+
|
|
461
|
+
async def dispatch_event(
|
|
462
|
+
self,
|
|
463
|
+
selector: str,
|
|
464
|
+
type: str,
|
|
465
|
+
eventInit: Dict = None,
|
|
466
|
+
timeout: float = None,
|
|
467
|
+
strict: bool = None,
|
|
468
|
+
) -> None:
|
|
469
|
+
return await self._main_frame.dispatch_event(**locals_to_params(locals()))
|
|
470
|
+
|
|
471
|
+
async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
|
|
472
|
+
return await self._main_frame.evaluate(expression, arg)
|
|
473
|
+
|
|
474
|
+
async def evaluate_handle(
|
|
475
|
+
self, expression: str, arg: Serializable = None
|
|
476
|
+
) -> JSHandle:
|
|
477
|
+
return await self._main_frame.evaluate_handle(expression, arg)
|
|
478
|
+
|
|
479
|
+
async def eval_on_selector(
|
|
480
|
+
self,
|
|
481
|
+
selector: str,
|
|
482
|
+
expression: str,
|
|
483
|
+
arg: Serializable = None,
|
|
484
|
+
strict: bool = None,
|
|
485
|
+
) -> Any:
|
|
486
|
+
return await self._main_frame.eval_on_selector(
|
|
487
|
+
selector, expression, arg, strict
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
async def eval_on_selector_all(
|
|
491
|
+
self,
|
|
492
|
+
selector: str,
|
|
493
|
+
expression: str,
|
|
494
|
+
arg: Serializable = None,
|
|
495
|
+
) -> Any:
|
|
496
|
+
return await self._main_frame.eval_on_selector_all(selector, expression, arg)
|
|
497
|
+
|
|
498
|
+
async def add_script_tag(
|
|
499
|
+
self,
|
|
500
|
+
url: str = None,
|
|
501
|
+
path: Union[str, Path] = None,
|
|
502
|
+
content: str = None,
|
|
503
|
+
type: str = None,
|
|
504
|
+
) -> ElementHandle:
|
|
505
|
+
return await self._main_frame.add_script_tag(**locals_to_params(locals()))
|
|
506
|
+
|
|
507
|
+
async def add_style_tag(
|
|
508
|
+
self, url: str = None, path: Union[str, Path] = None, content: str = None
|
|
509
|
+
) -> ElementHandle:
|
|
510
|
+
return await self._main_frame.add_style_tag(**locals_to_params(locals()))
|
|
511
|
+
|
|
512
|
+
async def expose_function(self, name: str, callback: Callable) -> Disposable:
|
|
513
|
+
return await self.expose_binding(name, lambda source, *args: callback(*args))
|
|
514
|
+
|
|
515
|
+
async def expose_binding(self, name: str, callback: Callable) -> Disposable:
|
|
516
|
+
if name in self._bindings:
|
|
517
|
+
raise Error(f'Function "{name}" has been already registered')
|
|
518
|
+
if name in self._browser_context._bindings:
|
|
519
|
+
raise Error(
|
|
520
|
+
f'Function "{name}" has been already registered in the browser context'
|
|
521
|
+
)
|
|
522
|
+
self._bindings[name] = callback
|
|
523
|
+
return from_channel(
|
|
524
|
+
await self._channel.send(
|
|
525
|
+
"exposeBinding",
|
|
526
|
+
None,
|
|
527
|
+
dict(name=name),
|
|
528
|
+
)
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
async def set_extra_http_headers(self, headers: Dict[str, str]) -> None:
|
|
532
|
+
await self._channel.send(
|
|
533
|
+
"setExtraHTTPHeaders",
|
|
534
|
+
None,
|
|
535
|
+
dict(headers=serialize_headers(headers)),
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
@property
|
|
539
|
+
def url(self) -> str:
|
|
540
|
+
return self._main_frame.url
|
|
541
|
+
|
|
542
|
+
async def content(self) -> str:
|
|
543
|
+
return await self._main_frame.content()
|
|
544
|
+
|
|
545
|
+
async def set_content(
|
|
546
|
+
self,
|
|
547
|
+
html: str,
|
|
548
|
+
timeout: float = None,
|
|
549
|
+
waitUntil: DocumentLoadState = None,
|
|
550
|
+
) -> None:
|
|
551
|
+
return await self._main_frame.set_content(**locals_to_params(locals()))
|
|
552
|
+
|
|
553
|
+
async def goto(
|
|
554
|
+
self,
|
|
555
|
+
url: str,
|
|
556
|
+
timeout: float = None,
|
|
557
|
+
waitUntil: DocumentLoadState = None,
|
|
558
|
+
referer: str = None,
|
|
559
|
+
) -> Optional[Response]:
|
|
560
|
+
return await self._main_frame.goto(**locals_to_params(locals()))
|
|
561
|
+
|
|
562
|
+
async def reload(
|
|
563
|
+
self,
|
|
564
|
+
timeout: float = None,
|
|
565
|
+
waitUntil: DocumentLoadState = None,
|
|
566
|
+
) -> Optional[Response]:
|
|
567
|
+
return from_nullable_channel(
|
|
568
|
+
await self._channel.send(
|
|
569
|
+
"reload",
|
|
570
|
+
self._timeout_settings.navigation_timeout,
|
|
571
|
+
locals_to_params(locals()),
|
|
572
|
+
)
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
async def wait_for_load_state(
|
|
576
|
+
self,
|
|
577
|
+
state: Literal["domcontentloaded", "load", "networkidle"] = None,
|
|
578
|
+
timeout: float = None,
|
|
579
|
+
) -> None:
|
|
580
|
+
return await self._main_frame.wait_for_load_state(**locals_to_params(locals()))
|
|
581
|
+
|
|
582
|
+
async def wait_for_url(
|
|
583
|
+
self,
|
|
584
|
+
url: URLMatch,
|
|
585
|
+
waitUntil: DocumentLoadState = None,
|
|
586
|
+
timeout: float = None,
|
|
587
|
+
) -> None:
|
|
588
|
+
return await self._main_frame.wait_for_url(**locals_to_params(locals()))
|
|
589
|
+
|
|
590
|
+
async def wait_for_event(
|
|
591
|
+
self, event: str, predicate: Callable = None, timeout: float = None
|
|
592
|
+
) -> Any:
|
|
593
|
+
async with self.expect_event(event, predicate, timeout) as event_info:
|
|
594
|
+
pass
|
|
595
|
+
return await event_info
|
|
596
|
+
|
|
597
|
+
async def go_back(
|
|
598
|
+
self,
|
|
599
|
+
timeout: float = None,
|
|
600
|
+
waitUntil: DocumentLoadState = None,
|
|
601
|
+
) -> Optional[Response]:
|
|
602
|
+
return from_nullable_channel(
|
|
603
|
+
await self._channel.send(
|
|
604
|
+
"goBack",
|
|
605
|
+
self._timeout_settings.navigation_timeout,
|
|
606
|
+
locals_to_params(locals()),
|
|
607
|
+
)
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
async def go_forward(
|
|
611
|
+
self,
|
|
612
|
+
timeout: float = None,
|
|
613
|
+
waitUntil: DocumentLoadState = None,
|
|
614
|
+
) -> Optional[Response]:
|
|
615
|
+
return from_nullable_channel(
|
|
616
|
+
await self._channel.send(
|
|
617
|
+
"goForward",
|
|
618
|
+
self._timeout_settings.navigation_timeout,
|
|
619
|
+
locals_to_params(locals()),
|
|
620
|
+
)
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
async def request_gc(self) -> None:
|
|
624
|
+
await self._channel.send("requestGC", None)
|
|
625
|
+
|
|
626
|
+
async def emulate_media(
|
|
627
|
+
self,
|
|
628
|
+
media: Literal["null", "print", "screen"] = None,
|
|
629
|
+
colorScheme: ColorScheme = None,
|
|
630
|
+
reducedMotion: ReducedMotion = None,
|
|
631
|
+
forcedColors: ForcedColors = None,
|
|
632
|
+
contrast: Contrast = None,
|
|
633
|
+
) -> None:
|
|
634
|
+
params = locals_to_params(locals())
|
|
635
|
+
if "media" in params:
|
|
636
|
+
params["media"] = "no-override" if params["media"] == "null" else media
|
|
637
|
+
if "colorScheme" in params:
|
|
638
|
+
params["colorScheme"] = (
|
|
639
|
+
"no-override" if params["colorScheme"] == "null" else colorScheme
|
|
640
|
+
)
|
|
641
|
+
if "reducedMotion" in params:
|
|
642
|
+
params["reducedMotion"] = (
|
|
643
|
+
"no-override" if params["reducedMotion"] == "null" else reducedMotion
|
|
644
|
+
)
|
|
645
|
+
if "forcedColors" in params:
|
|
646
|
+
params["forcedColors"] = (
|
|
647
|
+
"no-override" if params["forcedColors"] == "null" else forcedColors
|
|
648
|
+
)
|
|
649
|
+
if "contrast" in params:
|
|
650
|
+
params["contrast"] = (
|
|
651
|
+
"no-override" if params["contrast"] == "null" else contrast
|
|
652
|
+
)
|
|
653
|
+
await self._channel.send("emulateMedia", None, params)
|
|
654
|
+
|
|
655
|
+
async def set_viewport_size(self, viewportSize: ViewportSize) -> None:
|
|
656
|
+
self._viewport_size = viewportSize
|
|
657
|
+
await self._channel.send(
|
|
658
|
+
"setViewportSize",
|
|
659
|
+
None,
|
|
660
|
+
locals_to_params(locals()),
|
|
661
|
+
)
|
|
662
|
+
|
|
663
|
+
@property
|
|
664
|
+
def viewport_size(self) -> Optional[ViewportSize]:
|
|
665
|
+
return self._viewport_size
|
|
666
|
+
|
|
667
|
+
async def bring_to_front(self) -> None:
|
|
668
|
+
await self._channel.send("bringToFront", None)
|
|
669
|
+
|
|
670
|
+
async def hide_highlight(self) -> None:
|
|
671
|
+
await self._channel.send("hideHighlight", None)
|
|
672
|
+
|
|
673
|
+
async def add_init_script(
|
|
674
|
+
self, script: str = None, path: Union[str, Path] = None
|
|
675
|
+
) -> Disposable:
|
|
676
|
+
if path:
|
|
677
|
+
script = add_source_url_to_script(
|
|
678
|
+
(await async_readfile(path)).decode(), path
|
|
679
|
+
)
|
|
680
|
+
if not isinstance(script, str):
|
|
681
|
+
raise Error("Either path or script parameter must be specified")
|
|
682
|
+
return from_channel(
|
|
683
|
+
await self._channel.send("addInitScript", None, dict(source=script))
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
async def route(
|
|
687
|
+
self, url: URLMatch, handler: RouteHandlerCallback, times: int = None
|
|
688
|
+
) -> DisposableStub:
|
|
689
|
+
self._routes.insert(
|
|
690
|
+
0,
|
|
691
|
+
RouteHandler(
|
|
692
|
+
self._browser_context._base_url,
|
|
693
|
+
url,
|
|
694
|
+
handler,
|
|
695
|
+
True if self._dispatcher_fiber else False,
|
|
696
|
+
times,
|
|
697
|
+
),
|
|
698
|
+
)
|
|
699
|
+
await self._update_interception_patterns()
|
|
700
|
+
return DisposableStub(lambda: self.unroute(url, handler), self)
|
|
701
|
+
|
|
702
|
+
async def unroute(
|
|
703
|
+
self, url: URLMatch, handler: Optional[RouteHandlerCallback] = None
|
|
704
|
+
) -> None:
|
|
705
|
+
removed = []
|
|
706
|
+
remaining = []
|
|
707
|
+
for route in self._routes:
|
|
708
|
+
if route.url != url or (handler and route.handler != handler):
|
|
709
|
+
remaining.append(route)
|
|
710
|
+
else:
|
|
711
|
+
removed.append(route)
|
|
712
|
+
await self._unroute_internal(removed, remaining, "default")
|
|
713
|
+
|
|
714
|
+
async def _unroute_internal(
|
|
715
|
+
self,
|
|
716
|
+
removed: List[RouteHandler],
|
|
717
|
+
remaining: List[RouteHandler],
|
|
718
|
+
behavior: Literal["default", "ignoreErrors", "wait"] = None,
|
|
719
|
+
) -> None:
|
|
720
|
+
self._routes = remaining
|
|
721
|
+
if behavior is not None and behavior != "default":
|
|
722
|
+
await asyncio.gather(
|
|
723
|
+
*map(
|
|
724
|
+
lambda route: route.stop(behavior), # type: ignore
|
|
725
|
+
removed,
|
|
726
|
+
)
|
|
727
|
+
)
|
|
728
|
+
await self._update_interception_patterns()
|
|
729
|
+
|
|
730
|
+
async def route_web_socket(
|
|
731
|
+
self, url: URLMatch, handler: WebSocketRouteHandlerCallback
|
|
732
|
+
) -> None:
|
|
733
|
+
self._web_socket_routes.insert(
|
|
734
|
+
0,
|
|
735
|
+
WebSocketRouteHandler(self._browser_context._base_url, url, handler),
|
|
736
|
+
)
|
|
737
|
+
await self._update_web_socket_interception_patterns()
|
|
738
|
+
|
|
739
|
+
def _dispose_har_routers(self) -> None:
|
|
740
|
+
for router in self._har_routers:
|
|
741
|
+
router.dispose()
|
|
742
|
+
self._har_routers = []
|
|
743
|
+
|
|
744
|
+
async def unroute_all(
|
|
745
|
+
self, behavior: Literal["default", "ignoreErrors", "wait"] = None
|
|
746
|
+
) -> None:
|
|
747
|
+
await self._unroute_internal(self._routes, [], behavior)
|
|
748
|
+
self._dispose_har_routers()
|
|
749
|
+
|
|
750
|
+
async def route_from_har(
|
|
751
|
+
self,
|
|
752
|
+
har: Union[Path, str],
|
|
753
|
+
url: Union[Pattern[str], str] = None,
|
|
754
|
+
notFound: RouteFromHarNotFoundPolicy = None,
|
|
755
|
+
update: bool = None,
|
|
756
|
+
updateContent: Literal["attach", "embed"] = None,
|
|
757
|
+
updateMode: HarMode = None,
|
|
758
|
+
) -> None:
|
|
759
|
+
if update:
|
|
760
|
+
await self._browser_context._tracing._record_into_har(
|
|
761
|
+
har=har,
|
|
762
|
+
page=self,
|
|
763
|
+
url=url,
|
|
764
|
+
update_content=updateContent,
|
|
765
|
+
update_mode=updateMode,
|
|
766
|
+
)
|
|
767
|
+
return
|
|
768
|
+
router = await HarRouter.create(
|
|
769
|
+
local_utils=self._connection.local_utils,
|
|
770
|
+
file=str(har),
|
|
771
|
+
not_found_action=notFound or "abort",
|
|
772
|
+
url_matcher=url,
|
|
773
|
+
)
|
|
774
|
+
self._har_routers.append(router)
|
|
775
|
+
await router.add_page_route(self)
|
|
776
|
+
|
|
777
|
+
async def _update_interception_patterns(self) -> None:
|
|
778
|
+
patterns = RouteHandler.prepare_interception_patterns(self._routes)
|
|
779
|
+
await self._channel.send(
|
|
780
|
+
"setNetworkInterceptionPatterns",
|
|
781
|
+
None,
|
|
782
|
+
{"patterns": patterns},
|
|
783
|
+
)
|
|
784
|
+
|
|
785
|
+
async def _update_web_socket_interception_patterns(self) -> None:
|
|
786
|
+
patterns = WebSocketRouteHandler.prepare_interception_patterns(
|
|
787
|
+
self._web_socket_routes
|
|
788
|
+
)
|
|
789
|
+
await self._channel.send(
|
|
790
|
+
"setWebSocketInterceptionPatterns",
|
|
791
|
+
None,
|
|
792
|
+
{"patterns": patterns},
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
async def screenshot(
|
|
796
|
+
self,
|
|
797
|
+
timeout: float = None,
|
|
798
|
+
type: Literal["jpeg", "png", "webp"] = None,
|
|
799
|
+
path: Union[str, Path] = None,
|
|
800
|
+
quality: int = None,
|
|
801
|
+
omitBackground: bool = None,
|
|
802
|
+
fullPage: bool = None,
|
|
803
|
+
clip: FloatRect = None,
|
|
804
|
+
animations: Literal["allow", "disabled"] = None,
|
|
805
|
+
caret: Literal["hide", "initial"] = None,
|
|
806
|
+
scale: Literal["css", "device"] = None,
|
|
807
|
+
mask: Sequence["Locator"] = None,
|
|
808
|
+
maskColor: str = None,
|
|
809
|
+
style: str = None,
|
|
810
|
+
) -> bytes:
|
|
811
|
+
params = locals_to_params(locals())
|
|
812
|
+
if "path" in params:
|
|
813
|
+
if "type" not in params:
|
|
814
|
+
params["type"] = determine_screenshot_type(params["path"])
|
|
815
|
+
del params["path"]
|
|
816
|
+
if "mask" in params:
|
|
817
|
+
params["mask"] = list(
|
|
818
|
+
map(
|
|
819
|
+
lambda locator: (
|
|
820
|
+
{
|
|
821
|
+
"frame": locator._frame._channel,
|
|
822
|
+
"selector": locator._selector,
|
|
823
|
+
}
|
|
824
|
+
),
|
|
825
|
+
params["mask"],
|
|
826
|
+
)
|
|
827
|
+
)
|
|
828
|
+
encoded_binary = await self._channel.send(
|
|
829
|
+
"screenshot", self._timeout_settings.timeout, params
|
|
830
|
+
)
|
|
831
|
+
decoded_binary = base64.b64decode(encoded_binary)
|
|
832
|
+
if path:
|
|
833
|
+
make_dirs_for_file(path)
|
|
834
|
+
await async_writefile(path, decoded_binary)
|
|
835
|
+
return decoded_binary
|
|
836
|
+
|
|
837
|
+
async def title(self) -> str:
|
|
838
|
+
return await self._main_frame.title()
|
|
839
|
+
|
|
840
|
+
async def aria_snapshot(
|
|
841
|
+
self,
|
|
842
|
+
timeout: float = None,
|
|
843
|
+
depth: int = None,
|
|
844
|
+
mode: Literal["ai", "default"] = None,
|
|
845
|
+
boxes: bool = None,
|
|
846
|
+
) -> str:
|
|
847
|
+
return await self._main_frame._channel.send(
|
|
848
|
+
"ariaSnapshot",
|
|
849
|
+
self._main_frame._timeout,
|
|
850
|
+
locals_to_params(locals()),
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
async def close(self, runBeforeUnload: bool = None, reason: str = None) -> None:
|
|
854
|
+
self._close_reason = reason
|
|
855
|
+
if not runBeforeUnload:
|
|
856
|
+
self._close_was_called = True
|
|
857
|
+
try:
|
|
858
|
+
if self._owned_context:
|
|
859
|
+
await self._owned_context.close()
|
|
860
|
+
elif runBeforeUnload:
|
|
861
|
+
await self._channel.send("runBeforeUnload", None)
|
|
862
|
+
else:
|
|
863
|
+
await self._channel.send("close", None, {"reason": reason})
|
|
864
|
+
except Exception as e:
|
|
865
|
+
if is_target_closed_error(e) and not runBeforeUnload:
|
|
866
|
+
return
|
|
867
|
+
raise e
|
|
868
|
+
|
|
869
|
+
def is_closed(self) -> bool:
|
|
870
|
+
return self._is_closed
|
|
871
|
+
|
|
872
|
+
async def click(
|
|
873
|
+
self,
|
|
874
|
+
selector: str,
|
|
875
|
+
modifiers: Sequence[KeyboardModifier] = None,
|
|
876
|
+
position: Position = None,
|
|
877
|
+
delay: float = None,
|
|
878
|
+
button: MouseButton = None,
|
|
879
|
+
clickCount: int = None,
|
|
880
|
+
timeout: float = None,
|
|
881
|
+
force: bool = None,
|
|
882
|
+
noWaitAfter: bool = None,
|
|
883
|
+
trial: bool = None,
|
|
884
|
+
strict: bool = None,
|
|
885
|
+
scroll: Literal["auto", "none"] = None,
|
|
886
|
+
) -> None:
|
|
887
|
+
return await self._main_frame._click(**locals_to_params(locals()))
|
|
888
|
+
|
|
889
|
+
async def dblclick(
|
|
890
|
+
self,
|
|
891
|
+
selector: str,
|
|
892
|
+
modifiers: Sequence[KeyboardModifier] = None,
|
|
893
|
+
position: Position = None,
|
|
894
|
+
delay: float = None,
|
|
895
|
+
button: MouseButton = None,
|
|
896
|
+
timeout: float = None,
|
|
897
|
+
force: bool = None,
|
|
898
|
+
noWaitAfter: bool = None,
|
|
899
|
+
strict: bool = None,
|
|
900
|
+
trial: bool = None,
|
|
901
|
+
scroll: Literal["auto", "none"] = None,
|
|
902
|
+
) -> None:
|
|
903
|
+
return await self._main_frame.dblclick(**locals_to_params(locals()))
|
|
904
|
+
|
|
905
|
+
async def tap(
|
|
906
|
+
self,
|
|
907
|
+
selector: str,
|
|
908
|
+
modifiers: Sequence[KeyboardModifier] = None,
|
|
909
|
+
position: Position = None,
|
|
910
|
+
timeout: float = None,
|
|
911
|
+
force: bool = None,
|
|
912
|
+
noWaitAfter: bool = None,
|
|
913
|
+
strict: bool = None,
|
|
914
|
+
trial: bool = None,
|
|
915
|
+
scroll: Literal["auto", "none"] = None,
|
|
916
|
+
) -> None:
|
|
917
|
+
return await self._main_frame.tap(**locals_to_params(locals()))
|
|
918
|
+
|
|
919
|
+
async def fill(
|
|
920
|
+
self,
|
|
921
|
+
selector: str,
|
|
922
|
+
value: str,
|
|
923
|
+
timeout: float = None,
|
|
924
|
+
noWaitAfter: bool = None,
|
|
925
|
+
strict: bool = None,
|
|
926
|
+
force: bool = None,
|
|
927
|
+
) -> None:
|
|
928
|
+
return await self._main_frame.fill(**locals_to_params(locals()))
|
|
929
|
+
|
|
930
|
+
def locator(
|
|
931
|
+
self,
|
|
932
|
+
selector: str,
|
|
933
|
+
hasText: Union[str, Pattern[str]] = None,
|
|
934
|
+
hasNotText: Union[str, Pattern[str]] = None,
|
|
935
|
+
has: "Locator" = None,
|
|
936
|
+
hasNot: "Locator" = None,
|
|
937
|
+
) -> "Locator":
|
|
938
|
+
return self._main_frame.locator(
|
|
939
|
+
selector,
|
|
940
|
+
hasText=hasText,
|
|
941
|
+
hasNotText=hasNotText,
|
|
942
|
+
has=has,
|
|
943
|
+
hasNot=hasNot,
|
|
944
|
+
)
|
|
945
|
+
|
|
946
|
+
def get_by_alt_text(
|
|
947
|
+
self, text: Union[str, Pattern[str]], exact: bool = None
|
|
948
|
+
) -> "Locator":
|
|
949
|
+
return self._main_frame.get_by_alt_text(text, exact=exact)
|
|
950
|
+
|
|
951
|
+
def get_by_label(
|
|
952
|
+
self, text: Union[str, Pattern[str]], exact: bool = None
|
|
953
|
+
) -> "Locator":
|
|
954
|
+
return self._main_frame.get_by_label(text, exact=exact)
|
|
955
|
+
|
|
956
|
+
def get_by_placeholder(
|
|
957
|
+
self, text: Union[str, Pattern[str]], exact: bool = None
|
|
958
|
+
) -> "Locator":
|
|
959
|
+
return self._main_frame.get_by_placeholder(text, exact=exact)
|
|
960
|
+
|
|
961
|
+
def get_by_role(
|
|
962
|
+
self,
|
|
963
|
+
role: AriaRole,
|
|
964
|
+
checked: bool = None,
|
|
965
|
+
disabled: bool = None,
|
|
966
|
+
expanded: bool = None,
|
|
967
|
+
includeHidden: bool = None,
|
|
968
|
+
level: int = None,
|
|
969
|
+
name: Union[str, Pattern[str]] = None,
|
|
970
|
+
pressed: bool = None,
|
|
971
|
+
selected: bool = None,
|
|
972
|
+
exact: bool = None,
|
|
973
|
+
description: Union[str, Pattern[str]] = None,
|
|
974
|
+
) -> "Locator":
|
|
975
|
+
return self._main_frame.get_by_role(
|
|
976
|
+
role,
|
|
977
|
+
checked=checked,
|
|
978
|
+
disabled=disabled,
|
|
979
|
+
expanded=expanded,
|
|
980
|
+
includeHidden=includeHidden,
|
|
981
|
+
level=level,
|
|
982
|
+
name=name,
|
|
983
|
+
pressed=pressed,
|
|
984
|
+
selected=selected,
|
|
985
|
+
exact=exact,
|
|
986
|
+
description=description,
|
|
987
|
+
)
|
|
988
|
+
|
|
989
|
+
def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
|
|
990
|
+
return self._main_frame.get_by_test_id(testId)
|
|
991
|
+
|
|
992
|
+
def get_by_text(
|
|
993
|
+
self, text: Union[str, Pattern[str]], exact: bool = None
|
|
994
|
+
) -> "Locator":
|
|
995
|
+
return self._main_frame.get_by_text(text, exact=exact)
|
|
996
|
+
|
|
997
|
+
def get_by_title(
|
|
998
|
+
self, text: Union[str, Pattern[str]], exact: bool = None
|
|
999
|
+
) -> "Locator":
|
|
1000
|
+
return self._main_frame.get_by_title(text, exact=exact)
|
|
1001
|
+
|
|
1002
|
+
def frame_locator(self, selector: str) -> "FrameLocator":
|
|
1003
|
+
return self.main_frame.frame_locator(selector)
|
|
1004
|
+
|
|
1005
|
+
async def focus(
|
|
1006
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
1007
|
+
) -> None:
|
|
1008
|
+
return await self._main_frame.focus(**locals_to_params(locals()))
|
|
1009
|
+
|
|
1010
|
+
async def text_content(
|
|
1011
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
1012
|
+
) -> Optional[str]:
|
|
1013
|
+
return await self._main_frame.text_content(**locals_to_params(locals()))
|
|
1014
|
+
|
|
1015
|
+
async def inner_text(
|
|
1016
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
1017
|
+
) -> str:
|
|
1018
|
+
return await self._main_frame.inner_text(**locals_to_params(locals()))
|
|
1019
|
+
|
|
1020
|
+
async def inner_html(
|
|
1021
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
1022
|
+
) -> str:
|
|
1023
|
+
return await self._main_frame.inner_html(**locals_to_params(locals()))
|
|
1024
|
+
|
|
1025
|
+
async def get_attribute(
|
|
1026
|
+
self, selector: str, name: str, strict: bool = None, timeout: float = None
|
|
1027
|
+
) -> Optional[str]:
|
|
1028
|
+
return await self._main_frame.get_attribute(**locals_to_params(locals()))
|
|
1029
|
+
|
|
1030
|
+
async def hover(
|
|
1031
|
+
self,
|
|
1032
|
+
selector: str,
|
|
1033
|
+
modifiers: Sequence[KeyboardModifier] = None,
|
|
1034
|
+
position: Position = None,
|
|
1035
|
+
timeout: float = None,
|
|
1036
|
+
noWaitAfter: bool = None,
|
|
1037
|
+
force: bool = None,
|
|
1038
|
+
strict: bool = None,
|
|
1039
|
+
trial: bool = None,
|
|
1040
|
+
scroll: Literal["auto", "none"] = None,
|
|
1041
|
+
) -> None:
|
|
1042
|
+
return await self._main_frame.hover(**locals_to_params(locals()))
|
|
1043
|
+
|
|
1044
|
+
async def drag_and_drop(
|
|
1045
|
+
self,
|
|
1046
|
+
source: str,
|
|
1047
|
+
target: str,
|
|
1048
|
+
sourcePosition: Position = None,
|
|
1049
|
+
targetPosition: Position = None,
|
|
1050
|
+
force: bool = None,
|
|
1051
|
+
noWaitAfter: bool = None,
|
|
1052
|
+
timeout: float = None,
|
|
1053
|
+
strict: bool = None,
|
|
1054
|
+
trial: bool = None,
|
|
1055
|
+
steps: int = None,
|
|
1056
|
+
scroll: Literal["auto", "none"] = None,
|
|
1057
|
+
) -> None:
|
|
1058
|
+
return await self._main_frame.drag_and_drop(**locals_to_params(locals()))
|
|
1059
|
+
|
|
1060
|
+
async def select_option(
|
|
1061
|
+
self,
|
|
1062
|
+
selector: str,
|
|
1063
|
+
value: Union[str, Sequence[str]] = None,
|
|
1064
|
+
index: Union[int, Sequence[int]] = None,
|
|
1065
|
+
label: Union[str, Sequence[str]] = None,
|
|
1066
|
+
element: Union["ElementHandle", Sequence["ElementHandle"]] = None,
|
|
1067
|
+
timeout: float = None,
|
|
1068
|
+
noWaitAfter: bool = None,
|
|
1069
|
+
force: bool = None,
|
|
1070
|
+
strict: bool = None,
|
|
1071
|
+
) -> List[str]:
|
|
1072
|
+
params = locals_to_params(locals())
|
|
1073
|
+
return await self._main_frame.select_option(**params)
|
|
1074
|
+
|
|
1075
|
+
async def input_value(
|
|
1076
|
+
self, selector: str, strict: bool = None, timeout: float = None
|
|
1077
|
+
) -> str:
|
|
1078
|
+
params = locals_to_params(locals())
|
|
1079
|
+
return await self._main_frame.input_value(**params)
|
|
1080
|
+
|
|
1081
|
+
async def set_input_files(
|
|
1082
|
+
self,
|
|
1083
|
+
selector: str,
|
|
1084
|
+
files: Union[
|
|
1085
|
+
str, Path, FilePayload, Sequence[Union[str, Path]], Sequence[FilePayload]
|
|
1086
|
+
],
|
|
1087
|
+
timeout: float = None,
|
|
1088
|
+
strict: bool = None,
|
|
1089
|
+
noWaitAfter: bool = None,
|
|
1090
|
+
) -> None:
|
|
1091
|
+
return await self._main_frame.set_input_files(**locals_to_params(locals()))
|
|
1092
|
+
|
|
1093
|
+
async def type(
|
|
1094
|
+
self,
|
|
1095
|
+
selector: str,
|
|
1096
|
+
text: str,
|
|
1097
|
+
delay: float = None,
|
|
1098
|
+
timeout: float = None,
|
|
1099
|
+
noWaitAfter: bool = None,
|
|
1100
|
+
strict: bool = None,
|
|
1101
|
+
) -> None:
|
|
1102
|
+
return await self._main_frame.type(**locals_to_params(locals()))
|
|
1103
|
+
|
|
1104
|
+
async def press(
|
|
1105
|
+
self,
|
|
1106
|
+
selector: str,
|
|
1107
|
+
key: str,
|
|
1108
|
+
delay: float = None,
|
|
1109
|
+
timeout: float = None,
|
|
1110
|
+
noWaitAfter: bool = None,
|
|
1111
|
+
strict: bool = None,
|
|
1112
|
+
) -> None:
|
|
1113
|
+
return await self._main_frame.press(**locals_to_params(locals()))
|
|
1114
|
+
|
|
1115
|
+
async def check(
|
|
1116
|
+
self,
|
|
1117
|
+
selector: str,
|
|
1118
|
+
position: Position = None,
|
|
1119
|
+
timeout: float = None,
|
|
1120
|
+
force: bool = None,
|
|
1121
|
+
noWaitAfter: bool = None,
|
|
1122
|
+
strict: bool = None,
|
|
1123
|
+
trial: bool = None,
|
|
1124
|
+
scroll: Literal["auto", "none"] = None,
|
|
1125
|
+
) -> None:
|
|
1126
|
+
return await self._main_frame.check(**locals_to_params(locals()))
|
|
1127
|
+
|
|
1128
|
+
async def uncheck(
|
|
1129
|
+
self,
|
|
1130
|
+
selector: str,
|
|
1131
|
+
position: Position = None,
|
|
1132
|
+
timeout: float = None,
|
|
1133
|
+
force: bool = None,
|
|
1134
|
+
noWaitAfter: bool = None,
|
|
1135
|
+
strict: bool = None,
|
|
1136
|
+
trial: bool = None,
|
|
1137
|
+
scroll: Literal["auto", "none"] = None,
|
|
1138
|
+
) -> None:
|
|
1139
|
+
return await self._main_frame.uncheck(**locals_to_params(locals()))
|
|
1140
|
+
|
|
1141
|
+
async def wait_for_timeout(self, timeout: float) -> None:
|
|
1142
|
+
await self._main_frame.wait_for_timeout(timeout)
|
|
1143
|
+
|
|
1144
|
+
async def wait_for_function(
|
|
1145
|
+
self,
|
|
1146
|
+
expression: str,
|
|
1147
|
+
arg: Serializable = None,
|
|
1148
|
+
timeout: float = None,
|
|
1149
|
+
polling: Union[float, Literal["raf"]] = None,
|
|
1150
|
+
) -> JSHandle:
|
|
1151
|
+
return await self._main_frame.wait_for_function(**locals_to_params(locals()))
|
|
1152
|
+
|
|
1153
|
+
@property
|
|
1154
|
+
def workers(self) -> List["Worker"]:
|
|
1155
|
+
return self._workers.copy()
|
|
1156
|
+
|
|
1157
|
+
@property
|
|
1158
|
+
def request(self) -> "APIRequestContext":
|
|
1159
|
+
return self.context.request
|
|
1160
|
+
|
|
1161
|
+
async def pause(self) -> None:
|
|
1162
|
+
default_navigation_timeout = (
|
|
1163
|
+
self._browser_context._timeout_settings.default_navigation_timeout()
|
|
1164
|
+
)
|
|
1165
|
+
default_timeout = self._browser_context._timeout_settings.default_timeout()
|
|
1166
|
+
self._browser_context.set_default_navigation_timeout(0)
|
|
1167
|
+
self._browser_context.set_default_timeout(0)
|
|
1168
|
+
try:
|
|
1169
|
+
await asyncio.wait(
|
|
1170
|
+
[
|
|
1171
|
+
asyncio.create_task(
|
|
1172
|
+
self._browser_context._channel.send("pause", None)
|
|
1173
|
+
),
|
|
1174
|
+
self._closed_or_crashed_future,
|
|
1175
|
+
],
|
|
1176
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
1177
|
+
)
|
|
1178
|
+
finally:
|
|
1179
|
+
self._browser_context._set_default_navigation_timeout_impl(
|
|
1180
|
+
default_navigation_timeout
|
|
1181
|
+
)
|
|
1182
|
+
self._browser_context._set_default_timeout_impl(default_timeout)
|
|
1183
|
+
|
|
1184
|
+
async def pdf(
|
|
1185
|
+
self,
|
|
1186
|
+
scale: float = None,
|
|
1187
|
+
displayHeaderFooter: bool = None,
|
|
1188
|
+
headerTemplate: str = None,
|
|
1189
|
+
footerTemplate: str = None,
|
|
1190
|
+
printBackground: bool = None,
|
|
1191
|
+
landscape: bool = None,
|
|
1192
|
+
pageRanges: str = None,
|
|
1193
|
+
format: str = None,
|
|
1194
|
+
width: Union[str, float] = None,
|
|
1195
|
+
height: Union[str, float] = None,
|
|
1196
|
+
preferCSSPageSize: bool = None,
|
|
1197
|
+
margin: PdfMargins = None,
|
|
1198
|
+
path: Union[str, Path] = None,
|
|
1199
|
+
outline: bool = None,
|
|
1200
|
+
tagged: bool = None,
|
|
1201
|
+
) -> bytes:
|
|
1202
|
+
params = locals_to_params(locals())
|
|
1203
|
+
if "path" in params:
|
|
1204
|
+
del params["path"]
|
|
1205
|
+
encoded_binary = await self._channel.send("pdf", None, params)
|
|
1206
|
+
decoded_binary = base64.b64decode(encoded_binary)
|
|
1207
|
+
if path:
|
|
1208
|
+
make_dirs_for_file(path)
|
|
1209
|
+
await async_writefile(path, decoded_binary)
|
|
1210
|
+
return decoded_binary
|
|
1211
|
+
|
|
1212
|
+
@property
|
|
1213
|
+
def video(self) -> Optional[Video]:
|
|
1214
|
+
# Video is only exposed when the page actually produced a recording artifact.
|
|
1215
|
+
# The initializer carries the artifact; if absent, no video was recorded.
|
|
1216
|
+
if not self._video._artifact:
|
|
1217
|
+
return None
|
|
1218
|
+
return self._video
|
|
1219
|
+
|
|
1220
|
+
@property
|
|
1221
|
+
def screencast(self) -> Screencast:
|
|
1222
|
+
return self._screencast
|
|
1223
|
+
|
|
1224
|
+
@property
|
|
1225
|
+
def local_storage(self) -> WebStorage:
|
|
1226
|
+
return self._local_storage
|
|
1227
|
+
|
|
1228
|
+
@property
|
|
1229
|
+
def session_storage(self) -> WebStorage:
|
|
1230
|
+
return self._session_storage
|
|
1231
|
+
|
|
1232
|
+
def _close_error_with_reason(self) -> TargetClosedError:
|
|
1233
|
+
return TargetClosedError(
|
|
1234
|
+
self._close_reason or self._browser_context._effective_close_reason()
|
|
1235
|
+
)
|
|
1236
|
+
|
|
1237
|
+
def expect_event(
|
|
1238
|
+
self,
|
|
1239
|
+
event: str,
|
|
1240
|
+
predicate: Callable = None,
|
|
1241
|
+
timeout: float = None,
|
|
1242
|
+
) -> EventContextManagerImpl:
|
|
1243
|
+
return self._expect_event(
|
|
1244
|
+
event, predicate, timeout, f'waiting for event "{event}"'
|
|
1245
|
+
)
|
|
1246
|
+
|
|
1247
|
+
def _expect_event(
|
|
1248
|
+
self,
|
|
1249
|
+
event: str,
|
|
1250
|
+
predicate: Callable = None,
|
|
1251
|
+
timeout: float = None,
|
|
1252
|
+
log_line: str = None,
|
|
1253
|
+
) -> EventContextManagerImpl:
|
|
1254
|
+
if timeout is None:
|
|
1255
|
+
timeout = self._timeout_settings.timeout()
|
|
1256
|
+
waiter = Waiter(self, f"page.expect_event({event})")
|
|
1257
|
+
waiter.reject_on_timeout(
|
|
1258
|
+
timeout, f'Timeout {timeout}ms exceeded while waiting for event "{event}"'
|
|
1259
|
+
)
|
|
1260
|
+
if log_line:
|
|
1261
|
+
waiter.log(log_line)
|
|
1262
|
+
if event != Page.Events.Crash:
|
|
1263
|
+
waiter.reject_on_event(self, Page.Events.Crash, Error("Page crashed"))
|
|
1264
|
+
if event != Page.Events.Close:
|
|
1265
|
+
waiter.reject_on_event(
|
|
1266
|
+
self, Page.Events.Close, lambda: self._close_error_with_reason()
|
|
1267
|
+
)
|
|
1268
|
+
waiter.wait_for_event(self, event, predicate)
|
|
1269
|
+
return EventContextManagerImpl(waiter.result())
|
|
1270
|
+
|
|
1271
|
+
def expect_console_message(
|
|
1272
|
+
self,
|
|
1273
|
+
predicate: Callable[[ConsoleMessage], bool] = None,
|
|
1274
|
+
timeout: float = None,
|
|
1275
|
+
) -> EventContextManagerImpl[ConsoleMessage]:
|
|
1276
|
+
return self.expect_event(Page.Events.Console, predicate, timeout)
|
|
1277
|
+
|
|
1278
|
+
def expect_download(
|
|
1279
|
+
self,
|
|
1280
|
+
predicate: Callable[[Download], bool] = None,
|
|
1281
|
+
timeout: float = None,
|
|
1282
|
+
) -> EventContextManagerImpl[Download]:
|
|
1283
|
+
return self.expect_event(Page.Events.Download, predicate, timeout)
|
|
1284
|
+
|
|
1285
|
+
def expect_file_chooser(
|
|
1286
|
+
self,
|
|
1287
|
+
predicate: Callable[[FileChooser], bool] = None,
|
|
1288
|
+
timeout: float = None,
|
|
1289
|
+
) -> EventContextManagerImpl[FileChooser]:
|
|
1290
|
+
return self.expect_event(Page.Events.FileChooser, predicate, timeout)
|
|
1291
|
+
|
|
1292
|
+
def expect_navigation(
|
|
1293
|
+
self,
|
|
1294
|
+
url: URLMatch = None,
|
|
1295
|
+
waitUntil: DocumentLoadState = None,
|
|
1296
|
+
timeout: float = None,
|
|
1297
|
+
) -> EventContextManagerImpl[Response]:
|
|
1298
|
+
return self.main_frame.expect_navigation(url, waitUntil, timeout)
|
|
1299
|
+
|
|
1300
|
+
def expect_popup(
|
|
1301
|
+
self,
|
|
1302
|
+
predicate: Callable[["Page"], bool] = None,
|
|
1303
|
+
timeout: float = None,
|
|
1304
|
+
) -> EventContextManagerImpl["Page"]:
|
|
1305
|
+
return self.expect_event(Page.Events.Popup, predicate, timeout)
|
|
1306
|
+
|
|
1307
|
+
def expect_request(
|
|
1308
|
+
self,
|
|
1309
|
+
urlOrPredicate: URLMatchRequest,
|
|
1310
|
+
timeout: float = None,
|
|
1311
|
+
) -> EventContextManagerImpl[Request]:
|
|
1312
|
+
def my_predicate(request: Request) -> Union[bool, Awaitable[bool]]:
|
|
1313
|
+
if not callable(urlOrPredicate):
|
|
1314
|
+
return url_matches(
|
|
1315
|
+
self._browser_context._base_url,
|
|
1316
|
+
request.url,
|
|
1317
|
+
urlOrPredicate,
|
|
1318
|
+
)
|
|
1319
|
+
return urlOrPredicate(request)
|
|
1320
|
+
|
|
1321
|
+
trimmed_url = trim_url(urlOrPredicate)
|
|
1322
|
+
log_line = f"waiting for request {trimmed_url}" if trimmed_url else None
|
|
1323
|
+
return self._expect_event(
|
|
1324
|
+
Page.Events.Request,
|
|
1325
|
+
predicate=my_predicate,
|
|
1326
|
+
timeout=timeout,
|
|
1327
|
+
log_line=log_line,
|
|
1328
|
+
)
|
|
1329
|
+
|
|
1330
|
+
def expect_request_finished(
|
|
1331
|
+
self,
|
|
1332
|
+
predicate: Callable[["Request"], bool] = None,
|
|
1333
|
+
timeout: float = None,
|
|
1334
|
+
) -> EventContextManagerImpl[Request]:
|
|
1335
|
+
return self.expect_event(
|
|
1336
|
+
Page.Events.RequestFinished, predicate=predicate, timeout=timeout
|
|
1337
|
+
)
|
|
1338
|
+
|
|
1339
|
+
def expect_response(
|
|
1340
|
+
self,
|
|
1341
|
+
urlOrPredicate: URLMatchResponse,
|
|
1342
|
+
timeout: float = None,
|
|
1343
|
+
) -> EventContextManagerImpl[Response]:
|
|
1344
|
+
def my_predicate(request: Response) -> Union[bool, Awaitable[bool]]:
|
|
1345
|
+
if not callable(urlOrPredicate):
|
|
1346
|
+
return url_matches(
|
|
1347
|
+
self._browser_context._base_url,
|
|
1348
|
+
request.url,
|
|
1349
|
+
urlOrPredicate,
|
|
1350
|
+
)
|
|
1351
|
+
return urlOrPredicate(request)
|
|
1352
|
+
|
|
1353
|
+
trimmed_url = trim_url(urlOrPredicate)
|
|
1354
|
+
log_line = f"waiting for response {trimmed_url}" if trimmed_url else None
|
|
1355
|
+
return self._expect_event(
|
|
1356
|
+
Page.Events.Response,
|
|
1357
|
+
predicate=my_predicate,
|
|
1358
|
+
timeout=timeout,
|
|
1359
|
+
log_line=log_line,
|
|
1360
|
+
)
|
|
1361
|
+
|
|
1362
|
+
def expect_websocket(
|
|
1363
|
+
self,
|
|
1364
|
+
predicate: Callable[["WebSocket"], bool] = None,
|
|
1365
|
+
timeout: float = None,
|
|
1366
|
+
) -> EventContextManagerImpl["WebSocket"]:
|
|
1367
|
+
return self.expect_event("websocket", predicate, timeout)
|
|
1368
|
+
|
|
1369
|
+
def expect_worker(
|
|
1370
|
+
self,
|
|
1371
|
+
predicate: Callable[["Worker"], bool] = None,
|
|
1372
|
+
timeout: float = None,
|
|
1373
|
+
) -> EventContextManagerImpl["Worker"]:
|
|
1374
|
+
return self.expect_event("worker", predicate, timeout)
|
|
1375
|
+
|
|
1376
|
+
async def set_checked(
|
|
1377
|
+
self,
|
|
1378
|
+
selector: str,
|
|
1379
|
+
checked: bool,
|
|
1380
|
+
position: Position = None,
|
|
1381
|
+
timeout: float = None,
|
|
1382
|
+
force: bool = None,
|
|
1383
|
+
noWaitAfter: bool = None,
|
|
1384
|
+
strict: bool = None,
|
|
1385
|
+
trial: bool = None,
|
|
1386
|
+
scroll: Literal["auto", "none"] = None,
|
|
1387
|
+
) -> None:
|
|
1388
|
+
if checked:
|
|
1389
|
+
await self.check(
|
|
1390
|
+
selector=selector,
|
|
1391
|
+
position=position,
|
|
1392
|
+
timeout=timeout,
|
|
1393
|
+
force=force,
|
|
1394
|
+
strict=strict,
|
|
1395
|
+
trial=trial,
|
|
1396
|
+
scroll=scroll,
|
|
1397
|
+
)
|
|
1398
|
+
else:
|
|
1399
|
+
await self.uncheck(
|
|
1400
|
+
selector=selector,
|
|
1401
|
+
position=position,
|
|
1402
|
+
timeout=timeout,
|
|
1403
|
+
force=force,
|
|
1404
|
+
strict=strict,
|
|
1405
|
+
trial=trial,
|
|
1406
|
+
scroll=scroll,
|
|
1407
|
+
)
|
|
1408
|
+
|
|
1409
|
+
async def add_locator_handler(
|
|
1410
|
+
self,
|
|
1411
|
+
locator: "Locator",
|
|
1412
|
+
handler: Union[Callable[["Locator"], Any], Callable[[], Any]],
|
|
1413
|
+
noWaitAfter: bool = None,
|
|
1414
|
+
times: int = None,
|
|
1415
|
+
) -> None:
|
|
1416
|
+
if locator._frame != self._main_frame:
|
|
1417
|
+
raise Error("Locator must belong to the main frame of this page")
|
|
1418
|
+
if times == 0:
|
|
1419
|
+
return
|
|
1420
|
+
uid = await self._channel.send(
|
|
1421
|
+
"registerLocatorHandler",
|
|
1422
|
+
None,
|
|
1423
|
+
{
|
|
1424
|
+
"selector": locator._selector,
|
|
1425
|
+
"noWaitAfter": noWaitAfter,
|
|
1426
|
+
},
|
|
1427
|
+
)
|
|
1428
|
+
self._locator_handlers[uid] = LocatorHandler(
|
|
1429
|
+
handler=handler, times=times, locator=locator
|
|
1430
|
+
)
|
|
1431
|
+
|
|
1432
|
+
async def _on_locator_handler_triggered(self, uid: str) -> None:
|
|
1433
|
+
remove = False
|
|
1434
|
+
try:
|
|
1435
|
+
handler = self._locator_handlers.get(uid)
|
|
1436
|
+
if handler and handler.times != 0:
|
|
1437
|
+
if handler.times is not None:
|
|
1438
|
+
handler.times -= 1
|
|
1439
|
+
if self._dispatcher_fiber:
|
|
1440
|
+
handler_finished_future = self._loop.create_future()
|
|
1441
|
+
|
|
1442
|
+
def _handler() -> None:
|
|
1443
|
+
try:
|
|
1444
|
+
handler()
|
|
1445
|
+
handler_finished_future.set_result(None)
|
|
1446
|
+
except Exception as e:
|
|
1447
|
+
handler_finished_future.set_exception(e)
|
|
1448
|
+
|
|
1449
|
+
g = LocatorHandlerGreenlet(_handler)
|
|
1450
|
+
g.switch()
|
|
1451
|
+
await handler_finished_future
|
|
1452
|
+
else:
|
|
1453
|
+
coro_or_future = handler()
|
|
1454
|
+
if coro_or_future:
|
|
1455
|
+
await coro_or_future
|
|
1456
|
+
remove = handler.times == 0
|
|
1457
|
+
finally:
|
|
1458
|
+
if remove:
|
|
1459
|
+
del self._locator_handlers[uid]
|
|
1460
|
+
try:
|
|
1461
|
+
await self._connection.wrap_api_call(
|
|
1462
|
+
lambda: self._channel.send(
|
|
1463
|
+
"resolveLocatorHandlerNoReply",
|
|
1464
|
+
None,
|
|
1465
|
+
{"uid": uid, "remove": remove},
|
|
1466
|
+
),
|
|
1467
|
+
is_internal=True,
|
|
1468
|
+
)
|
|
1469
|
+
except Error:
|
|
1470
|
+
pass
|
|
1471
|
+
|
|
1472
|
+
async def remove_locator_handler(self, locator: "Locator") -> None:
|
|
1473
|
+
for uid, data in self._locator_handlers.copy().items():
|
|
1474
|
+
if data.locator._equals(locator):
|
|
1475
|
+
del self._locator_handlers[uid]
|
|
1476
|
+
self._channel.send_no_reply(
|
|
1477
|
+
"unregisterLocatorHandler",
|
|
1478
|
+
None,
|
|
1479
|
+
{"uid": uid},
|
|
1480
|
+
)
|
|
1481
|
+
|
|
1482
|
+
async def requests(self) -> List[Request]:
|
|
1483
|
+
request_objects = await self._channel.send("requests", None)
|
|
1484
|
+
return [from_channel(r) for r in request_objects]
|
|
1485
|
+
|
|
1486
|
+
async def console_messages(
|
|
1487
|
+
self, filter: Literal["all", "since-navigation"] = None
|
|
1488
|
+
) -> List[ConsoleMessage]:
|
|
1489
|
+
message_dicts = await self._channel.send(
|
|
1490
|
+
"consoleMessages", None, locals_to_params(locals())
|
|
1491
|
+
)
|
|
1492
|
+
return [
|
|
1493
|
+
ConsoleMessage(
|
|
1494
|
+
{**event, "page": self._channel}, self._loop, self._dispatcher_fiber
|
|
1495
|
+
)
|
|
1496
|
+
for event in message_dicts
|
|
1497
|
+
]
|
|
1498
|
+
|
|
1499
|
+
async def page_errors(
|
|
1500
|
+
self, filter: Literal["all", "since-navigation"] = None
|
|
1501
|
+
) -> List[Error]:
|
|
1502
|
+
error_objects = await self._channel.send(
|
|
1503
|
+
"pageErrors", None, locals_to_params(locals())
|
|
1504
|
+
)
|
|
1505
|
+
return [parse_error(error["error"]) for error in error_objects]
|
|
1506
|
+
|
|
1507
|
+
async def clear_console_messages(self) -> None:
|
|
1508
|
+
await self._channel.send("clearConsoleMessages", None)
|
|
1509
|
+
|
|
1510
|
+
async def clear_page_errors(self) -> None:
|
|
1511
|
+
await self._channel.send("clearPageErrors", None)
|
|
1512
|
+
|
|
1513
|
+
async def pick_locator(self) -> "Locator":
|
|
1514
|
+
selector = await self._channel.send("pickLocator", None, {})
|
|
1515
|
+
return self.locator(selector)
|
|
1516
|
+
|
|
1517
|
+
async def cancel_pick_locator(self) -> None:
|
|
1518
|
+
await self._channel.send("cancelPickLocator", None, {})
|
|
1519
|
+
|
|
1520
|
+
|
|
1521
|
+
class Worker(ChannelOwner):
|
|
1522
|
+
Events = SimpleNamespace(Close="close", Console="console")
|
|
1523
|
+
|
|
1524
|
+
def __init__(
|
|
1525
|
+
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
|
|
1526
|
+
) -> None:
|
|
1527
|
+
super().__init__(parent, type, guid, initializer)
|
|
1528
|
+
self._set_event_to_subscription_mapping({Worker.Events.Console: "console"})
|
|
1529
|
+
self._channel.on("close", lambda _: self._on_close())
|
|
1530
|
+
self._page: Optional[Page] = None
|
|
1531
|
+
self._context: Optional["BrowserContext"] = None
|
|
1532
|
+
|
|
1533
|
+
def __repr__(self) -> str:
|
|
1534
|
+
return f"<Worker url={self.url!r}>"
|
|
1535
|
+
|
|
1536
|
+
def _on_close(self) -> None:
|
|
1537
|
+
if self._page:
|
|
1538
|
+
self._page._workers.remove(self)
|
|
1539
|
+
if self._context:
|
|
1540
|
+
self._context._service_workers.remove(self)
|
|
1541
|
+
self.emit(Worker.Events.Close, self)
|
|
1542
|
+
|
|
1543
|
+
@property
|
|
1544
|
+
def url(self) -> str:
|
|
1545
|
+
return self._initializer["url"]
|
|
1546
|
+
|
|
1547
|
+
async def evaluate(self, expression: str, arg: Serializable = None) -> Any:
|
|
1548
|
+
return parse_result(
|
|
1549
|
+
await self._channel.send(
|
|
1550
|
+
"evaluateExpression",
|
|
1551
|
+
None,
|
|
1552
|
+
dict(
|
|
1553
|
+
expression=expression,
|
|
1554
|
+
arg=serialize_argument(arg),
|
|
1555
|
+
),
|
|
1556
|
+
)
|
|
1557
|
+
)
|
|
1558
|
+
|
|
1559
|
+
async def evaluate_handle(
|
|
1560
|
+
self, expression: str, arg: Serializable = None
|
|
1561
|
+
) -> JSHandle:
|
|
1562
|
+
return from_channel(
|
|
1563
|
+
await self._channel.send(
|
|
1564
|
+
"evaluateExpressionHandle",
|
|
1565
|
+
None,
|
|
1566
|
+
dict(
|
|
1567
|
+
expression=expression,
|
|
1568
|
+
arg=serialize_argument(arg),
|
|
1569
|
+
),
|
|
1570
|
+
)
|
|
1571
|
+
)
|
|
1572
|
+
|
|
1573
|
+
def expect_event(
|
|
1574
|
+
self,
|
|
1575
|
+
event: str,
|
|
1576
|
+
predicate: Callable = None,
|
|
1577
|
+
timeout: float = None,
|
|
1578
|
+
) -> EventContextManagerImpl:
|
|
1579
|
+
if timeout is None:
|
|
1580
|
+
if self._page:
|
|
1581
|
+
timeout = self._page._timeout_settings.timeout()
|
|
1582
|
+
elif self._context:
|
|
1583
|
+
timeout = self._context._timeout_settings.timeout()
|
|
1584
|
+
else:
|
|
1585
|
+
timeout = 30000
|
|
1586
|
+
waiter = Waiter(self, f"worker.expect_event({event})")
|
|
1587
|
+
waiter.reject_on_timeout(
|
|
1588
|
+
cast(float, timeout),
|
|
1589
|
+
f'Timeout {timeout}ms exceeded while waiting for event "{event}"',
|
|
1590
|
+
)
|
|
1591
|
+
if event != Worker.Events.Close:
|
|
1592
|
+
waiter.reject_on_event(
|
|
1593
|
+
self, Worker.Events.Close, lambda: TargetClosedError()
|
|
1594
|
+
)
|
|
1595
|
+
waiter.wait_for_event(self, event, predicate)
|
|
1596
|
+
return EventContextManagerImpl(waiter.result())
|
|
1597
|
+
|
|
1598
|
+
|
|
1599
|
+
class BindingCall(ChannelOwner):
|
|
1600
|
+
def __init__(
|
|
1601
|
+
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
|
|
1602
|
+
) -> None:
|
|
1603
|
+
super().__init__(parent, type, guid, initializer)
|
|
1604
|
+
|
|
1605
|
+
async def call(self, func: Callable) -> None:
|
|
1606
|
+
try:
|
|
1607
|
+
frame = from_channel(self._initializer["frame"])
|
|
1608
|
+
source = dict(context=frame._page.context, page=frame._page, frame=frame)
|
|
1609
|
+
if self._initializer.get("handle"):
|
|
1610
|
+
result = func(source, from_channel(self._initializer["handle"]))
|
|
1611
|
+
else:
|
|
1612
|
+
func_args = list(map(parse_result, self._initializer["args"]))
|
|
1613
|
+
result = func(source, *func_args)
|
|
1614
|
+
if inspect.iscoroutine(result):
|
|
1615
|
+
result = await result
|
|
1616
|
+
self._channel.send_may_fail(
|
|
1617
|
+
"resolve", None, dict(result=serialize_argument(result))
|
|
1618
|
+
)
|
|
1619
|
+
except Exception as e:
|
|
1620
|
+
tb = sys.exc_info()[2]
|
|
1621
|
+
self._channel.send_may_fail(
|
|
1622
|
+
"reject", None, dict(error=dict(error=serialize_error(e, tb)))
|
|
1623
|
+
)
|
|
1624
|
+
|
|
1625
|
+
|
|
1626
|
+
def trim_url(param: Union[URLMatchRequest, URLMatchResponse]) -> Optional[str]:
|
|
1627
|
+
if isinstance(param, re.Pattern):
|
|
1628
|
+
return trim_end(param.pattern)
|
|
1629
|
+
if isinstance(param, str):
|
|
1630
|
+
return trim_end(param)
|
|
1631
|
+
return None
|
|
1632
|
+
|
|
1633
|
+
|
|
1634
|
+
def trim_end(s: str) -> str:
|
|
1635
|
+
if len(s) > 50:
|
|
1636
|
+
return s[:50] + "\u2026"
|
|
1637
|
+
return s
|