mirror of
https://github.com/microsoft/playwright-java.git
synced 2025-12-29 19:01:05 +00:00
240 lines
12 KiB
Java
240 lines
12 KiB
Java
/*
|
|
* Copyright (c) Microsoft Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.microsoft.playwright;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import com.microsoft.playwright.impl.PlaywrightImpl;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.Future;
|
|
import java.util.regex.Pattern;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
public class TestPageInterception extends TestBase {
|
|
@Test
|
|
void shouldWorkWithNavigationSmoke() {
|
|
HashMap<String, Request> requests = new HashMap<>();
|
|
page.route("**/*", route -> {
|
|
String[] parts = route.request().url().split("/");
|
|
requests.put(parts[parts.length - 1], route.request());
|
|
route.resume();
|
|
});
|
|
server.setRedirect("/rrredirect", "/frames/one-frame.html");
|
|
page.navigate(server.PREFIX + "/rrredirect");
|
|
assertTrue(requests.get("rrredirect").isNavigationRequest());
|
|
assertTrue(requests.get("frame.html").isNavigationRequest());
|
|
assertFalse(requests.get("script.js").isNavigationRequest());
|
|
assertFalse(requests.get("style.css").isNavigationRequest());
|
|
}
|
|
|
|
@Test
|
|
void shouldInterceptAfterAServiceWorker() {
|
|
page.navigate(server.PREFIX + "/serviceworkers/fetchdummy/sw.html");
|
|
page.evaluate("() => window['activationPromise']");
|
|
|
|
// Sanity check.
|
|
Object swResponse = page.evaluate("() => window['fetchDummy']('foo')");
|
|
assertEquals("responseFromServiceWorker:foo", swResponse);
|
|
|
|
page.route("**/foo", route -> {
|
|
int slash = route.request().url().lastIndexOf("/");
|
|
String name = route.request().url().substring(slash + 1);
|
|
route.fulfill(new Route.FulfillOptions()
|
|
.setStatus(200)
|
|
.setContentType("text/css").setBody("responseFromInterception:" + name));
|
|
});
|
|
|
|
// Page route is applied after service worker fetch event.
|
|
Object swResponse2 = page.evaluate("() => window['fetchDummy']('foo')");
|
|
assertEquals("responseFromServiceWorker:foo", swResponse2);
|
|
|
|
// Page route is not applied to service worker initiated fetch.
|
|
Object nonInterceptedResponse = page.evaluate("() => window['fetchDummy']('passthrough')");
|
|
assertEquals("FAILURE: Not Found", nonInterceptedResponse);
|
|
|
|
// Firefox does not want to fetch the redirect for some reason.
|
|
if (!isFirefox()) {
|
|
// Page route is not applied to service worker initiated fetch with redirect.
|
|
server.setRedirect("/serviceworkers/fetchdummy/passthrough", "/simple.json");
|
|
Object redirectedResponse = page.evaluate("() => window['fetchDummy']('passthrough')");
|
|
assertEquals("{\"foo\": \"bar\"}\n", redirectedResponse);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
void shouldFulfillInterceptedResponseUsingAlias() {
|
|
page.route("**/*", route -> {
|
|
APIResponse response = route.fetch();
|
|
route.fulfill(new Route.FulfillOptions().setResponse(response));
|
|
});
|
|
Response response = page.navigate(server.PREFIX + "/empty.html");
|
|
assertEquals(200, response.status());
|
|
assertTrue(response.headers().get("content-type").contains("text/html"));
|
|
}
|
|
|
|
@Test
|
|
void shouldSupportTimeoutOptionInRouteFetch() {
|
|
server.setRoute("/slow", exchange -> {
|
|
exchange.getResponseHeaders().set("Content-type", "text/plain");
|
|
exchange.sendResponseHeaders(200, 4096);
|
|
});
|
|
|
|
page.route("**/*", route -> {
|
|
PlaywrightException error = assertThrows(PlaywrightException.class,
|
|
() -> route.fetch(new Route.FetchOptions().setTimeout(1000)));
|
|
assertTrue(error.getMessage().contains("Timeout 1000ms exceeded"), error.getMessage());
|
|
});
|
|
PlaywrightException error = assertThrows(PlaywrightException.class,
|
|
() -> page.navigate(server.PREFIX + "/slow", new Page.NavigateOptions().setTimeout(2000)));
|
|
assertTrue(error.getMessage().contains("Timeout 2000ms exceeded"), error.getMessage());
|
|
}
|
|
|
|
@Test
|
|
void shouldInterceptWithUrlOverride() {
|
|
page.route("**/*.html", route -> {
|
|
APIResponse response = route.fetch(new Route.FetchOptions().setUrl(server.PREFIX + "/one-style.html"));
|
|
route.fulfill(new Route.FulfillOptions().setResponse(response));
|
|
});
|
|
Response response = page.navigate(server.PREFIX + "/empty.html");
|
|
assertEquals(200, response.status());
|
|
assertTrue(response.text().contains("one-style.css"), response.text());
|
|
}
|
|
|
|
@Test
|
|
void shouldInterceptWithPostDataOverride() throws ExecutionException, InterruptedException {
|
|
Future<Server.Request> request = server.futureRequest("/empty.html");
|
|
page.route("**/*.html", route -> {
|
|
APIResponse response = route.fetch(new Route.FetchOptions().setPostData("{ \"foo\": \"bar\" }"));
|
|
route.fulfill(new Route.FulfillOptions().setResponse(response));
|
|
});
|
|
page.navigate(server.PREFIX + "/empty.html");
|
|
assertEquals("{ \"foo\": \"bar\" }", new String(request.get().postBody));
|
|
}
|
|
|
|
@Test
|
|
void shouldNotFollowRedirectsWhenMaxRedirectsIsSetTo0InRouteFetch() {
|
|
server.setRedirect("/foo", "/empty.html");
|
|
page.route("**/*", route -> {
|
|
APIResponse response = route.fetch(new Route.FetchOptions().setMaxRedirects(0));
|
|
assertEquals("/empty.html", response.headers().get("location"));
|
|
assertEquals(302, response.status());
|
|
route.fulfill(new Route.FulfillOptions().setBody("hello"));
|
|
});
|
|
page.navigate(server.PREFIX + "/foo");
|
|
assertTrue(page.content().contains("hello"));
|
|
}
|
|
|
|
@Test
|
|
void shouldWorkWithGlob() {
|
|
assertTrue(globToRegex("**/*.js").matcher("https://localhost:8080/foo.js").find());
|
|
assertFalse(globToRegex("**/*.css").matcher("https://localhost:8080/foo.js").find());
|
|
assertFalse(globToRegex("*.js").matcher("https://localhost:8080/foo.js").find());
|
|
assertTrue(globToRegex("https://**/*.js").matcher("https://localhost:8080/foo.js").find());
|
|
assertTrue(globToRegex("http://localhost:8080/simple/path.js").matcher("http://localhost:8080/simple/path.js").find());
|
|
assertTrue(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/a.js").find());
|
|
assertTrue(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/b.js").find());
|
|
assertFalse(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/c.js").find());
|
|
|
|
assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.jpg").find());
|
|
assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.jpeg").find());
|
|
assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.png").find());
|
|
assertFalse(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.css").find());
|
|
assertTrue(globToRegex("foo*").matcher("foo.js").find());
|
|
assertFalse(globToRegex("foo*").matcher("foo/bar.js").find());
|
|
assertFalse(globToRegex("http://localhost:3000/signin-oidc*").matcher("http://localhost:3000/signin-oidc/foo").find());
|
|
assertTrue(globToRegex("http://localhost:3000/signin-oidc*").matcher("http://localhost:3000/signin-oidcnice").find());
|
|
|
|
// range [] is NOT supported
|
|
assertTrue(globToRegex("**/api/v[0-9]").matcher("http://example.com/api/v[0-9]").find());
|
|
assertFalse(globToRegex("**/api/v[0-9]").matcher("http://example.com/api/version").find());
|
|
|
|
// query params
|
|
assertTrue(globToRegex("**/api\\?param").matcher("http://example.com/api?param").find());
|
|
assertFalse(globToRegex("**/api\\?param").matcher("http://example.com/api-param").find());
|
|
assertTrue(globToRegex("**/three-columns/settings.html\\?**id=settings-**").matcher("http://mydomain:8080/blah/blah/three-columns/settings.html?id=settings-e3c58efe-02e9-44b0-97ac-dd138100cf7c&blah").find());
|
|
|
|
assertEquals("^\\?$", globToRegex("\\?").pattern());
|
|
assertEquals("^\\\\$", globToRegex("\\").pattern());
|
|
assertEquals("^\\\\$", globToRegex("\\\\").pattern());
|
|
assertEquals("^\\[$", globToRegex("\\[").pattern());
|
|
assertEquals("^\\[a-z\\]$", globToRegex("[a-z]").pattern());
|
|
assertEquals("^\\$\\^\\+\\.\\*\\(\\)\\|\\?\\{\\}\\[\\]$", globToRegex("$^+.\\*()|\\?\\{\\}\\[\\]").pattern());
|
|
|
|
|
|
assertTrue(urlMatches(null, "http://playwright.dev/", "http://playwright.dev"));
|
|
assertTrue(urlMatches(null, "http://playwright.dev/?a=b", "http://playwright.dev?a=b"));
|
|
assertTrue(urlMatches(null, "http://playwright.dev/", "h*://playwright.dev"));
|
|
assertTrue(urlMatches(null, "http://api.playwright.dev/?x=y", "http://*.playwright.dev?x=y"));
|
|
assertTrue(urlMatches(null, "http://playwright.dev/foo/bar", "**/foo/**"));
|
|
assertTrue(urlMatches("http://playwright.dev", "http://playwright.dev/?x=y", "?x=y"));
|
|
assertTrue(urlMatches("http://playwright.dev/foo/", "http://playwright.dev/foo/bar?x=y", "./bar?x=y"));
|
|
|
|
// Case insensitive matching
|
|
assertTrue(urlMatches(null, "https://playwright.dev/fooBAR", "HtTpS://pLaYwRiGhT.dEv/fooBAR"));
|
|
assertTrue(urlMatches("http://ignored", "https://playwright.dev/fooBAR", "HtTpS://pLaYwRiGhT.dEv/fooBAR"));
|
|
// Path and search query are case-sensitive
|
|
assertFalse(urlMatches(null, "https://playwright.dev/foobar", "https://playwright.dev/fooBAR"));
|
|
assertFalse(urlMatches(null, "https://playwright.dev/foobar?a=b", "https://playwright.dev/foobar?A=B"));
|
|
|
|
// This is not supported, we treat ? as a query separator.
|
|
assertFalse(urlMatches(null, "http://localhost:8080/Simple/path.js", "http://localhost:8080/?imple/path.js"));
|
|
assertFalse(urlMatches(null, "http://playwright.dev/", "http://playwright.?ev"));
|
|
assertTrue(urlMatches(null, "http://playwright./?ev", "http://playwright.?ev"));
|
|
assertFalse(urlMatches(null, "http://playwright.dev/foo", "http://playwright.dev/f??"));
|
|
assertTrue(urlMatches(null, "http://playwright.dev/f??", "http://playwright.dev/f??"));
|
|
assertTrue(urlMatches(null, "http://playwright.dev/?x=y", "http://playwright.dev\\\\?x=y"));
|
|
assertTrue(urlMatches(null, "http://playwright.dev/?x=y", "http://playwright.dev/\\\\?x=y"));
|
|
assertTrue(urlMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "?bar"));
|
|
assertTrue(urlMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "\\\\?bar"));
|
|
assertTrue(urlMatches("http://first.host/", "http://second.host/foo", "**/foo"));
|
|
assertTrue(urlMatches("http://playwright.dev/", "http://localhost/", "*//localhost/"));
|
|
|
|
String[] customPrefixes = {"about", "data", "chrome", "edge", "file"};
|
|
for (String prefix : customPrefixes) {
|
|
assertTrue(urlMatches("http://playwright.dev/", prefix + ":blank", prefix + ":blank"));
|
|
assertFalse(urlMatches("http://playwright.dev/", prefix + ":blank", "http://playwright.dev/"));
|
|
assertTrue(urlMatches(null, prefix + ":blank", prefix + ":blank"));
|
|
assertTrue(urlMatches(null, prefix + ":blank", prefix + ":*"));
|
|
assertFalse(urlMatches(null, "not" + prefix + ":blank", prefix + ":*"));
|
|
}
|
|
}
|
|
|
|
Pattern globToRegex(String glob) {
|
|
return globToRegex(glob, null, false);
|
|
}
|
|
|
|
Pattern globToRegex(String glob, String baseURL, boolean webSocketUrl) {
|
|
return ((PlaywrightImpl) playwright).localUtils().globToRegex(glob, baseURL, webSocketUrl);
|
|
}
|
|
|
|
boolean urlMatches(String baseURL, String urlString, String match) {
|
|
if (match == null) {
|
|
return true;
|
|
}
|
|
|
|
String glob = (String) match;
|
|
if (glob.isEmpty()) {
|
|
return true;
|
|
}
|
|
|
|
return globToRegex(glob, baseURL, false).matcher(urlString).find();
|
|
}
|
|
}
|