Skip to content

Commit 396fc64

Browse files
authored
feat(websocket): implement Web Sockets (microsoft#265)
1 parent d05857b commit 396fc64

File tree

7 files changed

+99
-4
lines changed

7 files changed

+99
-4
lines changed

playwright/async_api.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
from playwright.network import Request as RequestImpl
6363
from playwright.network import Response as ResponseImpl
6464
from playwright.network import Route as RouteImpl
65+
from playwright.network import WebSocket as WebSocketImpl
6566
from playwright.page import BindingCall as BindingCallImpl
6667
from playwright.page import Page as PageImpl
6768
from playwright.page import Worker as WorkerImpl
@@ -488,6 +489,26 @@ async def continue_(
488489
mapping.register(RouteImpl, Route)
489490

490491

492+
class WebSocket(AsyncBase):
493+
def __init__(self, obj: WebSocketImpl):
494+
super().__init__(obj)
495+
496+
@property
497+
def url(self) -> str:
498+
"""WebSocket.url
499+
500+
Contains the URL of the WebSocket.
501+
502+
Returns
503+
-------
504+
str
505+
"""
506+
return mapping.from_maybe_impl(self._impl_obj.url)
507+
508+
509+
mapping.register(WebSocketImpl, WebSocket)
510+
511+
491512
class Keyboard(AsyncBase):
492513
def __init__(self, obj: KeyboardImpl):
493514
super().__init__(obj)

playwright/network.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import json
1717
import mimetypes
1818
from pathlib import Path
19+
from types import SimpleNamespace
1920
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
2021
from urllib import parse
2122

@@ -257,6 +258,49 @@ def frame(self) -> "Frame":
257258
return self._request.frame
258259

259260

261+
class WebSocket(ChannelOwner):
262+
263+
Events = SimpleNamespace(
264+
Close="close",
265+
FrameReceived="framereceived",
266+
FrameSent="framesent",
267+
Error="socketerror",
268+
)
269+
270+
def __init__(
271+
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
272+
) -> None:
273+
super().__init__(parent, type, guid, initializer)
274+
self._channel.on(
275+
"frameSent",
276+
lambda params: self._on_frame_sent(params["opcode"], params["data"]),
277+
)
278+
self._channel.on(
279+
"frameReceived",
280+
lambda params: self._on_frame_received(params["opcode"], params["data"]),
281+
)
282+
self._channel.on(
283+
"error", lambda params: self.emit(WebSocket.Events.Error, params["error"])
284+
)
285+
self._channel.on("close", lambda params: self.emit(WebSocket.Events.Close))
286+
287+
@property
288+
def url(self) -> str:
289+
return self._initializer["url"]
290+
291+
def _on_frame_sent(self, opcode: int, data: str) -> None:
292+
if opcode == 2:
293+
self.emit(WebSocket.Events.FrameSent, base64.b64decode(data))
294+
else:
295+
self.emit(WebSocket.Events.FrameSent, data)
296+
297+
def _on_frame_received(self, opcode: int, data: str) -> None:
298+
if opcode == 2:
299+
self.emit(WebSocket.Events.FrameReceived, base64.b64decode(data))
300+
else:
301+
self.emit(WebSocket.Events.FrameReceived, data)
302+
303+
260304
def serialize_headers(headers: Dict[str, str]) -> List[Header]:
261305
return [{"name": name, "value": value} for name, value in headers.items()]
262306

playwright/object_factory.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from playwright.element_handle import ElementHandle
2727
from playwright.frame import Frame
2828
from playwright.js_handle import JSHandle
29-
from playwright.network import Request, Response, Route
29+
from playwright.network import Request, Response, Route, WebSocket
3030
from playwright.page import BindingCall, Page, Worker
3131
from playwright.playwright import Playwright
3232
from playwright.selectors import Selectors
@@ -81,6 +81,8 @@ def create_remote_object(
8181
return Response(parent, type, guid, initializer)
8282
if type == "Route":
8383
return Route(parent, type, guid, initializer)
84+
if type == "WebSocket":
85+
return WebSocket(parent, type, guid, initializer)
8486
if type == "Worker":
8587
return Worker(parent, type, guid, initializer)
8688
if type == "Selectors":

playwright/page.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class Page(ChannelOwner):
9191
FrameNavigated="framenavigated",
9292
Load="load",
9393
Popup="popup",
94+
WebSocket="websocket",
9495
Worker="worker",
9596
)
9697
accessibility: Accessibility
@@ -213,6 +214,12 @@ def __init__(
213214
params["relativePath"]
214215
),
215216
)
217+
self._channel.on(
218+
"webSocket",
219+
lambda params: self.emit(
220+
Page.Events.WebSocket, from_channel(params["webSocket"])
221+
),
222+
)
216223
self._channel.on(
217224
"worker", lambda params: self._on_worker(from_channel(params["worker"]))
218225
)

playwright/sync_api.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
from playwright.network import Request as RequestImpl
6262
from playwright.network import Response as ResponseImpl
6363
from playwright.network import Route as RouteImpl
64+
from playwright.network import WebSocket as WebSocketImpl
6465
from playwright.page import BindingCall as BindingCallImpl
6566
from playwright.page import Page as PageImpl
6667
from playwright.page import Worker as WorkerImpl
@@ -494,6 +495,26 @@ def continue_(
494495
mapping.register(RouteImpl, Route)
495496

496497

498+
class WebSocket(SyncBase):
499+
def __init__(self, obj: WebSocketImpl):
500+
super().__init__(obj)
501+
502+
@property
503+
def url(self) -> str:
504+
"""WebSocket.url
505+
506+
Contains the URL of the WebSocket.
507+
508+
Returns
509+
-------
510+
str
511+
"""
512+
return mapping.from_maybe_impl(self._impl_obj.url)
513+
514+
515+
mapping.register(WebSocketImpl, WebSocket)
516+
517+
497518
class Keyboard(SyncBase):
498519
def __init__(self, obj: KeyboardImpl):
499520
super().__init__(obj)

scripts/expected_api_mismatch.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,3 @@ Parameter not implemented: BrowserContext.waitForEvent(optionsOrPredicate=)
121121
# 1.6 Todo
122122
Parameter not implemented: Browser.newPage(proxy=)
123123
Parameter not implemented: Browser.newContext(proxy=)
124-
Method not implemented: WebSocket.url

scripts/generate_api.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from playwright.frame import Frame
4040
from playwright.input import Keyboard, Mouse, Touchscreen
4141
from playwright.js_handle import JSHandle, Serializable
42-
from playwright.network import Request, Response, Route
42+
from playwright.network import Request, Response, Route, WebSocket
4343
from playwright.page import BindingCall, Page, Worker
4444
from playwright.playwright import Playwright
4545
from playwright.selectors import Selectors
@@ -166,7 +166,7 @@ def return_value(value: Any) -> List[str]:
166166
from playwright.helper import ConsoleMessageLocation, Credentials, MousePosition, Error, FilePayload, SelectOption, RequestFailure, Viewport, DeviceDescriptor, IntSize, FloatRect, Geolocation, ProxyServer, PdfMargins, ResourceTiming, RecordHarOptions
167167
from playwright.input import Keyboard as KeyboardImpl, Mouse as MouseImpl, Touchscreen as TouchscreenImpl
168168
from playwright.js_handle import JSHandle as JSHandleImpl
169-
from playwright.network import Request as RequestImpl, Response as ResponseImpl, Route as RouteImpl
169+
from playwright.network import Request as RequestImpl, Response as ResponseImpl, Route as RouteImpl, WebSocket as WebSocketImpl
170170
from playwright.page import BindingCall as BindingCallImpl, Page as PageImpl, Worker as WorkerImpl
171171
from playwright.playwright import Playwright as PlaywrightImpl
172172
from playwright.selectors import Selectors as SelectorsImpl
@@ -177,6 +177,7 @@ def return_value(value: Any) -> List[str]:
177177
Request,
178178
Response,
179179
Route,
180+
WebSocket,
180181
Keyboard,
181182
Mouse,
182183
Touchscreen,

0 commit comments

Comments
 (0)