Skip to content

Commit 00fbc3c

Browse files
authored
fix(webSocketRoute): allow no trailing slash in route matching (#2687)
1 parent 4f2cdde commit 00fbc3c

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

playwright/_impl/_helper.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
Union,
3535
cast,
3636
)
37-
from urllib.parse import urljoin
37+
from urllib.parse import urljoin, urlparse
3838

3939
from playwright._impl._api_structures import NameValue
4040
from playwright._impl._errors import (
@@ -157,6 +157,10 @@ def url_matches(
157157
base_url = re.sub(r"^http", "ws", base_url)
158158
if base_url:
159159
match = urljoin(base_url, match)
160+
parsed = urlparse(match)
161+
if parsed.path == "":
162+
parsed = parsed._replace(path="/")
163+
match = parsed.geturl()
160164
if isinstance(match, str):
161165
match = glob_to_regex(match)
162166
if isinstance(match, Pattern):

tests/async/test_route_web_socket.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,3 +346,36 @@ async def _handle_ws(ws: WebSocketRoute) -> None:
346346
f"message: data=echo origin=ws://localhost:{server.PORT} lastEventId=",
347347
],
348348
)
349+
350+
351+
async def test_should_work_with_no_trailing_slash(page: Page, server: Server) -> None:
352+
log: list[str] = []
353+
354+
async def handle_ws(ws: WebSocketRoute) -> None:
355+
def on_message(message: Union[str, bytes]) -> None:
356+
assert isinstance(message, str)
357+
log.append(message)
358+
ws.send("response")
359+
360+
ws.on_message(on_message)
361+
362+
# No trailing slash in the route pattern
363+
await page.route_web_socket(f"ws://localhost:{server.PORT}", handle_ws)
364+
365+
await page.goto("about:blank")
366+
await page.evaluate(
367+
"""({ port }) => {
368+
window.log = [];
369+
// No trailing slash in WebSocket URL
370+
window.ws = new WebSocket('ws://localhost:' + port);
371+
window.ws.addEventListener('message', event => window.log.push(event.data));
372+
}""",
373+
{"port": server.PORT},
374+
)
375+
376+
await assert_equal(
377+
lambda: page.evaluate("window.ws.readyState"), 1 # WebSocket.OPEN
378+
)
379+
await page.evaluate("window.ws.send('query')")
380+
await assert_equal(lambda: log, ["query"])
381+
await assert_equal(lambda: page.evaluate("window.log"), ["response"])

tests/sync/test_route_web_socket.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,34 @@ def _handle_ws(ws: WebSocketRoute) -> None:
340340
f"message: data=echo origin=ws://localhost:{server.PORT} lastEventId=",
341341
],
342342
)
343+
344+
345+
def test_should_work_with_no_trailing_slash(page: Page, server: Server) -> None:
346+
log: list[str] = []
347+
348+
async def handle_ws(ws: WebSocketRoute) -> None:
349+
def on_message(message: Union[str, bytes]) -> None:
350+
assert isinstance(message, str)
351+
log.append(message)
352+
ws.send("response")
353+
354+
ws.on_message(on_message)
355+
356+
# No trailing slash in the route pattern
357+
page.route_web_socket(f"ws://localhost:{server.PORT}", handle_ws)
358+
359+
page.goto("about:blank")
360+
page.evaluate(
361+
"""({ port }) => {
362+
window.log = [];
363+
// No trailing slash in WebSocket URL
364+
window.ws = new WebSocket('ws://localhost:' + port);
365+
window.ws.addEventListener('message', event => window.log.push(event.data));
366+
}""",
367+
{"port": server.PORT},
368+
)
369+
370+
assert_equal(lambda: page.evaluate("window.ws.readyState"), 1) # WebSocket.OPEN
371+
page.evaluate("window.ws.send('query')")
372+
assert_equal(lambda: log, ["query"])
373+
assert_equal(lambda: page.evaluate("window.log"), ["response"])

0 commit comments

Comments
 (0)