diff --git a/playwright/src/main/java/com/microsoft/playwright/APIRequestContext.java b/playwright/src/main/java/com/microsoft/playwright/APIRequestContext.java index 8dd88c08..6570d532 100644 --- a/playwright/src/main/java/com/microsoft/playwright/APIRequestContext.java +++ b/playwright/src/main/java/com/microsoft/playwright/APIRequestContext.java @@ -30,15 +30,15 @@ import java.nio.file.Path; * *

**Cookie management** * - *

{@code APIRequestContext} retuned by {@link BrowserContext#request BrowserContext.request()} and {@link Page#request + *

{@code APIRequestContext} returned by {@link BrowserContext#request BrowserContext.request()} and {@link Page#request * Page.request()} shares cookie storage with the corresponding {@code BrowserContext}. Each API request will have {@code Cookie} * header populated with the values from the browser context. If the API response contains {@code Set-Cookie} header it will * automatically update {@code BrowserContext} cookies and requests made from the page will pick them up. This means that if you * log in using this API, your e2e test will be logged in and vice versa. * - *

If you want API requests to not interfere with the browser cookies you shoud create a new {@code APIRequestContext} by calling - * {@link APIRequest#newContext APIRequest.newContext()}. Such {@code APIRequestContext} object will have its own isolated cookie - * storage. + *

If you want API requests to not interfere with the browser cookies you should create a new {@code APIRequestContext} by + * calling {@link APIRequest#newContext APIRequest.newContext()}. Such {@code APIRequestContext} object will have its own + * isolated cookie storage. */ public interface APIRequestContext { class StorageStateOptions { diff --git a/playwright/src/main/java/com/microsoft/playwright/Browser.java b/playwright/src/main/java/com/microsoft/playwright/Browser.java index 92d81946..c388486d 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Browser.java +++ b/playwright/src/main/java/com/microsoft/playwright/Browser.java @@ -1099,7 +1099,7 @@ public interface Browser extends AutoCloseable { /** * Creates a new browser context. It won't share cookies/cache with other browser contexts. * - *

NOTE: If directly using this method to create {@code BrowserContext}s, it is best practice to explicilty close the returned context + *

NOTE: If directly using this method to create {@code BrowserContext}s, it is best practice to explicitly close the returned context * via {@link BrowserContext#close BrowserContext.close()} when your code is done with the {@code BrowserContext}, and before * calling {@link Browser#close Browser.close()}. This will ensure the {@code context} is closed gracefully and any * artifacts—like HARs and videos—are fully flushed and saved. @@ -1111,7 +1111,7 @@ public interface Browser extends AutoCloseable { * Page page = context.newPage(); * page.navigate('https://example.com'); * - * // Gracefull close up everything + * // Graceful close up everything * context.close(); * browser.close(); * } @@ -1122,7 +1122,7 @@ public interface Browser extends AutoCloseable { /** * Creates a new browser context. It won't share cookies/cache with other browser contexts. * - *

NOTE: If directly using this method to create {@code BrowserContext}s, it is best practice to explicilty close the returned context + *

NOTE: If directly using this method to create {@code BrowserContext}s, it is best practice to explicitly close the returned context * via {@link BrowserContext#close BrowserContext.close()} when your code is done with the {@code BrowserContext}, and before * calling {@link Browser#close Browser.close()}. This will ensure the {@code context} is closed gracefully and any * artifacts—like HARs and videos—are fully flushed and saved. @@ -1134,7 +1134,7 @@ public interface Browser extends AutoCloseable { * Page page = context.newPage(); * page.navigate('https://example.com'); * - * // Gracefull close up everything + * // Graceful close up everything * context.close(); * browser.close(); * } diff --git a/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java b/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java index a02ebd07..aa1579a6 100644 --- a/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java +++ b/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java @@ -586,7 +586,7 @@ public interface ElementHandle extends JSHandle { */ public ScreenshotCaret caret; /** - * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box * {@code #FF00FF} that completely covers its bounding box. */ public List mask; @@ -647,7 +647,7 @@ public interface ElementHandle extends JSHandle { return this; } /** - * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box * {@code #FF00FF} that completely covers its bounding box. */ public ScreenshotOptions setMask(List mask) { diff --git a/playwright/src/main/java/com/microsoft/playwright/Locator.java b/playwright/src/main/java/com/microsoft/playwright/Locator.java index f75b252a..f3464a51 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Locator.java +++ b/playwright/src/main/java/com/microsoft/playwright/Locator.java @@ -1013,7 +1013,7 @@ public interface Locator { */ public ScreenshotCaret caret; /** - * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box * {@code #FF00FF} that completely covers its bounding box. */ public List mask; @@ -1074,7 +1074,7 @@ public interface Locator { return this; } /** - * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box * {@code #FF00FF} that completely covers its bounding box. */ public ScreenshotOptions setMask(List mask) { diff --git a/playwright/src/main/java/com/microsoft/playwright/Page.java b/playwright/src/main/java/com/microsoft/playwright/Page.java index 773a371b..9bf9b8d0 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Page.java +++ b/playwright/src/main/java/com/microsoft/playwright/Page.java @@ -2080,7 +2080,7 @@ public interface Page extends AutoCloseable { */ public Boolean fullPage; /** - * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box * {@code #FF00FF} that completely covers its bounding box. */ public List mask; @@ -2162,7 +2162,7 @@ public interface Page extends AutoCloseable { return this; } /** - * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box * {@code #FF00FF} that completely covers its bounding box. */ public ScreenshotOptions setMask(List mask) { diff --git a/playwright/src/main/java/com/microsoft/playwright/Response.java b/playwright/src/main/java/com/microsoft/playwright/Response.java index 3b398b99..c28d9e1f 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Response.java +++ b/playwright/src/main/java/com/microsoft/playwright/Response.java @@ -40,7 +40,7 @@ public interface Response { */ Frame frame(); /** - * Indicates whether this Response was fullfilled by a Service Worker's Fetch Handler (i.e. via FetchEvent.respondWith). */ boolean fromServiceWorker(); diff --git a/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java b/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java index b850e717..e7234cc8 100644 --- a/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java +++ b/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java @@ -88,7 +88,7 @@ public interface PlaywrightAssertions { } /** - * Changes default timeout for Playwright assertions from 5 seconds to the speicified value. + * Changes default timeout for Playwright assertions from 5 seconds to the specified value. *

{@code
    * PlaywrightAssertions.setDefaultAssertionTimeout(30_000);
    * }
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/APIResponseAssertionsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/APIResponseAssertionsImpl.java index 9fb08a9b..67d7dfc5 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/APIResponseAssertionsImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/APIResponseAssertionsImpl.java @@ -21,6 +21,7 @@ import com.microsoft.playwright.assertions.APIResponseAssertions; import org.opentest4j.AssertionFailedError; import java.util.List; +import java.util.regex.Pattern; public class APIResponseAssertionsImpl implements APIResponseAssertions { private final APIResponse actual; @@ -54,6 +55,20 @@ public class APIResponseAssertionsImpl implements APIResponseAssertions { if (!log.isEmpty()) { log = "\nCall log:\n" + log; } - throw new AssertionFailedError(message + log); + + String contentType = actual.headers().get("content-type"); + boolean isTextEncoding = contentType == null ? false : isTextualMimeType(contentType); + String responseText = ""; + if (isTextEncoding) { + String text = actual.text(); + if (text != null) { + responseText = "\nResponse text:\n" + (text.length() > 1000 ? text.substring(0, 1000) : text); + } + } + + throw new AssertionFailedError(message + log + responseText); + } + static boolean isTextualMimeType(String mimeType) { + return Pattern.matches("^(text/.*?|application/(json|(x-)?javascript|xml.*?|ecmascript|graphql|x-www-form-urlencoded)|image/svg(\\+xml)?|application/.*?(\\+json|\\+xml))(;\\s*charset=.*)?$", mimeType); } } diff --git a/playwright/src/test/java/com/microsoft/playwright/Server.java b/playwright/src/test/java/com/microsoft/playwright/Server.java index 0d98bf32..8774fd50 100644 --- a/playwright/src/test/java/com/microsoft/playwright/Server.java +++ b/playwright/src/test/java/com/microsoft/playwright/Server.java @@ -195,6 +195,7 @@ public class Server implements HttpHandler { String resourcePath = "resources" + path; InputStream resource = getClass().getClassLoader().getResourceAsStream(resourcePath); if (resource == null) { + exchange.getResponseHeaders().add("Content-Type", "text/plain"); exchange.sendResponseHeaders(404, 0); try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) { writer.write("File not found: " + resourcePath); diff --git a/playwright/src/test/java/com/microsoft/playwright/TestAPIResponseAssertions.java b/playwright/src/test/java/com/microsoft/playwright/TestAPIResponseAssertions.java index d84f3852..02ab8ba9 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestAPIResponseAssertions.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestAPIResponseAssertions.java @@ -19,8 +19,11 @@ package com.microsoft.playwright; import org.junit.jupiter.api.Test; import org.opentest4j.AssertionFailedError; +import java.io.OutputStreamWriter; +import java.io.Writer; + import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class TestAPIResponseAssertions extends TestBase { @Test @@ -38,14 +41,62 @@ public class TestAPIResponseAssertions extends TestBase { @Test void fail() { APIResponse res = page.request().get(server.PREFIX + "/unknown"); - boolean didThrow = false; - try { - assertThat(res).isOK(); - } catch (AssertionFailedError e) { - didThrow = true; - assertTrue(e.getMessage().contains("→ GET " + server.PREFIX + "/unknown"), "Actual error: " + e.toString()); - assertTrue(e.getMessage().contains("← 404 Not Found"), "Actual error: " + e.toString()); + AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> assertThat(res).isOK()); + assertTrue(e.getMessage().contains("→ GET " + server.PREFIX + "/unknown"), "Actual error: " + e.toString()); + assertTrue(e.getMessage().contains("← 404 Not Found"), "Actual error: " + e.toString()); + } + + @Test + void shouldPrintResponseTextIfIdOkFails() { + APIResponse res = page.request().get(server.PREFIX + "/unknown"); + AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> assertThat(res).isOK()); + assertTrue(e.getMessage().contains("File not found"), "Actual error: " + e.toString()); + } + + @Test + void shouldOnlyPrintResponseWithTextContentTypeIfIsOkFails() { + { + server.setRoute("/text-content-type", exchange -> { + exchange.getResponseHeaders().set("Content-type", "text/plain"); + exchange.sendResponseHeaders(404, 0); + try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) { + writer.write("Text error"); + } + }); + AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> assertThat(page.request().get(server.PREFIX + "/text-content-type")).isOK()); + assertTrue(e.getMessage().contains("Text error"), "Actual error: " + e); + } + { + server.setRoute("/svg-xml-content-type", exchange -> { + exchange.getResponseHeaders().set("Content-type", "image/svg+xml"); + exchange.sendResponseHeaders(404, 0); + try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) { + writer.write("Json error"); + } + }); + AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> assertThat(page.request().get(server.PREFIX + "/svg-xml-content-type")).isOK()); + assertTrue(e.getMessage().contains("Json error"), "Actual error: " + e); + } + { + server.setRoute("/no-content-type", exchange -> { + exchange.sendResponseHeaders(404, 0); + try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) { + writer.write("No content type error"); + } + }); + AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> assertThat(page.request().get(server.PREFIX + "/no-content-type")).isOK()); + assertFalse(e.getMessage().contains("No content type error"), "Actual error: " + e); + } + { + server.setRoute("/image-content-type", exchange -> { + exchange.getResponseHeaders().set("Content-type", "image/bmp"); + exchange.sendResponseHeaders(404, 0); + try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) { + writer.write("Image type error"); + } + }); + AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> assertThat(page.request().get(server.PREFIX + "/image-content-type")).isOK()); + assertFalse(e.getMessage().contains("Image type error"), "Actual error: " + e); } - assertTrue(didThrow); } } diff --git a/scripts/CLI_VERSION b/scripts/CLI_VERSION index 85e87281..ad219194 100644 --- a/scripts/CLI_VERSION +++ b/scripts/CLI_VERSION @@ -1 +1 @@ -1.25.0-alpha-1659998098000 +1.25.0