Skip to content

Commit 4820088

Browse files
authored
fix(urlMatcher): normalize URLs to align with Node.js parser behavior (#1734)
1 parent fcd0444 commit 4820088

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

playwright/src/main/java/com/microsoft/playwright/impl/UrlMatcher.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.net.URI;
2222
import java.net.URISyntaxException;
2323
import java.net.URL;
24+
import java.util.Arrays;
2425
import java.util.function.Predicate;
2526
import java.util.regex.Pattern;
2627

@@ -65,6 +66,21 @@ private static String resolveUrl(String baseUrl, String spec) {
6566
}
6667
}
6768

69+
private static String normaliseUrl(String spec) {
70+
try {
71+
// Align with the Node.js URL parser which automatically adds a slash to the path if it is empty.
72+
URI url = new URI(spec);
73+
if (url.getScheme() != null &&
74+
Arrays.asList("http", "https", "ws", "wss").contains(url.getScheme()) &&
75+
url.getPath().isEmpty()) {
76+
return new URI(url.getScheme(), url.getAuthority(), "/", url.getQuery(), url.getFragment()).toString();
77+
}
78+
return url.toString();
79+
} catch (URISyntaxException e) {
80+
return spec;
81+
}
82+
}
83+
6884
UrlMatcher(URL baseURL, String glob) {
6985
this(baseURL, glob, null, null);
7086
}
@@ -101,7 +117,7 @@ private static boolean testImpl(String baseURL, Pattern pattern, Predicate<Strin
101117
if (baseURL != null && Pattern.compile("^https?://").matcher(baseURL).find() && Pattern.compile("^wss?://").matcher(value).find()) {
102118
baseURL = baseURL.replaceFirst("^http", "ws");
103119
}
104-
glob = resolveUrl(baseURL, glob);
120+
glob = normaliseUrl(resolveUrl(baseURL, glob));
105121
}
106122
return Pattern.compile(globToRegex(glob)).matcher(value).find();
107123
}

playwright/src/test/java/com/microsoft/playwright/TestRouteWebSocket.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import java.io.IOException;
1111
import java.nio.charset.StandardCharsets;
12+
import java.util.ArrayList;
13+
import java.util.List;
1214
import java.util.concurrent.ExecutionException;
1315
import java.util.concurrent.Future;
1416
import java.util.regex.Pattern;
@@ -349,4 +351,44 @@ public void shouldWorkWithBaseURL(Browser browser) throws Exception {
349351
asList("open", "message: data=echo origin=ws://localhost:" + webSocketServer.getPort() + " lastEventId="),
350352
newPage.evaluate("window.log"));
351353
}
354+
355+
@Test
356+
public void shouldWorkWithNoTrailingSlash(Page page) throws Exception {
357+
List<String> log = new ArrayList<>();
358+
359+
// No trailing slash in the route pattern
360+
page.routeWebSocket("ws://localhost:" + webSocketServer.getPort(), ws -> {
361+
ws.onMessage(message -> {
362+
log.add(message.text());
363+
ws.send("response");
364+
});
365+
});
366+
367+
page.navigate("about:blank");
368+
page.evaluate("({ port }) => {\n" +
369+
" window.log = [];\n" +
370+
" // No trailing slash in WebSocket URL\n" +
371+
" window.ws = new WebSocket('ws://localhost:' + port);\n" +
372+
" window.ws.addEventListener('message', event => window.log.push(event.data));\n" +
373+
"}", mapOf("port", webSocketServer.getPort()));
374+
375+
// Wait for WebSocket to be ready (readyState === 1)
376+
page.waitForCondition(() -> {
377+
Integer result = (Integer) page.evaluate("() => window.ws.readyState");
378+
return result == 1;
379+
});
380+
381+
page.evaluate("() => window.ws.send('query')");
382+
383+
// Wait and verify server received message
384+
page.waitForCondition(() -> log.size() >= 1);
385+
assertEquals(asList("query"), log);
386+
387+
// Wait and verify client received response
388+
page.waitForCondition(() -> {
389+
Boolean result = (Boolean) page.evaluate("() => window.log.length >= 1");
390+
return result;
391+
});
392+
assertEquals(asList("response"), page.evaluate("window.log"));
393+
}
352394
}

0 commit comments

Comments
 (0)