Compare commits
11 Commits
release-1.24
...
v1.25.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e5074954b | |||
| 385131e51b | |||
| 6cb9f60988 | |||
| aef9badd64 | |||
| 64f7a059af | |||
| 436fc12609 | |||
| 560575a9b5 | |||
| 0afaf6c561 | |||
| 202371b5d7 | |||
| 2093bba554 | |||
| 77538dcf7f |
@@ -11,9 +11,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->104.0.5112.48<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->105.0.5195.19<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->16.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->102.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Firefox <!-- GEN:firefox-version -->103.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
Headless execution is supported for all the browsers on all platforms. Check out [system requirements](https://playwright.dev/java/docs/next/intro/#system-requirements) for details.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
|
||||
+9
-2
@@ -14,7 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
package com.microsoft.playwright.impl.driver.jar;
|
||||
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@@ -26,6 +28,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DriverJar extends Driver {
|
||||
private static final String PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD";
|
||||
private static final String SELENIUM_REMOTE_URL = "SELENIUM_REMOTE_URL";
|
||||
private final Path driverTempDir;
|
||||
|
||||
public DriverJar() throws IOException {
|
||||
@@ -57,6 +60,10 @@ public class DriverJar extends Driver {
|
||||
System.out.println("Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set");
|
||||
return;
|
||||
}
|
||||
if (env.get(SELENIUM_REMOTE_URL) != null || System.getenv(SELENIUM_REMOTE_URL) != null) {
|
||||
logMessage("Skipping browsers download because `SELENIUM_REMOTE_URL` env variable is set");
|
||||
return;
|
||||
}
|
||||
Path driver = driverPath();
|
||||
if (!Files.exists(driver)) {
|
||||
throw new RuntimeException("Failed to find driver: " + driver);
|
||||
@@ -158,7 +165,7 @@ public class DriverJar extends Driver {
|
||||
}
|
||||
|
||||
@Override
|
||||
Path driverDir() {
|
||||
protected Path driverDir() {
|
||||
return driverTempDir;
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.impl.Driver;
|
||||
import com.microsoft.playwright.impl.DriverJar;
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
import com.microsoft.playwright.impl.driver.jar.DriverJar;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver</artifactId>
|
||||
|
||||
+5
-6
@@ -14,14 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
package com.microsoft.playwright.impl.driver;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.microsoft.playwright.impl.DriverLogging.logWithTimestamp;
|
||||
import static com.microsoft.playwright.impl.driver.DriverLogging.logWithTimestamp;
|
||||
|
||||
/**
|
||||
* This class provides access to playwright-cli. It can be either preinstalled
|
||||
@@ -44,7 +43,7 @@ public abstract class Driver {
|
||||
}
|
||||
|
||||
@Override
|
||||
Path driverDir() {
|
||||
protected Path driverDir() {
|
||||
return driverDir;
|
||||
}
|
||||
}
|
||||
@@ -100,12 +99,12 @@ public abstract class Driver {
|
||||
}
|
||||
|
||||
String driverImpl =
|
||||
System.getProperty("playwright.driver.impl", "com.microsoft.playwright.impl.DriverJar");
|
||||
System.getProperty("playwright.driver.impl", "com.microsoft.playwright.impl.driver.jar.DriverJar");
|
||||
Class<?> jarDriver = Class.forName(driverImpl);
|
||||
return (Driver) jarDriver.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
abstract Path driverDir();
|
||||
protected abstract Path driverDir();
|
||||
|
||||
protected static void logMessage(String message) {
|
||||
// This matches log format produced by the server.
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
package com.microsoft.playwright.impl.driver;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>examples</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
<name>Playwright Client Examples</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playwright</artifactId>
|
||||
|
||||
@@ -30,15 +30,15 @@ import java.nio.file.Path;
|
||||
*
|
||||
* <p> **Cookie management**
|
||||
*
|
||||
* <p> {@code APIRequestContext} retuned by {@link BrowserContext#request BrowserContext.request()} and {@link Page#request
|
||||
* <p> {@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.
|
||||
*
|
||||
* <p> 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.
|
||||
* <p> 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 {
|
||||
|
||||
@@ -1099,7 +1099,7 @@ public interface Browser extends AutoCloseable {
|
||||
/**
|
||||
* Creates a new browser context. It won't share cookies/cache with other browser contexts.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> If directly using this method to create {@code BrowserContext}s, it is best practice to explicilty close the returned context
|
||||
* <p> <strong>NOTE:</strong> 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();
|
||||
* }</pre>
|
||||
@@ -1122,7 +1122,7 @@ public interface Browser extends AutoCloseable {
|
||||
/**
|
||||
* Creates a new browser context. It won't share cookies/cache with other browser contexts.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> If directly using this method to create {@code BrowserContext}s, it is best practice to explicilty close the returned context
|
||||
* <p> <strong>NOTE:</strong> 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();
|
||||
* }</pre>
|
||||
|
||||
@@ -1028,7 +1028,9 @@ public interface BrowserType {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This method attaches Playwright to an existing browser instance.
|
||||
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via
|
||||
* {@code BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
|
||||
* compatible with 1.2.x).
|
||||
*
|
||||
* @param wsEndpoint A browser websocket endpoint to connect to.
|
||||
*/
|
||||
@@ -1036,7 +1038,9 @@ public interface BrowserType {
|
||||
return connect(wsEndpoint, null);
|
||||
}
|
||||
/**
|
||||
* This method attaches Playwright to an existing browser instance.
|
||||
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via
|
||||
* {@code BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
|
||||
* compatible with 1.2.x).
|
||||
*
|
||||
* @param wsEndpoint A browser websocket endpoint to connect to.
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.impl.Driver;
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@@ -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<Locator> 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<Locator> mask) {
|
||||
|
||||
@@ -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<Locator> 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<Locator> mask) {
|
||||
|
||||
@@ -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<Locator> 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<Locator> mask) {
|
||||
|
||||
@@ -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 <a
|
||||
* Indicates whether this Response was fulfilled by a Service Worker's Fetch Handler (i.e. via <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith">FetchEvent.respondWith</a>).
|
||||
*/
|
||||
boolean fromServiceWorker();
|
||||
|
||||
+344
-32
@@ -498,9 +498,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -515,9 +535,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -530,9 +570,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -547,9 +607,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -562,9 +642,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -579,9 +679,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -594,9 +714,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -611,9 +751,29 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).containsText("substring");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> Elements from a **subset** of this list contain text from the expected array, respectively.</li>
|
||||
* <li> The matching subset of elements has the same order as the expected array.</li>
|
||||
* <li> Each text value from the expected array is matched by some element from the list.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .list-item")).containsText(new String[] {"Text 1", "Text 4", "Text 5"});
|
||||
* // ✓ Contains the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
|
||||
*
|
||||
* // ✖ No item contains this text
|
||||
* assertThat(page.locator("ul > li")).containsText(new String[] {"Some 33"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).containsText(new String[] {"Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -934,9 +1094,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -951,9 +1130,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -966,9 +1164,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -983,9 +1200,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -998,9 +1234,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -1015,9 +1270,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -1030,9 +1304,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
@@ -1047,9 +1340,28 @@ public interface LocatorAssertions {
|
||||
* assertThat(page.locator(".title")).hasText(Pattern.compile("Welcome, .*"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> If you pass an array as an expected value, the expectations are:
|
||||
* <ol>
|
||||
* <li> Locator resolves to a list of elements.</li>
|
||||
* <li> The number of elements equals the number of expected values in the array.</li>
|
||||
* <li> Elements from the list have text matching expected array values, one by one, in order.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> For example, consider the following list:
|
||||
*
|
||||
* <p> Let's see how we can use the assertion:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* // ✓ Has the right items in the right order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
*
|
||||
* // ✖ Wrong order
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 3", "Text 2", "Text 1"});
|
||||
*
|
||||
* // ✖ Last item does not match
|
||||
* assertThat(page.locator("ul > li")).hasText(new String[] {"Text 1", "Text 2", "Text"});
|
||||
*
|
||||
* // ✖ Locator points to the outer list element, not to the list items
|
||||
* assertThat(page.locator("ul")).hasText(new String[] {"Text 1", "Text 2", "Text 3"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected substring or RegExp or a list of those.
|
||||
|
||||
+13
@@ -20,6 +20,7 @@ import com.microsoft.playwright.APIResponse;
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.impl.APIResponseAssertionsImpl;
|
||||
import com.microsoft.playwright.impl.AssertionsTimeout;
|
||||
import com.microsoft.playwright.impl.LocatorAssertionsImpl;
|
||||
import com.microsoft.playwright.impl.PageAssertionsImpl;
|
||||
|
||||
@@ -86,5 +87,17 @@ public interface PlaywrightAssertions {
|
||||
return new PageAssertionsImpl(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes default timeout for Playwright assertions from 5 seconds to the specified value.
|
||||
* <pre>{@code
|
||||
* PlaywrightAssertions.setDefaultAssertionTimeout(30_000);
|
||||
* }</pre>
|
||||
*
|
||||
* @param timeout Timeout in milliseconds.
|
||||
*/
|
||||
static void setDefaultAssertionTimeout(double milliseconds) {
|
||||
AssertionsTimeout.setDefaultTimeout(milliseconds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class AssertionsBase {
|
||||
|
||||
void expectImpl(String expression, FrameExpectOptions expectOptions, Object expected, String message) {
|
||||
if (expectOptions.timeout == null) {
|
||||
expectOptions.timeout = 5_000.0;
|
||||
expectOptions.timeout = AssertionsTimeout.defaultTimeout;
|
||||
}
|
||||
if (expectOptions.isNot) {
|
||||
message = message.replace("expected to", "expected not to");
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.impl;
|
||||
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
public class AssertionsTimeout {
|
||||
static double defaultTimeout = 5_000;
|
||||
|
||||
public static void setDefaultTimeout(double ms) {
|
||||
if (ms < 0) {
|
||||
throw new PlaywrightException("Timeout cannot be negative");
|
||||
}
|
||||
defaultTimeout = ms;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
this.tracing = connection.getExistingObject(initializer.getAsJsonObject("tracing").get("guid").getAsString());
|
||||
tracing.isRemote = browser != null && browser.isRemote;
|
||||
this.request = connection.getExistingObject(initializer.getAsJsonObject("APIRequestContext").get("guid").getAsString());
|
||||
this.request = connection.getExistingObject(initializer.getAsJsonObject("requestContext").get("guid").getAsString());
|
||||
}
|
||||
|
||||
void setRecordHar(Path path, HarContentPolicy policy) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.function.Supplier;
|
||||
|
||||
class ChannelOwner extends LoggingSupport {
|
||||
final Connection connection;
|
||||
private final ChannelOwner parent;
|
||||
private ChannelOwner parent;
|
||||
private final Map<String, ChannelOwner> objects = new HashMap<>();
|
||||
|
||||
final String type;
|
||||
@@ -68,6 +68,12 @@ class ChannelOwner extends LoggingSupport {
|
||||
objects.clear();
|
||||
}
|
||||
|
||||
void adopt(ChannelOwner child) {
|
||||
child.parent.objects.remove(child.guid);
|
||||
objects.put(child.guid, child);
|
||||
child.parent = this;
|
||||
}
|
||||
|
||||
<T> T withWaitLogging(String apiName, Supplier<T> code) {
|
||||
return new WaitForEventLogger<>(this, apiName, code).get();
|
||||
}
|
||||
|
||||
@@ -201,18 +201,24 @@ public class Connection {
|
||||
createRemoteObject(message.guid, message.params);
|
||||
return;
|
||||
}
|
||||
if (message.method.equals("__dispose__")) {
|
||||
ChannelOwner object = objects.get(message.guid);
|
||||
if (object == null) {
|
||||
throw new PlaywrightException("Cannot find object to dispose: " + message.guid);
|
||||
}
|
||||
object.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelOwner object = objects.get(message.guid);
|
||||
if (object == null) {
|
||||
throw new PlaywrightException("Cannot find object to call " + message.method + ": " + message.guid);
|
||||
}
|
||||
if (message.method.equals("__adopt__")) {
|
||||
String childGuid = message.params.get("guid").getAsString();
|
||||
ChannelOwner child = objects.get(childGuid);
|
||||
if (child == null) {
|
||||
throw new PlaywrightException("Unknown new child: " + childGuid);
|
||||
}
|
||||
object.adopt(child);
|
||||
return;
|
||||
}
|
||||
if (message.method.equals("__dispose__")) {
|
||||
object.disconnect();
|
||||
return;
|
||||
}
|
||||
object.handleEvent(message.method, message.params);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.microsoft.playwright.APIRequest;
|
||||
import com.microsoft.playwright.Playwright;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Selectors;
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@@ -72,6 +72,9 @@ class VideoImpl implements Video {
|
||||
@Override
|
||||
public void saveAs(Path path) {
|
||||
page.withLogging("Video.saveAs", () -> {
|
||||
if (!page.isClosed()) {
|
||||
throw new PlaywrightException("Page is not yet closed. Close the page prior to calling saveAs");
|
||||
}
|
||||
try {
|
||||
waitForArtifact().saveAs(path);
|
||||
} catch (PlaywrightException e) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.impl.Driver;
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.assertions.LocatorAssertions;
|
||||
import com.microsoft.playwright.assertions.PlaywrightAssertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
@@ -980,4 +981,35 @@ public class TestLocatorAssertions extends TestBase {
|
||||
page.locator("#searchResultTableDiv .x-grid3-row").count();
|
||||
assertThat(page.locator("#searchResultTableDiv .x-grid3-row")).hasCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultTimeoutHasTextFail() {
|
||||
page.setContent("<div></div>");
|
||||
Locator locator = page.locator("div");
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(1000);
|
||||
AssertionFailedError exception = assertThrows(AssertionFailedError.class, () -> assertThat(locator).hasText("foo"));
|
||||
assertTrue(exception.getMessage().contains("Locator.expect with timeout 1000ms"), exception.getMessage());
|
||||
// Restore default.
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(5_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultTimeoutHasTextPass() {
|
||||
page.setContent("<div>foo</div>");
|
||||
Locator locator = page.locator("div");
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(1000);
|
||||
assertThat(locator).hasText("foo");
|
||||
// Restore default.
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(5_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultTimeoutZeroHasTextPass() {
|
||||
page.setContent("<div>foo</div>");
|
||||
Locator locator = page.locator("div");
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(0);
|
||||
assertThat(locator).hasText("foo");
|
||||
// Restore default.
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(5_000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@ package com.microsoft.playwright;
|
||||
import com.microsoft.playwright.options.WaitForSelectorState;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestLocatorMisc extends TestBase{
|
||||
@Test
|
||||
@@ -49,4 +50,22 @@ public class TestLocatorMisc extends TestBase{
|
||||
page.evalOnSelector("div", "div => setTimeout(() => div.innerHTML = '', 500)");
|
||||
locator.waitFor(new Locator.WaitForOptions().setState(WaitForSelectorState.HIDDEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
void locatorsHasDoesNotEncodeUnicode() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Locator[] locators = new Locator[]{
|
||||
page.locator("button", new Page.LocatorOptions().setHasText("Драматург")),
|
||||
page.locator("button", new Page.LocatorOptions().setHasText(Pattern.compile("Драматург"))),
|
||||
page.locator("button", new Page.LocatorOptions().setHas(page.locator("text=Драматург")))
|
||||
};
|
||||
for (Locator locator: locators) {
|
||||
try {
|
||||
locator.click(new Locator.ClickOptions().setTimeout(100));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Драматург"), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class TestPageBasic extends TestBase {
|
||||
newPage.evaluate("() => new Promise(r => {})");
|
||||
fail("evaluate should throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Target closed"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,14 +133,10 @@ public class TestPageRequestFallback extends TestBase {
|
||||
@Test
|
||||
void shouldChainOnce() {
|
||||
page.route("**/empty.html", route -> {
|
||||
System.out.println("before fulfill");
|
||||
route.fulfill(new Route.FulfillOptions().setStatus(200).setBody("fulfilled one"));
|
||||
System.out.println("after fulfill");
|
||||
}, new Page.RouteOptions().setTimes(1));
|
||||
page.route("**/empty.html", route -> {
|
||||
System.out.println("before fallback");
|
||||
route.fallback();
|
||||
System.out.println("after fallback");
|
||||
}, new Page.RouteOptions().setTimes(1));
|
||||
Response response = page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals("fulfilled one", response.text());
|
||||
|
||||
@@ -127,4 +127,17 @@ public class TestScreencast extends TestBase {
|
||||
assertTrue(Files.exists(files.get(0)));
|
||||
assertTrue(Files.size(files.get(0)) > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldErrorIfPageNotClosedBeforeSaveAs(@TempDir Path tmpDir) {
|
||||
try (Page page = browser.newPage(new Browser.NewPageOptions().setRecordVideoDir(tmpDir))) {
|
||||
page.navigate(server.PREFIX + "/grid.html");
|
||||
Path outPath = tmpDir.resolve("some-video.webm");
|
||||
Video video = page.video();
|
||||
PlaywrightException exception = assertThrows(PlaywrightException.class, () -> video.saveAs(outPath));
|
||||
assertTrue(
|
||||
exception.getMessage().contains("Page is not yet closed. Close the page prior to calling saveAs"),
|
||||
exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +108,8 @@ public class TestWheel extends TestBase {
|
||||
"shiftKey", false,
|
||||
"altKey", false,
|
||||
"metaKey", false);
|
||||
expectEvent(expected);
|
||||
page.waitForFunction("window.scrollX === 100");
|
||||
expectEvent(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,6 +121,8 @@ public class TestWheel extends TestBase {
|
||||
" document.querySelector('div').addEventListener('wheel', e => e.preventDefault());\n" +
|
||||
" }");
|
||||
page.mouse().wheel(0, 100);
|
||||
// give the page a chance to scroll
|
||||
page.waitForFunction("!!window['lastEvent']");
|
||||
Map<String, Object> expected = mapOf(
|
||||
"deltaX", 0,
|
||||
"deltaY", 100,
|
||||
@@ -132,8 +134,6 @@ public class TestWheel extends TestBase {
|
||||
"altKey", false,
|
||||
"metaKey", false);
|
||||
expectEvent(expected);
|
||||
// give the page a chacne to scroll
|
||||
page.waitForTimeout(100);
|
||||
// ensure that it did not.
|
||||
assertEquals(0, page.evaluate("window.scrollY"));
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Playwright Parent Project</name>
|
||||
<description>Java library to automate Chromium, Firefox and WebKit with a single API.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.24.0
|
||||
1.25.0
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>api-generator</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
<name>Playwright - API Generator</name>
|
||||
<description>
|
||||
This is an internal module used to generate Java API from the upstream Playwright
|
||||
|
||||
@@ -675,6 +675,14 @@ class Method extends Element {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ("PlaywrightAssertions.setDefaultAssertionTimeout".equals(jsonPath)) {
|
||||
writeJavadoc(params, output, offset);
|
||||
output.add(offset + "static void setDefaultAssertionTimeout(double milliseconds) {");
|
||||
output.add(offset + " AssertionsTimeout.setDefaultTimeout(milliseconds);");
|
||||
output.add(offset + "}");
|
||||
output.add("");
|
||||
return;
|
||||
}
|
||||
int numOverloads = 1;
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
if (params.get(i).type.isTypeUnion()) {
|
||||
@@ -952,6 +960,7 @@ class Interface extends TypeDefinition {
|
||||
output.add("import com.microsoft.playwright.Locator;");
|
||||
output.add("import com.microsoft.playwright.Page;");
|
||||
output.add("import com.microsoft.playwright.impl.APIResponseAssertionsImpl;");
|
||||
output.add("import com.microsoft.playwright.impl.AssertionsTimeout;");
|
||||
output.add("import com.microsoft.playwright.impl.LocatorAssertionsImpl;");
|
||||
output.add("import com.microsoft.playwright.impl.PageAssertionsImpl;");
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-cli-version</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
<name>Test Playwright Command Line Version</name>
|
||||
<properties>
|
||||
<compiler.version>1.8</compiler.version>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-local-installation</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
<name>Test local installation</name>
|
||||
<description>Runs Playwright test suite (copied from playwright module) against locally cached Playwright</description>
|
||||
<properties>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-spring-boot-starter</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
<name>Test Playwright With Spring Boot</name>
|
||||
<properties>
|
||||
<spring.version>2.4.3</spring.version>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>update-version</artifactId>
|
||||
<version>1.24.0-SNAPSHOT</version>
|
||||
<version>1.25.0</version>
|
||||
<name>Playwright - Update Version in Documentation</name>
|
||||
<description>
|
||||
This is an internal module used to update versions in the documentation based on
|
||||
|
||||
Reference in New Issue
Block a user