1
0
mirror of synced 2026-05-23 11:13:15 +00:00

Compare commits

...

11 Commits

Author SHA1 Message Date
Yury Semikhatsky 8e5074954b chore: mark 1.25.0 (#1027) 2022-08-11 14:00:32 -07:00
Yury Semikhatsky 385131e51b chore: roll driver to 1.25.0 (#1026) 2022-08-11 13:40:57 -07:00
Yury Semikhatsky 6cb9f60988 chore: roll driver to 1.25.0-alpha-1659998098000 (#1025) 2022-08-09 14:07:53 -07:00
Yury Semikhatsky aef9badd64 feat: assertions default timeout (#1023) 2022-08-04 17:29:02 -07:00
Yury Semikhatsky 64f7a059af fix: prevent video.saveAs() from hanging (#1020) 2022-08-01 15:01:43 -07:00
Yury Semikhatsky 436fc12609 feat: roll driver to 1.25.0-alpha-jul-28-2022 (#1015) 2022-07-28 14:23:59 -07:00
Yury Semikhatsky 560575a9b5 test: unflake wheel test (#1014) 2022-07-27 16:39:47 -07:00
Yury Semikhatsky 0afaf6c561 fix: no split packages for compatibility with modules (#1013) 2022-07-27 13:32:25 -07:00
Yury Semikhatsky 202371b5d7 test: locator has with unicode symbols (#1012) 2022-07-26 14:12:47 -07:00
Yury Semikhatsky 2093bba554 fix: do not download browsers if selenium url is set (#1008) 2022-07-25 16:20:38 -07:00
Yury Semikhatsky 77538dcf7f chore: bump dev version to 1.25 (#1007) 2022-07-25 15:56:22 -07:00
44 changed files with 623 additions and 106 deletions
+2 -2
View File
@@ -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.
+1 -1
View File
@@ -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>
@@ -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
View File
@@ -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>
@@ -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.
@@ -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
View File
@@ -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
View File
@@ -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();
@@ -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.
@@ -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);
}
}
@@ -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"));
}
+1 -1
View File
@@ -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
View File
@@ -1 +1 @@
1.24.0
1.25.0
+1 -1
View File
@@ -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;");
}
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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